<commit_before>//! Representing a pixel-aligned area

use std;
use super::DeepClone;

///  A cairo_region_t represents a set of integer-aligned rectangles.
///
/// It allows set-theoretical operations like cairo_region_union() and cairo_region_intersect() to be performed on them.
///
/// Memory management of cairo_region_t is done with cairo_region_reference() and cairo_region_destroy().
///
/// Since 1.10
pub struct Region {
  /// Wraps Cairo pointer for region.
  opaque: *mut std::libc::c_void
}

///  A data structure for holding a rectangle with integer coordinates.
///
/// Since 1.10
pub struct Rectangle {
  /// X coordinate of the left side of the rectangle
  x: i32,
  /// Y coordinate of the the top side of the rectangle
  y: i32,
  /// width of the rectangle
  width: i32,
  /// height of the rectangle
  height: i32
}

impl Region {
  ///  Allocates a new empty region object.
  ///
  /// Returns : A newly allocated cairo_region_t. Free with cairo_region_destroy(). This function always returns a valid pointer; if memory cannot be allocated, then a special error object is returned where all operations on the object do nothing. You can check for this with cairo_region_status().
  ///
  /// Since 1.10
  pub fn new() -> Region {
    unsafe {
      let foreign_result = cairo_region_create();
      return foreign_result;
    }
  }

  ///  Allocates a new region object containing rectangle.
  ///
  /// rectangle : a cairo_rectangle_int_t
  ///
  /// Returns : A newly allocated cairo_region_t. Free with cairo_region_destroy(). This function always returns a valid pointer; if memory cannot be allocated, then a special error object is returned where all operations on the object do nothing. You can check for this with cairo_region_status().
  ///
  /// Since 1.10
  pub fn rectangle(rectangle: &Rectangle) -> Region {
    unsafe {
      let foreign_result = cairo_region_create_rectangle(rectangle);
      return foreign_result;
    }
  }

  ///  Allocates a new region object containing the union of all given rects.
  ///
  /// rects : an array of count rectangles
  ///
  /// count : number of rectangles
  ///
  /// Returns : A newly allocated cairo_region_t. Free with cairo_region_destroy(). This function always returns a valid pointer; if memory cannot be allocated, then a special error object is returned where all operations on the object do nothing. You can check for this with cairo_region_status().
  ///
  /// Since 1.10
  pub fn rectangles(rectangles: &[Rectangle]) -> Region {
    unsafe {
      let foreign_result = cairo_region_create_rectangles(rectangles.as_ptr(), rectangles.len() as i32);
      return foreign_result;
    }
  }

  ///  Checks whether an error has previous occurred for this region object.
  ///
  /// region : a cairo_region_t
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn status(&mut self) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_status(self.opaque);
      return foreign_result;
    }
  }

  ///  Gets the bounding rectangle of region as a cairo_rectangle_int_t
  ///
  /// region : a cairo_region_t
  ///
  /// extents : rectangle into which to store the extents
  ///
  /// Since 1.10
  pub fn get_extents(&mut self) -> Rectangle {
    unsafe {
      let mut extents:Rectangle = std::intrinsics::init();
      cairo_region_get_extents(self.opaque, &mut extents);
      return extents;
    }
  }

  ///  Returns the number of rectangles contained in region.
  ///
  /// region : a cairo_region_t
  ///
  /// Returns : The number of rectangles contained in region.
  ///
  /// Since 1.10
  pub fn num_rectangles(&mut self) -> i32 {
    unsafe {
      let foreign_result = cairo_region_num_rectangles(self.opaque);
      return foreign_result;
    }
  }

  ///  Stores the nth rectangle from the region in rectangle.
  ///
  /// region : a cairo_region_t
  ///
  /// nth : a number indicating which rectangle should be returned
  ///
  /// rectangle : return location for a cairo_rectangle_int_t
  ///
  /// Since 1.10
  pub fn get_rectangle(&mut self, nth: i32) -> Rectangle {
    unsafe {
      let mut rectangle:Rectangle = std::intrinsics::init();
      cairo_region_get_rectangle(self.opaque, nth, &mut rectangle);
      return rectangle;
    }
  }

  ///  Checks whether region is empty.
  ///
  /// region : a cairo_region_t
  ///
  /// Returns : TRUE if region is empty, FALSE if it isn't.
  ///
  /// Since 1.1
  pub fn is_empty(&mut self) -> bool {
    unsafe {
      let foreign_result = cairo_region_is_empty(self.opaque);
      return foreign_result != 0;
    }
  }

  ///  Checks whether (x, y) is contained in region.
  ///
  /// region : a cairo_region_t
  ///
  /// x : the x coordinate of a point
  ///
  /// y : the y coordinate of a point
  ///
  /// Returns : TRUE if (x, y) is contained in region, FALSE if it is not.
  ///
  /// Since 1.10
  pub fn contains_point(&mut self, x: i32, y: i32) -> bool {
    unsafe {
      let foreign_result = cairo_region_contains_point(self.opaque, x, y);
      return foreign_result != 0;
    }
  }

  ///  Checks whether rectangle is inside, outside or partially contained in region
  ///
  /// region : a cairo_region_t
  ///
  /// rectangle : a cairo_rectangle_int_t
  ///
  /// Returns : CAIRO_REGION_OVERLAP_IN if rectangle is entirely inside region, CAIRO_REGION_OVERLAP_OUT if rectangle is entirely outside region, or CAIRO_REGION_OVERLAP_PART if rectangle is partially inside and partially outside region.
  ///
  /// Since 1.10
  pub fn containts_rectangle(&mut self, rectangle: &Rectangle) -> overlap::Overlap {
    unsafe {
      let foreign_result = cairo_region_contains_rectangle(self.opaque, rectangle);
      return foreign_result;
    }
  }

  ///  Compares whether region_a is equivalent to region_b. NULL as an argument is equal to itself, but not to any non-NULL region.
  ///
  /// a : a cairo_region_t or NULL
  ///
  /// b : a cairo_region_t or NULL
  ///
  /// Returns : TRUE if both regions contained the same coverage, FALSE if it is not or any region is in an error status.
  ///
  /// Since 1.10
  pub fn equal(&mut self, other: &Region) -> bool {
    unsafe {
      let foreign_result = cairo_region_equal(self.opaque, other.opaque as *std::libc::c_void);
      return foreign_result != 0;
    }
  }

  ///  Translates region by (dx, dy).
  ///
  /// region : a cairo_region_t
  ///
  /// dx : Amount to translate in the x direction
  ///
  /// dy : Amount to translate in the y direction
  ///
  /// Since 1.10
  pub fn translate(&mut self, dx: i32, dy: i32) {
    unsafe {
      cairo_region_translate(self.opaque, dx, dy);
    }
  }

  ///  Computes the intersection of dst with rectangle and places the result in dst
  ///
  /// dst : a cairo_region_t
  ///
  /// rectangle : a cairo_rectangle_int_t
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn intersect_rectangle(&mut self, rectangle: &Rectangle) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_intersect_rectangle(self.opaque, rectangle);
      return foreign_result;
    }
  }

  ///  Subtracts other from dst and places the result in dst
  ///
  /// dst : a cairo_region_t
  ///
  /// other : another cairo_region_t
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn subtract(&mut self, region: &Region) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_subtract(self.opaque, region);
      return foreign_result;
    }
  }

  ///  Subtracts rectangle from dst and places the result in dst
  ///
  /// dst : a cairo_region_t
  ///
  /// rectangle : a cairo_rectangle_int_t
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn subtract_rectangle(&mut self, rectangle: &Rectangle) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_subtract_rectangle(self.opaque, rectangle);
      return foreign_result;
    }
  }

  ///  Computes the union of dst with other and places the result in dst
  ///
  /// dst : a cairo_region_t
  ///
  /// other : another cairo_region_t
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn union(&mut self, region: &Region) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_union(self.opaque, region);
      return foreign_result;
    }
  }

  ///  Computes the union of dst with rectangle and places the result in dst.
  ///
  /// dst : a cairo_region_t
  ///
  /// rectangle : a cairo_rectangle_int_t
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn union_rectangle(&mut self, rectangle: &Rectangle) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_union_rectangle(self.opaque, rectangle);
      return foreign_result;
    }
  }

  ///  Computes the exclusive difference of dst with other and places the result in dst. That is, dst will be set to contain all areas that are either in dst or in other, but not in both.
  ///
  /// dst : a cairo_region_t
  ///
  /// other : another cairo_region_t
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn xor(&mut self, region: &Region) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_xor(self.opaque, region);
      return foreign_result;
    }
  }

  ///  Computes the exclusive difference of dst with rectangle and places the result in dst. That is, dst will be set to contain all areas that are either in dst or in rectangle, but not in both.
  ///
  /// dst : a cairo_region_t
  ///
  /// rectangle : a cairo_rectangle_int_t
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn xor_rectangle(&mut self, rectangle: &Rectangle) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_xor_rectangle(self.opaque, rectangle);
      return foreign_result;
    }
  }
}

extern {
  fn cairo_region_create() -> Region;
  fn cairo_region_create_rectangle(rectangle: *Rectangle) -> Region;
  fn cairo_region_create_rectangles(rectangles: *Rectangle, rectangles_length: i32) -> Region;
  fn cairo_region_status(self_value: *mut std::libc::c_void) -> super::Status;
  fn cairo_region_get_extents(self_value: *mut std::libc::c_void, extents: *mut Rectangle);
  fn cairo_region_num_rectangles(self_value: *mut std::libc::c_void) -> i32;
  fn cairo_region_get_rectangle(self_value: *mut std::libc::c_void, nth: i32, rectangle: *mut Rectangle);
  fn cairo_region_is_empty(self_value: *mut std::libc::c_void) -> i32;
  fn cairo_region_contains_point(self_value: *mut std::libc::c_void, x: i32, y: i32) -> i32;
  fn cairo_region_contains_rectangle(self_value: *mut std::libc::c_void, rectangle: *Rectangle) -> overlap::Overlap;
  fn cairo_region_equal(self_value: *mut std::libc::c_void, other: *std::libc::c_void) -> i32;
  fn cairo_region_translate(self_value: *mut std::libc::c_void, dx: i32, dy: i32);
  fn cairo_region_intersect_rectangle(self_value: *mut std::libc::c_void, rectangle: *Rectangle) -> super::Status;
  fn cairo_region_subtract(self_value: *mut std::libc::c_void, region: *Region) -> super::Status;
  fn cairo_region_subtract_rectangle(self_value: *mut std::libc::c_void, rectangle: *Rectangle) -> super::Status;
  fn cairo_region_union(self_value: *mut std::libc::c_void, region: *Region) -> super::Status;
  fn cairo_region_union_rectangle(self_value: *mut std::libc::c_void, rectangle: *Rectangle) -> super::Status;
  fn cairo_region_xor(self_value: *mut std::libc::c_void, region: *Region) -> super::Status;
  fn cairo_region_xor_rectangle(self_value: *mut std::libc::c_void, rectangle: *Rectangle) -> super::Status;
}

impl std::clone::Clone for Region {
  fn clone(&self) -> Region {
    unsafe {
      let foreign_result = cairo_region_reference(self.opaque as *std::libc::c_void);
      return foreign_result;
    }
  }
}

extern {
  fn cairo_region_reference(self_value: *std::libc::c_void) -> Region;
}

impl DeepClone for Region {
  fn deep_clone(&self) -> Region {
    unsafe {
      let foreign_result = cairo_region_copy(self.opaque as *std::libc::c_void);
      return foreign_result;
    }
  }
}

extern {
  fn cairo_region_copy(self_value: *std::libc::c_void) -> Region;
}

impl std::ops::Drop for Region {
  fn drop(&mut self) {
    unsafe {
      cairo_region_destroy(self.opaque);
    }
  }
}

extern {
  fn cairo_region_destroy(self_value: *mut std::libc::c_void);
}

pub mod overlap;
<commit_msg>Replaced Cairo '_t' types with Rust-Cairo types<commit_after>//! Representing a pixel-aligned area

use std;
use super::DeepClone;

/// A region::Region represents a set of integer-aligned rectangles.
///
/// It allows set-theoretical operations like cairo_region_union() and cairo_region_intersect() to be performed on them.
///
/// Memory management of region::Region is done with cairo_region_reference() and cairo_region_destroy().
///
/// Since 1.10
pub struct Region {
  /// Wraps Cairo pointer for region.
  opaque: *mut std::libc::c_void
}

///  A data structure for holding a rectangle with integer coordinates.
///
/// Since 1.10
pub struct Rectangle {
  /// X coordinate of the left side of the rectangle
  x: i32,
  /// Y coordinate of the the top side of the rectangle
  y: i32,
  /// width of the rectangle
  width: i32,
  /// height of the rectangle
  height: i32
}

impl Region {
  ///  Allocates a new empty region object.
  ///
  /// Returns : A newly allocated region::Region. Free with cairo_region_destroy(). This function always returns a valid pointer; if memory cannot be allocated, then a special error object is returned where all operations on the object do nothing. You can check for this with cairo_region_status().
  ///
  /// Since 1.10
  pub fn new() -> Region {
    unsafe {
      let foreign_result = cairo_region_create();
      return foreign_result;
    }
  }

  ///  Allocates a new region object containing rectangle.
  ///
  /// rectangle : a region::Rectangle
  ///
  /// Returns : A newly allocated region::Region. Free with cairo_region_destroy(). This function always returns a valid pointer; if memory cannot be allocated, then a special error object is returned where all operations on the object do nothing. You can check for this with cairo_region_status().
  ///
  /// Since 1.10
  pub fn rectangle(rectangle: &Rectangle) -> Region {
    unsafe {
      let foreign_result = cairo_region_create_rectangle(rectangle);
      return foreign_result;
    }
  }

  ///  Allocates a new region object containing the union of all given rects.
  ///
  /// rects : an array of count rectangles
  ///
  /// count : number of rectangles
  ///
  /// Returns : A newly allocated region::Region. Free with cairo_region_destroy(). This function always returns a valid pointer; if memory cannot be allocated, then a special error object is returned where all operations on the object do nothing. You can check for this with cairo_region_status().
  ///
  /// Since 1.10
  pub fn rectangles(rectangles: &[Rectangle]) -> Region {
    unsafe {
      let foreign_result = cairo_region_create_rectangles(rectangles.as_ptr(), rectangles.len() as i32);
      return foreign_result;
    }
  }

  ///  Checks whether an error has previous occurred for this region object.
  ///
  /// region : a region::Region
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn status(&mut self) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_status(self.opaque);
      return foreign_result;
    }
  }

  ///  Gets the bounding rectangle of region as a region::Rectangle
  ///
  /// region : a region::Region
  ///
  /// extents : rectangle into which to store the extents
  ///
  /// Since 1.10
  pub fn get_extents(&mut self) -> Rectangle {
    unsafe {
      let mut extents:Rectangle = std::intrinsics::init();
      cairo_region_get_extents(self.opaque, &mut extents);
      return extents;
    }
  }

  ///  Returns the number of rectangles contained in region.
  ///
  /// region : a region::Region
  ///
  /// Returns : The number of rectangles contained in region.
  ///
  /// Since 1.10
  pub fn num_rectangles(&mut self) -> i32 {
    unsafe {
      let foreign_result = cairo_region_num_rectangles(self.opaque);
      return foreign_result;
    }
  }

  ///  Stores the nth rectangle from the region in rectangle.
  ///
  /// region : a region::Region
  ///
  /// nth : a number indicating which rectangle should be returned
  ///
  /// rectangle : return location for a region::Rectangle
  ///
  /// Since 1.10
  pub fn get_rectangle(&mut self, nth: i32) -> Rectangle {
    unsafe {
      let mut rectangle:Rectangle = std::intrinsics::init();
      cairo_region_get_rectangle(self.opaque, nth, &mut rectangle);
      return rectangle;
    }
  }

  ///  Checks whether region is empty.
  ///
  /// region : a region::Region
  ///
  /// Returns : TRUE if region is empty, FALSE if it isn't.
  ///
  /// Since 1.1
  pub fn is_empty(&mut self) -> bool {
    unsafe {
      let foreign_result = cairo_region_is_empty(self.opaque);
      return foreign_result != 0;
    }
  }

  ///  Checks whether (x, y) is contained in region.
  ///
  /// region : a region::Region
  ///
  /// x : the x coordinate of a point
  ///
  /// y : the y coordinate of a point
  ///
  /// Returns : TRUE if (x, y) is contained in region, FALSE if it is not.
  ///
  /// Since 1.10
  pub fn contains_point(&mut self, x: i32, y: i32) -> bool {
    unsafe {
      let foreign_result = cairo_region_contains_point(self.opaque, x, y);
      return foreign_result != 0;
    }
  }

  ///  Checks whether rectangle is inside, outside or partially contained in region
  ///
  /// region : a region::Region
  ///
  /// rectangle : a region::Rectangle
  ///
  /// Returns : CAIRO_REGION_OVERLAP_IN if rectangle is entirely inside region, CAIRO_REGION_OVERLAP_OUT if rectangle is entirely outside region, or CAIRO_REGION_OVERLAP_PART if rectangle is partially inside and partially outside region.
  ///
  /// Since 1.10
  pub fn containts_rectangle(&mut self, rectangle: &Rectangle) -> overlap::Overlap {
    unsafe {
      let foreign_result = cairo_region_contains_rectangle(self.opaque, rectangle);
      return foreign_result;
    }
  }

  ///  Compares whether region_a is equivalent to region_b. NULL as an argument is equal to itself, but not to any non-NULL region.
  ///
  /// a : a region::Region or NULL
  ///
  /// b : a region::Region or NULL
  ///
  /// Returns : TRUE if both regions contained the same coverage, FALSE if it is not or any region is in an error status.
  ///
  /// Since 1.10
  pub fn equal(&mut self, other: &Region) -> bool {
    unsafe {
      let foreign_result = cairo_region_equal(self.opaque, other.opaque as *std::libc::c_void);
      return foreign_result != 0;
    }
  }

  ///  Translates region by (dx, dy).
  ///
  /// region : a region::Region
  ///
  /// dx : Amount to translate in the x direction
  ///
  /// dy : Amount to translate in the y direction
  ///
  /// Since 1.10
  pub fn translate(&mut self, dx: i32, dy: i32) {
    unsafe {
      cairo_region_translate(self.opaque, dx, dy);
    }
  }

  ///  Computes the intersection of dst with rectangle and places the result in dst
  ///
  /// dst : a region::Region
  ///
  /// rectangle : a region::Rectangle
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn intersect_rectangle(&mut self, rectangle: &Rectangle) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_intersect_rectangle(self.opaque, rectangle);
      return foreign_result;
    }
  }

  ///  Subtracts other from dst and places the result in dst
  ///
  /// dst : a region::Region
  ///
  /// other : another region::Region
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn subtract(&mut self, region: &Region) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_subtract(self.opaque, region);
      return foreign_result;
    }
  }

  ///  Subtracts rectangle from dst and places the result in dst
  ///
  /// dst : a region::Region
  ///
  /// rectangle : a region::Rectangle
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn subtract_rectangle(&mut self, rectangle: &Rectangle) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_subtract_rectangle(self.opaque, rectangle);
      return foreign_result;
    }
  }

  ///  Computes the union of dst with other and places the result in dst
  ///
  /// dst : a region::Region
  ///
  /// other : another region::Region
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn union(&mut self, region: &Region) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_union(self.opaque, region);
      return foreign_result;
    }
  }

  ///  Computes the union of dst with rectangle and places the result in dst.
  ///
  /// dst : a region::Region
  ///
  /// rectangle : a region::Rectangle
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn union_rectangle(&mut self, rectangle: &Rectangle) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_union_rectangle(self.opaque, rectangle);
      return foreign_result;
    }
  }

  ///  Computes the exclusive difference of dst with other and places the result in dst. That is, dst will be set to contain all areas that are either in dst or in other, but not in both.
  ///
  /// dst : a region::Region
  ///
  /// other : another region::Region
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn xor(&mut self, region: &Region) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_xor(self.opaque, region);
      return foreign_result;
    }
  }

  ///  Computes the exclusive difference of dst with rectangle and places the result in dst. That is, dst will be set to contain all areas that are either in dst or in rectangle, but not in both.
  ///
  /// dst : a region::Region
  ///
  /// rectangle : a region::Rectangle
  ///
  /// Returns : CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
  ///
  /// Since 1.10
  pub fn xor_rectangle(&mut self, rectangle: &Rectangle) -> super::Status {
    unsafe {
      let foreign_result = cairo_region_xor_rectangle(self.opaque, rectangle);
      return foreign_result;
    }
  }
}

extern {
  fn cairo_region_create() -> Region;
  fn cairo_region_create_rectangle(rectangle: *Rectangle) -> Region;
  fn cairo_region_create_rectangles(rectangles: *Rectangle, rectangles_length: i32) -> Region;
  fn cairo_region_status(self_value: *mut std::libc::c_void) -> super::Status;
  fn cairo_region_get_extents(self_value: *mut std::libc::c_void, extents: *mut Rectangle);
  fn cairo_region_num_rectangles(self_value: *mut std::libc::c_void) -> i32;
  fn cairo_region_get_rectangle(self_value: *mut std::libc::c_void, nth: i32, rectangle: *mut Rectangle);
  fn cairo_region_is_empty(self_value: *mut std::libc::c_void) -> i32;
  fn cairo_region_contains_point(self_value: *mut std::libc::c_void, x: i32, y: i32) -> i32;
  fn cairo_region_contains_rectangle(self_value: *mut std::libc::c_void, rectangle: *Rectangle) -> overlap::Overlap;
  fn cairo_region_equal(self_value: *mut std::libc::c_void, other: *std::libc::c_void) -> i32;
  fn cairo_region_translate(self_value: *mut std::libc::c_void, dx: i32, dy: i32);
  fn cairo_region_intersect_rectangle(self_value: *mut std::libc::c_void, rectangle: *Rectangle) -> super::Status;
  fn cairo_region_subtract(self_value: *mut std::libc::c_void, region: *Region) -> super::Status;
  fn cairo_region_subtract_rectangle(self_value: *mut std::libc::c_void, rectangle: *Rectangle) -> super::Status;
  fn cairo_region_union(self_value: *mut std::libc::c_void, region: *Region) -> super::Status;
  fn cairo_region_union_rectangle(self_value: *mut std::libc::c_void, rectangle: *Rectangle) -> super::Status;
  fn cairo_region_xor(self_value: *mut std::libc::c_void, region: *Region) -> super::Status;
  fn cairo_region_xor_rectangle(self_value: *mut std::libc::c_void, rectangle: *Rectangle) -> super::Status;
}

impl std::clone::Clone for Region {
  fn clone(&self) -> Region {
    unsafe {
      let foreign_result = cairo_region_reference(self.opaque as *std::libc::c_void);
      return foreign_result;
    }
  }
}

extern {
  fn cairo_region_reference(self_value: *std::libc::c_void) -> Region;
}

impl DeepClone for Region {
  fn deep_clone(&self) -> Region {
    unsafe {
      let foreign_result = cairo_region_copy(self.opaque as *std::libc::c_void);
      return foreign_result;
    }
  }
}

extern {
  fn cairo_region_copy(self_value: *std::libc::c_void) -> Region;
}

impl std::ops::Drop for Region {
  fn drop(&mut self) {
    unsafe {
      cairo_region_destroy(self.opaque);
    }
  }
}

extern {
  fn cairo_region_destroy(self_value: *mut std::libc::c_void);
}

pub mod overlap;
<|endoftext|>


<commit_before>#![feature(slice_patterns)]
use std::env;
use std::fs::File;
use std::io::Read;
use std::collections::HashMap;

#[derive(Clone)]
enum Expr {
  Int(i64),
  Str(String)
}

// XXX this should probably be split up. The VM has the instructions, a "Thread" has locals, stack, and arguments.
struct VM<'a> {
  instructions: Vec<&'a str>,
  locals: HashMap<&'a str, Expr>,
  labels: HashMap<&'a str, usize>,
}

fn parse_labels<'a>(instructions: &Vec<&'a str>) -> HashMap<&'a str, usize> {
  let mut map = HashMap::new();
  for (i, instr) in instructions.iter().enumerate() {
    if instr.starts_with("$label") {
      match instr.split(' ').nth(1) {
        Some(label) => map.insert(label, i),
        None => panic!("VM error: missing label"),
      };
    }
  };
  map
}

impl<'a> VM<'a> {
  pub fn new(instructions: Vec<&'a str>) -> VM {
    VM {
      labels: parse_labels(&instructions),
      instructions: instructions,
      locals: HashMap::new(),
    }
  }

  pub fn run(&mut self) {
    let ip = self.labels.get("main").unwrap_or(&0).clone();
    self.run_call(ip, &mut Vec::new());
  }

  // TODO locals
  pub fn run_call(&mut self, start_ip: usize, stack: &mut Vec<Expr>) -> Option<Expr> {
    let mut ip = start_ip;
    let len = self.instructions.len();

    let mut carry = false; // comparison carry

    let mut arguments = Vec::new();

    while ip < len {
      let instr = self.instructions[ip];
      ip += 1;
      if instr.starts_with("#") || instr.trim() == "" {
        continue;
      }
      match instr.split(" ").collect::<Vec<_>>().as_slice() {
        ["$label", _] => (),
        ["push", "int", n] => stack.push(Expr::Int(n.parse::<i64>().unwrap())),
        ["push", "str", n] => stack.push(Expr::Str(String::from(n))),
        ["push", "arg"] => arguments.push(stack.pop().expect("Nothing on the stack to push to the arguments")),

        ["dup"] => {
          let expr = stack.pop().expect("Nothing on the stack to pop");
          stack.push(expr.clone());
          stack.push(expr);
        },

        // convert to string
        ["convert", "int", "str"] => if let Some(&Expr::Int(arg)) = stack.last() {
          stack.push(Expr::Str(arg.to_string()));
        } else {
          panic!("VM error: cannot convert int to string");
        },

        ["convert", from, to] => panic!("VM error: cannot convert from {} to {}", from, to),

        // how = "always" | "carry"
        ["jump", how, n] => {
          let new_ip = if n.starts_with("$") {
            self.labels.get(n.trim_matches('$')).expect("VM error: no such label").clone()
          } else {
            n.parse::<usize>().unwrap()
          };

          if new_ip < len {
            // only check carry if we are conditionally jumping
            if how == "always" || (how == "carry" && carry) {
              ip = new_ip;
            }
          } else {
            panic!("VM error: trying to jump past end of bytecode ({} > {})", new_ip, len);
          }
        },

        ["carry", "set", val] => carry = val == "true",
        ["carry", "invert"] => carry = !carry,

        ["call", "primitive", "say"] => if let Some(Expr::Str(arg)) = stack.pop() {
          println!("hey {}", arg);
        } else {
          panic!("VM error: incorrect arguments to `say`");
        },

        // TODO resolve name in scope, check type, apply
        ["call", name] => {
          let new_ip = self.labels.get(name).expect("VM error: no such label").clone();
          let ret = self.run_call(new_ip, &mut arguments);
          arguments = Vec::new();
          match ret {
            Some(val) => stack.push(val),
            None => (),
          };
        },

        ["ret"] => {
          return None;
        },

        ["ret", "val"] => {
          if stack.len() != 1 {
            panic!("VM error: trying to return a value but the stack size is not 1 ({})", stack.len());
          }
          return stack.pop();
        },

        // NOTE: it's stack[*-1] OP stack[*-2]
        // which means if have stack=[1, 2]
        // you'll have 2 OP 1
        /// XXX this should JUST be a call!
        ["math", op] => if let
            (Some(Expr::Int(arg1)), Some(Expr::Int(arg2)))
            =
            (stack.pop(), stack.pop()) {
          let value = match op {
            "+" => arg1 + arg2,
            "-" => arg1 + arg2,
            //"/" => TODO. this should have very specific rules...
            "*" => arg1 * arg2,
            _ => panic!("VM error: unrecognized `op` operator: {}", op),
          };
          stack.push(Expr::Int(value));
        } else {
          panic!("VM error: not enough arguments to `math`");
        },

        // same note about "2 OP 1"
        // XXX same note about how this should be a `call`
        ["cmp", op] => if let
            (Some(Expr::Int(arg1)), Some(Expr::Int(arg2)))
            =
            (stack.pop(), stack.pop()) {
          carry = match op {
            "<" => arg1 < arg2,
            ">" => arg1 > arg2,
            "<=" => arg1 <= arg2,
            ">=" => arg1 >= arg2,
            "=" => arg1 == arg2,
            _ => panic!("VM error: unrecognized `cmp` operator: {}", op),
          };
        } else {
          panic!("VM error: not enough arguments to `cmp`");
        },

        // TODO this *shouldn't* be an identifier
        //      the backend should transform SSAF to tons of load/store
        //      (probably)
        //      (see backend#1)
        ["local", "load", name] => match self.locals.get(name) {
          Some(expr) => stack.push(expr.clone()),
          None       => panic!("VM error: unknown local variable {}", name),
        },

        ["local", "store", name] => if let Some(arg) = stack.pop() {
          // XXX check
          let _ = self.locals.insert(name, arg);
        } else {
          panic!("VM error: not enough arguments for `local store`");
        },

        [instr, ..] => panic!("VM error: no such instruction {}", instr),
        [..] => panic!("VM error: Unrecognized instruction!"),
      }
    }

    None
  }
}

fn main() {
	if let Some(path) = env::args().nth(1) {
		println!("Loading file {}", path);

    match File::open(&path) {
      Ok(mut file) => {
        let mut content = String::new();
        if let Ok(_) = file.read_to_string(&mut content) {
          // remove trailing newlines, split by line
          let instructions = content.trim_matches('\n').split('\n').collect();
          let mut vm = VM::new(instructions);
          vm.run();
        }
      },
      Err(err) => {
        panic!("Can't read file {} (error: {})", path, err);
      }
    }
	} else {
    panic!("Please give a file argument");
  }

  //     let path = Path::new("chry.fa");
  // let mut file = BufferedReader::new(File::open(&path));
  // for line in file.lines() {
  //  print!("{}", line.unwrap());
  //      }
}
<commit_msg>`convert` should pop arg<commit_after>#![feature(slice_patterns)]
use std::env;
use std::fs::File;
use std::io::Read;
use std::collections::HashMap;

#[derive(Clone)]
enum Expr {
  Int(i64),
  Str(String)
}

// XXX this should probably be split up. The VM has the instructions, a "Thread" has locals, stack, and arguments.
struct VM<'a> {
  instructions: Vec<&'a str>,
  locals: HashMap<&'a str, Expr>,
  labels: HashMap<&'a str, usize>,
}

fn parse_labels<'a>(instructions: &Vec<&'a str>) -> HashMap<&'a str, usize> {
  let mut map = HashMap::new();
  for (i, instr) in instructions.iter().enumerate() {
    if instr.starts_with("$label") {
      match instr.split(' ').nth(1) {
        Some(label) => map.insert(label, i),
        None => panic!("VM error: missing label"),
      };
    }
  };
  map
}

impl<'a> VM<'a> {
  pub fn new(instructions: Vec<&'a str>) -> VM {
    VM {
      labels: parse_labels(&instructions),
      instructions: instructions,
      locals: HashMap::new(),
    }
  }

  pub fn run(&mut self) {
    let ip = self.labels.get("main").unwrap_or(&0).clone();
    self.run_call(ip, &mut Vec::new());
  }

  // TODO locals
  pub fn run_call(&mut self, start_ip: usize, stack: &mut Vec<Expr>) -> Option<Expr> {
    let mut ip = start_ip;
    let len = self.instructions.len();

    let mut carry = false; // comparison carry

    let mut arguments = Vec::new();

    while ip < len {
      let instr = self.instructions[ip];
      ip += 1;
      if instr.starts_with("#") || instr.trim() == "" {
        continue;
      }
      match instr.split(" ").collect::<Vec<_>>().as_slice() {
        ["$label", _] => (),
        ["push", "int", n] => stack.push(Expr::Int(n.parse::<i64>().unwrap())),
        ["push", "str", n] => stack.push(Expr::Str(String::from(n))),
        ["push", "arg"] => arguments.push(stack.pop().expect("Nothing on the stack to push to the arguments")),

        ["dup"] => {
          let expr = stack.pop().expect("Nothing on the stack to pop");
          stack.push(expr.clone());
          stack.push(expr);
        },

        // convert to string
        ["convert", "int", "str"] => if let Some(Expr::Int(arg)) = stack.pop() {
          stack.push(Expr::Str(arg.to_string()));
        } else {
          panic!("VM error: cannot convert int to string");
        },

        ["convert", from, to] => panic!("VM error: cannot convert from {} to {}", from, to),

        // how = "always" | "carry"
        ["jump", how, n] => {
          let new_ip = if n.starts_with("$") {
            self.labels.get(n.trim_matches('$')).expect("VM error: no such label").clone()
          } else {
            n.parse::<usize>().unwrap()
          };

          if new_ip < len {
            // only check carry if we are conditionally jumping
            if how == "always" || (how == "carry" && carry) {
              ip = new_ip;
            }
          } else {
            panic!("VM error: trying to jump past end of bytecode ({} > {})", new_ip, len);
          }
        },

        ["carry", "set", val] => carry = val == "true",
        ["carry", "invert"] => carry = !carry,

        ["call", "primitive", "say"] => if let Some(Expr::Str(arg)) = stack.pop() {
          println!("hey {}", arg);
        } else {
          panic!("VM error: incorrect arguments to `say`");
        },

        // TODO resolve name in scope, check type, apply
        ["call", name] => {
          let new_ip = self.labels.get(name).expect("VM error: no such label").clone();
          let ret = self.run_call(new_ip, &mut arguments);
          arguments = Vec::new();
          match ret {
            Some(val) => stack.push(val),
            None => (),
          };
        },

        ["ret"] => {
          return None;
        },

        ["ret", "val"] => {
          if stack.len() != 1 {
            panic!("VM error: trying to return a value but the stack size is not 1 ({})", stack.len());
          }
          return stack.pop();
        },

        // NOTE: it's stack[*-1] OP stack[*-2]
        // which means if have stack=[1, 2]
        // you'll have 2 OP 1
        /// XXX this should JUST be a call!
        ["math", op] => if let
            (Some(Expr::Int(arg1)), Some(Expr::Int(arg2)))
            =
            (stack.pop(), stack.pop()) {
          let value = match op {
            "+" => arg1 + arg2,
            "-" => arg1 + arg2,
            //"/" => TODO. this should have very specific rules...
            "*" => arg1 * arg2,
            _ => panic!("VM error: unrecognized `op` operator: {}", op),
          };
          stack.push(Expr::Int(value));
        } else {
          panic!("VM error: not enough arguments to `math`");
        },

        // same note about "2 OP 1"
        // XXX same note about how this should be a `call`
        ["cmp", op] => if let
            (Some(Expr::Int(arg1)), Some(Expr::Int(arg2)))
            =
            (stack.pop(), stack.pop()) {
          carry = match op {
            "<" => arg1 < arg2,
            ">" => arg1 > arg2,
            "<=" => arg1 <= arg2,
            ">=" => arg1 >= arg2,
            "=" => arg1 == arg2,
            _ => panic!("VM error: unrecognized `cmp` operator: {}", op),
          };
        } else {
          panic!("VM error: not enough arguments to `cmp`");
        },

        // TODO this *shouldn't* be an identifier
        //      the backend should transform SSAF to tons of load/store
        //      (probably)
        //      (see backend#1)
        ["local", "load", name] => match self.locals.get(name) {
          Some(expr) => stack.push(expr.clone()),
          None       => panic!("VM error: unknown local variable {}", name),
        },

        ["local", "store", name] => if let Some(arg) = stack.pop() {
          // XXX check
          let _ = self.locals.insert(name, arg);
        } else {
          panic!("VM error: not enough arguments for `local store`");
        },

        [instr, ..] => panic!("VM error: no such instruction {}", instr),
        [..] => panic!("VM error: Unrecognized instruction!"),
      }
    }

    None
  }
}

fn main() {
	if let Some(path) = env::args().nth(1) {
		println!("Loading file {}", path);

    match File::open(&path) {
      Ok(mut file) => {
        let mut content = String::new();
        if let Ok(_) = file.read_to_string(&mut content) {
          // remove trailing newlines, split by line
          let instructions = content.trim_matches('\n').split('\n').collect();
          let mut vm = VM::new(instructions);
          vm.run();
        }
      },
      Err(err) => {
        panic!("Can't read file {} (error: {})", path, err);
      }
    }
	} else {
    panic!("Please give a file argument");
  }

  //     let path = Path::new("chry.fa");
  // let mut file = BufferedReader::new(File::open(&path));
  // for line in file.lines() {
  //  print!("{}", line.unwrap());
  //      }
}
<|endoftext|>


<commit_before>use petgraph::{Graph, Undirected};
use rand;
use rand::distributions::{IndependentSample, Range};

pub type GridIndexType = u16;
pub type GridGraphNodeIndex = ::petgraph::graph::NodeIndex<GridIndexType>;

pub enum GridDirection {
    North,
    South,
    East,
    West,
}

struct AdjacentCells {
    north: Option<GridGraphNodeIndex>,
    south: Option<GridGraphNodeIndex>,
    east: Option<GridGraphNodeIndex>,
    west: Option<GridGraphNodeIndex>,
}
impl AdjacentCells {
    fn new() -> Self {
        AdjacentCells {
            north: None,
            south: None,
            east: None,
            west: None,
        }
    }
}

#[derive(Hash, Eq, PartialEq, Debug, Copy, Clone)]
struct GridCoordinate {
    pub x: isize,
    pub y: isize,
}

pub struct SquareGrid {
    /// For mapping a 2D gridcoordinate (converted to a 1D index) to a graph node index.
    grid_coordinate_to_node_index_lookup: Vec<GridGraphNodeIndex>,
    graph: Graph<AdjacentCells, (), Undirected, GridIndexType>,
    dimension_size: GridIndexType,
}

impl SquareGrid {
    pub fn new(dimension_size: GridIndexType) -> SquareGrid {

        let cells_count = dimension_size * dimension_size;
        let nodes_count_hint = cells_count as usize;
        let edges_count_hint = 4 * cells_count as usize - 4 * dimension_size as usize; // Probably overkill, but don't want any capacity panics

        let mut grid = SquareGrid {
            grid_coordinate_to_node_index_lookup: Vec::with_capacity(nodes_count_hint),
            graph: Graph::with_capacity(nodes_count_hint, edges_count_hint),
            dimension_size: dimension_size,
        };

        // Although it does seem to, there is no guarantee that the index values are monotonically increasing when calling graph.add_node
        // So we maintain our own symbol table mapping gridcoordinates converted to 1d (the implicit Vec indices) to the NodeIndexes created
        // by adding a node to the graph.
        for _ in 0..cells_count {
            let node_index = grid.graph.add_node(AdjacentCells::new());
            grid.grid_coordinate_to_node_index_lookup.push(node_index);
        }

        for (index, node_index) in grid.grid_coordinate_to_node_index_lookup.iter().enumerate() {

            let coord = to_grid_coordinate(index, dimension_size);

            // Limit the lifetime of the find_neighbour_nodeindex closure so we don't get a grid
            // borrow conflict when mutating the adjacent_cells
            let (north_index, south_index, east_index, west_index) = {
                let find_neighbour_nodeindex = |dir: GridDirection| -> Option<GridGraphNodeIndex> {
                    let neighbour_coord = offset_coordinate(&coord, dir);
                    if is_valid_coordinate(&neighbour_coord, dimension_size) {
                        let node_indices_index = to_1d_index(&neighbour_coord, dimension_size);
                        let node_index =
                            grid.grid_coordinate_to_node_index_lookup[node_indices_index as usize];
                        Some(node_index)
                    } else {
                        None
                    }
                };
                (find_neighbour_nodeindex(GridDirection::North),
                 find_neighbour_nodeindex(GridDirection::South),
                 find_neighbour_nodeindex(GridDirection::East),
                 find_neighbour_nodeindex(GridDirection::West))
            };

            let adjacent_cells = grid.graph
                                     .node_weight_mut(node_index.clone())
                                     .unwrap();
            adjacent_cells.north = north_index;
            adjacent_cells.south = south_index;
            adjacent_cells.east = east_index;
            adjacent_cells.west = west_index;
        }

        grid
    }

    pub fn random_cell(&self) -> GridGraphNodeIndex {
        let random_pos = Range::new(0, self.grid_coordinate_to_node_index_lookup.len());
        let mut rng = rand::thread_rng();
        let index = random_pos.ind_sample(&mut rng);
        self.grid_coordinate_to_node_index_lookup[index]
    }

    /// Link two cells
    ///
    /// Todo - only allow links between adjacent cells? If `b` not in `g.neighbours(a)`.
    ///      - better to change the API to take an index and GridDirection
    ///
    /// Panics if a cell does not exist.
    pub fn link(&mut self, a: GridGraphNodeIndex, b: GridGraphNodeIndex) {
        if a != b {
            let _ = self.graph.update_edge(a, b, ());
        }
    }

    /// Unlink two cells, if a link exists between them.
    pub fn unlink(&mut self, a: GridGraphNodeIndex, b: GridGraphNodeIndex) {

        if let Some(edge_index) = self.graph.find_edge(a, b) {
            // This will invalidate the last edge index in the graph, which is fine as we
            // are not storing them for any reason.
            self.graph.remove_edge(edge_index);
        }
    }

    /// Cell nodes that are linked to a particular node by a passage.
    pub fn links(&self, node_index: GridGraphNodeIndex) -> Vec<GridGraphNodeIndex> {
        self.graph
            .edges(node_index)
            .map(|index_edge_data_pair| index_edge_data_pair.0.clone())
            .collect()
    }

    /// Cell nodes that are to the North, South, East or West of a particular node, but not
    /// necessarily linked by a passage.
    pub fn neighbours(&self, node_index: GridGraphNodeIndex) -> Vec<GridGraphNodeIndex> {

        if let Some(adj) = self.graph.node_weight(node_index) {
            vec![adj.north, adj.south, adj.east, adj.west]
                .iter()
                .filter_map(|&maybe_adj| maybe_adj.clone())
                .collect()
        } else {
            vec![]
        }
    }

    fn is_neighbour(&self, a: GridGraphNodeIndex, b: GridGraphNodeIndex) -> bool {
        macro_rules! index_node_match {
            ($opt_grid_index:expr) => (if let Some(node_index) = $opt_grid_index {
                                           if node_index == b {
                                               return true;
                                           }
                                       })
        }
        if let Some(adjacents_of_a) = self.graph.node_weight(a) {
            index_node_match!(adjacents_of_a.north);
            index_node_match!(adjacents_of_a.south);
            index_node_match!(adjacents_of_a.east);
            index_node_match!(adjacents_of_a.west);
        }
        false
    }
}

fn offset_coordinate(coord: &GridCoordinate, dir: GridDirection) -> GridCoordinate {
    let (x, y) = (coord.x, coord.y);
    match dir {
        GridDirection::North => GridCoordinate { x: x, y: y - 1 },
        GridDirection::South => GridCoordinate { x: x, y: y + 1 },
        GridDirection::East => GridCoordinate { x: x + 1, y: y },
        GridDirection::West => GridCoordinate { x: x - 1, y: y },
    }
}

fn is_valid_coordinate(coord: &GridCoordinate, dimension_size: GridIndexType) -> bool {
    if coord.x < 0 || coord.y < 0 {
        return false;
    }
    let (x, y) = (coord.x, coord.y);
    if x >= dimension_size as isize || y >= dimension_size as isize {
        return false;
    }
    true
}

fn to_1d_index(coord: &GridCoordinate, dimension_size: GridIndexType) -> GridIndexType {
    ((coord.y * dimension_size as isize) + coord.x) as GridIndexType
}

fn to_grid_coordinate(one_dimensional_index: usize,
                      dimension_size: GridIndexType)
                      -> GridCoordinate {
    let y = one_dimensional_index / dimension_size as usize;
    let x = one_dimensional_index - (y * dimension_size as usize);
    GridCoordinate {
        x: x as isize,
        y: y as isize,
    }
}

#[cfg(test)]
mod test {

    use super::*;
    use itertools::Itertools; // a trait

    #[test]
    fn neighbour_cells() {
        let g = SquareGrid::new(10);

        let check_expected_neighbours = |node_index, vec_expected_neighbour_indices: Vec<usize>| {
            let node_indices = g.neighbours(GridGraphNodeIndex::new(node_index))
                                .into_iter()
                                .sorted();
            let expected_indices =
                vec_expected_neighbour_indices.into_iter()
                                              .sorted()
                                              .into_iter()
                                              .map(|index: usize| GridGraphNodeIndex::new(index))
                                              .collect::<Vec<GridGraphNodeIndex>>();
            assert_eq!(node_indices, expected_indices);
        };

        // corners
        check_expected_neighbours(0, vec![1, 10]);
        check_expected_neighbours(9, vec![8, 19]);
        check_expected_neighbours(90, vec![80, 91]);
        check_expected_neighbours(99, vec![89, 98]);

        // side element examples
        check_expected_neighbours(10, vec![0, 11, 20]);
        check_expected_neighbours(1, vec![0, 2, 11]);
        check_expected_neighbours(80, vec![70, 81, 90]);
        check_expected_neighbours(89, vec![79, 88, 99]);
        check_expected_neighbours(19, vec![9, 18, 29]);
        check_expected_neighbours(8, vec![7, 9, 18]);

        // Some place with 4 neighbours inside the grid
        check_expected_neighbours(12, vec![2, 11, 13, 22]);
    }

    #[test]
    fn random_cell() {
        let g = SquareGrid::new(4);
        let cells_count = 4 * 4;
        for _ in 0..1000 {
            let grid_index = g.random_cell();
            assert!(grid_index.index() >= 0 && grid_index.index() < cells_count);
        }
    }

    #[test]
    fn linking_cells() {
        let mut g = SquareGrid::new(4);
        let a = GridGraphNodeIndex::new(0);
        let b = GridGraphNodeIndex::new(1);
        let c = GridGraphNodeIndex::new(2);

        // I'd rather use a closure, but it needs to borrow the graph immutably until
        // it goes out of scope
        // Passing the graph in allows me to use a plain function:
        // let links_sorted = |n: GridGraphNodeIndex, g: &SquareGrid| -> Vec<GridGraphNodeIndex> {
        //     g.links(n).into_iter().sorted()
        // };
        // but it's uglier in that I need to explicitly pass in the SquareGrid ref all the time
        macro_rules! links_sorted {
            ($x:expr) => (g.links($x).into_iter().sorted())
        }

        // a, b and c start with no links
        assert_eq!(links_sorted!(a), vec![]);
        assert_eq!(links_sorted!(b), vec![]);
        assert_eq!(links_sorted!(c), vec![]);

        g.link(a, b);
        // a - b linked bi-directionally
        assert_eq!(links_sorted!(a), vec![b]);
        assert_eq!(links_sorted!(b), vec![a]);

        g.link(b, c);
        // a - b still linked bi-directionally after linking b - c
        // b linked to a & c bi-directionally
        // c linked to b bi-directionally
        assert_eq!(links_sorted!(a), vec![b]);
        assert_eq!(links_sorted!(b), vec![a, c]);
        assert_eq!(links_sorted!(c), vec![b]);

        // add the same link - ensuring we can't add parallel links
        g.link(a, b);

        // a - b still linked bi-directionally after updating exist link
        assert_eq!(links_sorted!(a), vec![b]);
        assert_eq!(links_sorted!(b), vec![a, c]);

        // a - b unlinked
        // b still linked to c bi-directionally
        g.unlink(a, b);
        assert_eq!(links_sorted!(a), vec![]);
        assert_eq!(links_sorted!(b), vec![c]);
        assert_eq!(links_sorted!(c), vec![b]);

        // a, b and c start all unlinked again
        g.unlink(b, c);
        assert_eq!(links_sorted!(a), vec![]);
        assert_eq!(links_sorted!(b), vec![]);
        assert_eq!(links_sorted!(c), vec![]);

        // Deny cycle - self links
        g.link(a, a);
        assert_eq!(links_sorted!(a), vec![]);
    }
}
<commit_msg>Move some functions into the grid impl.<commit_after>use petgraph::{Graph, Undirected};
use rand;
use rand::distributions::{IndependentSample, Range};

pub type GridIndexType = u16;
pub type GridGraphNodeIndex = ::petgraph::graph::NodeIndex<GridIndexType>;

pub enum GridDirection {
    North,
    South,
    East,
    West,
}

struct AdjacentCells {
    north: Option<GridGraphNodeIndex>,
    south: Option<GridGraphNodeIndex>,
    east: Option<GridGraphNodeIndex>,
    west: Option<GridGraphNodeIndex>,
}
impl AdjacentCells {
    fn new() -> Self {
        AdjacentCells {
            north: None,
            south: None,
            east: None,
            west: None,
        }
    }
}

#[derive(Hash, Eq, PartialEq, Debug, Copy, Clone)]
struct GridCoordinate {
    pub x: isize,
    pub y: isize,
}

pub struct SquareGrid {
    /// For mapping a 2D gridcoordinate (converted to a 1D index) to a graph node index.
    grid_coordinate_to_node_index_lookup: Vec<GridGraphNodeIndex>,
    graph: Graph<AdjacentCells, (), Undirected, GridIndexType>,
    dimension_size: GridIndexType,
}

impl SquareGrid {
    pub fn new(dimension_size: GridIndexType) -> SquareGrid {

        let cells_count = dimension_size * dimension_size;
        let nodes_count_hint = cells_count as usize;
        let edges_count_hint = 4 * cells_count as usize - 4 * dimension_size as usize; // Probably overkill, but don't want any capacity panics

        let mut grid = SquareGrid {
            grid_coordinate_to_node_index_lookup: Vec::with_capacity(nodes_count_hint),
            graph: Graph::with_capacity(nodes_count_hint, edges_count_hint),
            dimension_size: dimension_size,
        };

        // Although it does seem to, there is no guarantee that the index values are monotonically increasing when calling graph.add_node
        // So we maintain our own symbol table mapping gridcoordinates converted to 1d (the implicit Vec indices) to the NodeIndexes created
        // by adding a node to the graph.
        for _ in 0..cells_count {
            let node_index = grid.graph.add_node(AdjacentCells::new());
            grid.grid_coordinate_to_node_index_lookup.push(node_index);
        }

        for (index, node_index) in grid.grid_coordinate_to_node_index_lookup.iter().enumerate() {

            let coord = grid.index_to_grid_coordinate(index);

            // Limit the lifetime of the find_neighbour_nodeindex closure so we don't get a grid
            // borrow conflict when mutating the adjacent_cells
            let (north_index, south_index, east_index, west_index) = {
                let find_neighbour_nodeindex = |dir: GridDirection| -> Option<GridGraphNodeIndex> {
                    let neighbour_coord = offset_coordinate(&coord, dir);
                    if grid.is_valid_coordinate(&neighbour_coord) {
                        let node_indices_index = grid.grid_coordinate_to_1d_index(&neighbour_coord);
                        let node_index =
                            grid.grid_coordinate_to_node_index_lookup[node_indices_index as usize];
                        Some(node_index)
                    } else {
                        None
                    }
                };
                (find_neighbour_nodeindex(GridDirection::North),
                 find_neighbour_nodeindex(GridDirection::South),
                 find_neighbour_nodeindex(GridDirection::East),
                 find_neighbour_nodeindex(GridDirection::West))
            };

            let adjacent_cells = grid.graph
                                     .node_weight_mut(node_index.clone())
                                     .unwrap();
            adjacent_cells.north = north_index;
            adjacent_cells.south = south_index;
            adjacent_cells.east = east_index;
            adjacent_cells.west = west_index;
        }

        grid
    }

    pub fn random_cell(&self) -> GridGraphNodeIndex {
        let random_pos = Range::new(0, self.grid_coordinate_to_node_index_lookup.len());
        let mut rng = rand::thread_rng();
        let index = random_pos.ind_sample(&mut rng);
        self.grid_coordinate_to_node_index_lookup[index]
    }

    /// Link two cells
    ///
    /// Todo - only allow links between adjacent cells? If `b` not in `g.neighbours(a)`.
    ///      - better to change the API to take an index and GridDirection
    ///
    /// Panics if a cell does not exist.
    pub fn link(&mut self, a: GridGraphNodeIndex, b: GridGraphNodeIndex) {
        if a != b {
            let _ = self.graph.update_edge(a, b, ());
        }
    }

    /// Unlink two cells, if a link exists between them.
    pub fn unlink(&mut self, a: GridGraphNodeIndex, b: GridGraphNodeIndex) {

        if let Some(edge_index) = self.graph.find_edge(a, b) {
            // This will invalidate the last edge index in the graph, which is fine as we
            // are not storing them for any reason.
            self.graph.remove_edge(edge_index);
        }
    }

    /// Cell nodes that are linked to a particular node by a passage.
    pub fn links(&self, node_index: GridGraphNodeIndex) -> Vec<GridGraphNodeIndex> {
        self.graph
            .edges(node_index)
            .map(|index_edge_data_pair| index_edge_data_pair.0.clone())
            .collect()
    }

    /// Cell nodes that are to the North, South, East or West of a particular node, but not
    /// necessarily linked by a passage.
    pub fn neighbours(&self, node_index: GridGraphNodeIndex) -> Vec<GridGraphNodeIndex> {

        if let Some(adj) = self.graph.node_weight(node_index) {
            vec![adj.north, adj.south, adj.east, adj.west]
                .iter()
                .filter_map(|&maybe_adj| maybe_adj.clone())
                .collect()
        } else {
            vec![]
        }
    }

    fn is_neighbour(&self, a: GridGraphNodeIndex, b: GridGraphNodeIndex) -> bool {
        macro_rules! index_node_match {
            ($opt_grid_index:expr) => (if let Some(node_index) = $opt_grid_index {
                                           if node_index == b {
                                               return true;
                                           }
                                       })
        }
        if let Some(adjacents_of_a) = self.graph.node_weight(a) {
            index_node_match!(adjacents_of_a.north);
            index_node_match!(adjacents_of_a.south);
            index_node_match!(adjacents_of_a.east);
            index_node_match!(adjacents_of_a.west);
        }
        false
    }

    fn is_valid_coordinate(&self, coord: &GridCoordinate) -> bool {
        let (x, y) = (coord.x, coord.y);
        let dim_size = self.dimension_size as isize;
        if x < 0 || y < 0 || x >= dim_size || y >= dim_size {
            return false;
        }
        true
    }

    fn grid_coordinate_to_1d_index(&self, coord: &GridCoordinate) -> GridIndexType {
        ((coord.y * self.dimension_size as isize) + coord.x) as GridIndexType
    }

    fn index_to_grid_coordinate(&self, one_dimensional_index: usize) -> GridCoordinate {
        let dim_size = self.dimension_size as usize;
        let y = one_dimensional_index / dim_size;
        let x = one_dimensional_index - (y * dim_size);
        GridCoordinate {
            x: x as isize,
            y: y as isize,
        }
    }
}

fn offset_coordinate(coord: &GridCoordinate, dir: GridDirection) -> GridCoordinate {
    let (x, y) = (coord.x, coord.y);
    match dir {
        GridDirection::North => GridCoordinate { x: x, y: y - 1 },
        GridDirection::South => GridCoordinate { x: x, y: y + 1 },
        GridDirection::East => GridCoordinate { x: x + 1, y: y },
        GridDirection::West => GridCoordinate { x: x - 1, y: y },
    }
}

#[cfg(test)]
mod test {

    use super::*;
    use itertools::Itertools; // a trait

    #[test]
    fn neighbour_cells() {
        let g = SquareGrid::new(10);

        let check_expected_neighbours = |node_index, vec_expected_neighbour_indices: Vec<usize>| {
            let node_indices = g.neighbours(GridGraphNodeIndex::new(node_index))
                                .into_iter()
                                .sorted();
            let expected_indices =
                vec_expected_neighbour_indices.into_iter()
                                              .sorted()
                                              .into_iter()
                                              .map(|index: usize| GridGraphNodeIndex::new(index))
                                              .collect::<Vec<GridGraphNodeIndex>>();
            assert_eq!(node_indices, expected_indices);
        };

        // corners
        check_expected_neighbours(0, vec![1, 10]);
        check_expected_neighbours(9, vec![8, 19]);
        check_expected_neighbours(90, vec![80, 91]);
        check_expected_neighbours(99, vec![89, 98]);

        // side element examples
        check_expected_neighbours(10, vec![0, 11, 20]);
        check_expected_neighbours(1, vec![0, 2, 11]);
        check_expected_neighbours(80, vec![70, 81, 90]);
        check_expected_neighbours(89, vec![79, 88, 99]);
        check_expected_neighbours(19, vec![9, 18, 29]);
        check_expected_neighbours(8, vec![7, 9, 18]);

        // Some place with 4 neighbours inside the grid
        check_expected_neighbours(12, vec![2, 11, 13, 22]);
    }

    #[test]
    fn random_cell() {
        let g = SquareGrid::new(4);
        let cells_count = 4 * 4;
        for _ in 0..1000 {
            let grid_index = g.random_cell();
            assert!(grid_index.index() >= 0 && grid_index.index() < cells_count);
        }
    }

    #[test]
    fn linking_cells() {
        let mut g = SquareGrid::new(4);
        let a = GridGraphNodeIndex::new(0);
        let b = GridGraphNodeIndex::new(1);
        let c = GridGraphNodeIndex::new(2);

        // I'd rather use a closure, but it needs to borrow the graph immutably until
        // it goes out of scope
        // Passing the graph in allows me to use a plain function:
        // let links_sorted = |n: GridGraphNodeIndex, g: &SquareGrid| -> Vec<GridGraphNodeIndex> {
        //     g.links(n).into_iter().sorted()
        // };
        // but it's uglier in that I need to explicitly pass in the SquareGrid ref all the time
        macro_rules! links_sorted {
            ($x:expr) => (g.links($x).into_iter().sorted())
        }

        // a, b and c start with no links
        assert_eq!(links_sorted!(a), vec![]);
        assert_eq!(links_sorted!(b), vec![]);
        assert_eq!(links_sorted!(c), vec![]);

        g.link(a, b);
        // a - b linked bi-directionally
        assert_eq!(links_sorted!(a), vec![b]);
        assert_eq!(links_sorted!(b), vec![a]);

        g.link(b, c);
        // a - b still linked bi-directionally after linking b - c
        // b linked to a & c bi-directionally
        // c linked to b bi-directionally
        assert_eq!(links_sorted!(a), vec![b]);
        assert_eq!(links_sorted!(b), vec![a, c]);
        assert_eq!(links_sorted!(c), vec![b]);

        // add the same link - ensuring we can't add parallel links
        g.link(a, b);

        // a - b still linked bi-directionally after updating exist link
        assert_eq!(links_sorted!(a), vec![b]);
        assert_eq!(links_sorted!(b), vec![a, c]);

        // a - b unlinked
        // b still linked to c bi-directionally
        g.unlink(a, b);
        assert_eq!(links_sorted!(a), vec![]);
        assert_eq!(links_sorted!(b), vec![c]);
        assert_eq!(links_sorted!(c), vec![b]);

        // a, b and c start all unlinked again
        g.unlink(b, c);
        assert_eq!(links_sorted!(a), vec![]);
        assert_eq!(links_sorted!(b), vec![]);
        assert_eq!(links_sorted!(c), vec![]);

        // Deny cycle - self links
        g.link(a, a);
        assert_eq!(links_sorted!(a), vec![]);
    }
}
<|endoftext|>


<commit_before>#![cfg(target_os = "linux")]

use std::{mem, ptr};
use libc::{c_int, sockaddr, socklen_t};
use fcntl::Fd;
use errno::{SysResult, SysError, from_ffi};

pub use libc::{in_addr, sockaddr_in, sockaddr_in6, sockaddr_un, sa_family_t};

mod ffi {
    use libc::{c_int, sockaddr, socklen_t};
    pub use libc::{socket, listen, bind, accept, connect};

    extern {
        pub fn accept4(
            sockfd: c_int,
            addr: *mut sockaddr,
            addrlen: *mut socklen_t,
            flags: c_int) -> c_int;
    }
}

pub type AddressFamily = c_int;

pub static AF_UNIX: AddressFamily  = 1;
pub static AF_LOCAL: AddressFamily = AF_UNIX;
pub static AF_INET: AddressFamily  = 2;
pub static AF_INET6: AddressFamily = 10;

pub type SockType = c_int;

pub static SOCK_STREAM: SockType = 1;
pub static SOCK_DGRAM: SockType = 1;
pub static SOCK_SEQPACKET: SockType = 1;
pub static SOCK_RAW: SockType = 1;
pub static SOCK_RDM: SockType = 1;

// Extra flags - Linux 2.6.27
bitflags!(
    flags SockFlag: c_int {
        static SOCK_NONBLOCK = 0o0004000,
        static SOCK_CLOEXEC  = 0o2000000
    }
)

pub fn socket(domain: AddressFamily, ty: SockType, flags: SockFlag) -> SysResult<Fd> {
    // TODO: Check the kernel version
    let res = unsafe { ffi::socket(domain, ty | flags.bits(), 0) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}

pub fn listen(sockfd: Fd, backlog: uint) -> SysResult<()> {
    let res = unsafe { ffi::listen(sockfd, backlog as c_int) };
    from_ffi(res)
}

pub enum SockAddr {
    SockIpV4(sockaddr_in),
    SockIpV6(sockaddr_in6),
    SockUnix(sockaddr_un)
}

pub fn bind(sockfd: Fd, addr: &SockAddr) -> SysResult<()> {
    let res = unsafe {
        match *addr {
            SockIpV4(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in>() as socklen_t),
            SockIpV6(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in6>() as socklen_t),
            SockUnix(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_un>() as socklen_t)
        }
    };

    from_ffi(res)
}

pub fn accept(sockfd: Fd) -> SysResult<Fd> {
    let res = unsafe { ffi::accept(sockfd, ptr::mut_null(), ptr::mut_null()) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}

pub fn accept4(sockfd: Fd, flags: SockFlag) -> SysResult<Fd> {
    // TODO: Check the kernel version
    let res = unsafe { ffi::accept4(sockfd, ptr::mut_null(), ptr::mut_null(), flags.bits) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}

pub fn connect(sockfd: Fd, addr: &SockAddr) -> SysResult<()> {
    let res = unsafe {
        match *addr {
            SockIpV4(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in>() as socklen_t),
            SockIpV6(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in6>() as socklen_t),
            SockUnix(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_un>() as socklen_t)
        }
    };

    from_ffi(res)
}

pub type SockOpt = c_int;

pub static SO_ACCEPTCONN: SockOpt = 30;
pub static SO_BINDTODEVICE: SockOpt = 25;
pub static SO_BROADCAST: SockOpt = 6;
pub static SO_BSDCOMPAT: SockOpt = 14;
pub static SO_DEBUG: SockOpt = 1;
pub static SO_DOMAIN: SockOpt = 39;
pub static SO_ERROR: SockOpt = 4;
pub static SO_DONTROUTE: SockOpt = 5;
pub static SO_KEEPALIVE: SockOpt = 9;
pub static SO_LINGER: SockOpt = 13;
pub static SO_MARK: SockOpt = 36;
pub static SO_OOBINLINE: SockOpt = 10;
pub static SO_PASSCRED: SockOpt = 16;
pub static SO_PEEK_OFF: SockOpt = 42;
pub static SO_PEERCRED: SockOpt = 17;
pub static SO_PRIORITY: SockOpt = 12;
pub static SO_PROTOCOL: SockOpt = 38;
pub static SO_RCVBUF: SockOpt = 8;
pub static SO_RCVBUFFORCE: SockOpt = 33;
pub static SO_RCVLOWAT: SockOpt = 18;
pub static SO_SNDLOWAT: SockOpt = 19;
pub static SO_RCVTIMEO: SockOpt = 20;
pub static SO_SNDTIMEO: SockOpt = 21;
pub static SO_REUSEADDR: SockOpt = 2;
pub static SO_RXQ_OVFL: SockOpt = 40;
pub static SO_SNDBUF: SockOpt = 7;
pub static SO_SNDBUFFORCE: SockOpt = 32;
pub static SO_TIMESTAMP: SockOpt = 29;
pub static SO_TYPE: SockOpt = 3;
pub static SO_BUSY_POLL: SockOpt = 46;
<commit_msg>getsockopt and setsockopt<commit_after>#![cfg(target_os = "linux")]

use std::{mem, ptr};
use libc::{c_int, c_void, sockaddr, socklen_t};
use fcntl::Fd;
use errno::{SysResult, SysError, from_ffi};

pub use libc::{in_addr, sockaddr_in, sockaddr_in6, sockaddr_un, sa_family_t};

mod ffi {
    use libc::{c_int, c_void, sockaddr, socklen_t};
    pub use libc::{socket, listen, bind, accept, connect, setsockopt};

    extern {
        pub fn accept4(
            sockfd: c_int,
            addr: *mut sockaddr,
            addrlen: *mut socklen_t,
            flags: c_int) -> c_int;

        pub fn getsockopt(
            sockfd: c_int,
            level: c_int,
            optname: c_int,
            optval: *mut c_void,
            optlen: *mut socklen_t) -> c_int;
    }
}

pub type AddressFamily = c_int;

pub static AF_UNIX: AddressFamily  = 1;
pub static AF_LOCAL: AddressFamily = AF_UNIX;
pub static AF_INET: AddressFamily  = 2;
pub static AF_INET6: AddressFamily = 10;

pub type SockType = c_int;

pub static SOCK_STREAM: SockType = 1;
pub static SOCK_DGRAM: SockType = 1;
pub static SOCK_SEQPACKET: SockType = 1;
pub static SOCK_RAW: SockType = 1;
pub static SOCK_RDM: SockType = 1;

// Extra flags - Linux 2.6.27
bitflags!(
    flags SockFlag: c_int {
        static SOCK_NONBLOCK = 0o0004000,
        static SOCK_CLOEXEC  = 0o2000000
    }
)

pub fn socket(domain: AddressFamily, ty: SockType, flags: SockFlag) -> SysResult<Fd> {
    // TODO: Check the kernel version
    let res = unsafe { ffi::socket(domain, ty | flags.bits(), 0) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}

pub fn listen(sockfd: Fd, backlog: uint) -> SysResult<()> {
    let res = unsafe { ffi::listen(sockfd, backlog as c_int) };
    from_ffi(res)
}

pub enum SockAddr {
    SockIpV4(sockaddr_in),
    SockIpV6(sockaddr_in6),
    SockUnix(sockaddr_un)
}

pub fn bind(sockfd: Fd, addr: &SockAddr) -> SysResult<()> {
    let res = unsafe {
        match *addr {
            SockIpV4(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in>() as socklen_t),
            SockIpV6(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in6>() as socklen_t),
            SockUnix(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_un>() as socklen_t)
        }
    };

    from_ffi(res)
}

pub fn accept(sockfd: Fd) -> SysResult<Fd> {
    let res = unsafe { ffi::accept(sockfd, ptr::mut_null(), ptr::mut_null()) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}

pub fn accept4(sockfd: Fd, flags: SockFlag) -> SysResult<Fd> {
    // TODO: Check the kernel version
    let res = unsafe { ffi::accept4(sockfd, ptr::mut_null(), ptr::mut_null(), flags.bits) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}

pub fn connect(sockfd: Fd, addr: &SockAddr) -> SysResult<()> {
    let res = unsafe {
        match *addr {
            SockIpV4(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in>() as socklen_t),
            SockIpV6(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in6>() as socklen_t),
            SockUnix(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_un>() as socklen_t)
        }
    };

    from_ffi(res)
}

pub type SockLevel = c_int;

pub static SOL_IP: SockLevel     = 0;
pub static SOL_SOCKET: SockLevel = 1;
pub static SOL_TCP: SockLevel    = 6;
pub static SOL_UDP: SockLevel    = 17;
pub static SOL_IPV6: SockLevel   = 41;

pub type SockOpt = c_int;

pub static SO_ACCEPTCONN: SockOpt = 30;
pub static SO_BINDTODEVICE: SockOpt = 25;
pub static SO_BROADCAST: SockOpt = 6;
pub static SO_BSDCOMPAT: SockOpt = 14;
pub static SO_DEBUG: SockOpt = 1;
pub static SO_DOMAIN: SockOpt = 39;
pub static SO_ERROR: SockOpt = 4;
pub static SO_DONTROUTE: SockOpt = 5;
pub static SO_KEEPALIVE: SockOpt = 9;
pub static SO_LINGER: SockOpt = 13;
pub static SO_MARK: SockOpt = 36;
pub static SO_OOBINLINE: SockOpt = 10;
pub static SO_PASSCRED: SockOpt = 16;
pub static SO_PEEK_OFF: SockOpt = 42;
pub static SO_PEERCRED: SockOpt = 17;
pub static SO_PRIORITY: SockOpt = 12;
pub static SO_PROTOCOL: SockOpt = 38;
pub static SO_RCVBUF: SockOpt = 8;
pub static SO_RCVBUFFORCE: SockOpt = 33;
pub static SO_RCVLOWAT: SockOpt = 18;
pub static SO_SNDLOWAT: SockOpt = 19;
pub static SO_RCVTIMEO: SockOpt = 20;
pub static SO_SNDTIMEO: SockOpt = 21;
pub static SO_REUSEADDR: SockOpt = 2;
pub static SO_RXQ_OVFL: SockOpt = 40;
pub static SO_SNDBUF: SockOpt = 7;
pub static SO_SNDBUFFORCE: SockOpt = 32;
pub static SO_TIMESTAMP: SockOpt = 29;
pub static SO_TYPE: SockOpt = 3;
pub static SO_BUSY_POLL: SockOpt = 46;

pub fn getsockopt<T>(fd: Fd, level: SockLevel, opt: SockOpt, val: &mut T) -> SysResult<uint> {
    let mut len = mem::size_of::<T>() as socklen_t;

    let res = unsafe {
        ffi::getsockopt(
            fd, level, opt,
            mem::transmute(val),
            &mut len as *mut socklen_t)
    };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(len as uint)
}

pub fn setsockopt<T>(fd: Fd, level: SockLevel, opt: SockOpt, val: &T) -> SysResult<()> {
    let len = mem::size_of::<T>() as socklen_t;

    let res = unsafe {
            ffi::setsockopt(
            fd, level, opt,
            mem::transmute(val),
            len)
    };

    from_ffi(res)
}
<|endoftext|>


<commit_before>use std::{collections::BTreeMap, convert::TryInto, fmt, panic};

use quickcheck::{Arbitrary, Gen, RngCore};
use rand::{rngs::StdRng, Rng, SeedableRng};
use rand_distr::{Distribution, Gamma};

use pagecache::MAX_SPACE_AMPLIFICATION;
use crate::*;

#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct Key(pub Vec<u8>);

impl fmt::Debug for Key {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Key(vec!{:?})", self.0)
    }
}

struct SledGen {
    r: StdRng,
    size: usize,
}

impl Gen for SledGen {
    fn size(&self) -> usize {
        self.size
    }
}

impl RngCore for SledGen {
    fn next_u32(&mut self) -> u32 {
        self.r.gen::<u32>()
    }

    fn next_u64(&mut self) -> u64 {
        self.r.gen::<u64>()
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        self.r.fill_bytes(dest)
    }

    fn try_fill_bytes(
        &mut self,
        dest: &mut [u8],
    ) -> std::result::Result<(), rand::Error> {
        self.r.try_fill_bytes(dest)
    }
}

pub fn fuzz_then_shrink(buf: &[u8]) {
    let use_compression = buf.get(0).unwrap_or(&0) % 2 == 0;

    let ops: Vec<Op> = buf
        .chunks(2)
        .map(|chunk| {
            let mut seed = [0_u8; 32];
            seed[0..chunk.len()].copy_from_slice(chunk);
            let rng: StdRng = SeedableRng::from_seed(seed);
            let mut sled_rng = SledGen { r: rng, size: 2 };

            Op::arbitrary(&mut sled_rng)
        })
        .collect();

    match panic::catch_unwind(move || {
        prop_tree_matches_btreemap(ops, 100, false, use_compression)
    }) {
        Ok(_) => {}
        Err(_e) => panic!("TODO"),
    }
}

impl Arbitrary for Key {
    #![allow(clippy::cast_possible_truncation)]
    #![allow(clippy::cast_precision_loss)]
    #![allow(clippy::cast_sign_loss)]

    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        if g.gen::<bool>() {
            let gs = g.size();
            let gamma = Gamma::new(0.3, gs as f64).unwrap();
            let v = gamma.sample(&mut rand::thread_rng());
            let len = if v > 30000.0 {
                10000
            } else {
                (v % 100.) as usize
            };

            let space = g.gen_range(0, gs) + 1;

            let inner = (0..len).map(|_| g.gen_range(0, space) as u8).collect();

            Self(inner)
        } else {
            let len = g.gen_range(0, 2);
            let mut inner = vec![];

            for _ in 0..len {
                inner.push(g.gen::<u8>());
            }

            Self(inner)
        }
    }

    fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
        // we only want to shrink on length, not byte values
        Box::new(
            self.0
                .len()
                .shrink()
                .zip(std::iter::repeat(self.0.clone()))
                .map(|(len, underlying)| Self(underlying[..len].to_vec())),
        )
    }
}

#[derive(Debug, Clone)]
pub enum Op {
    Set(Key, u8),
    Merge(Key, u8),
    Get(Key),
    GetLt(Key),
    GetGt(Key),
    Del(Key),
    Cas(Key, u8, u8),
    Scan(Key, isize),
    Restart,
}

use self::Op::{Cas, Del, Get, GetGt, GetLt, Merge, Restart, Scan, Set};

impl Arbitrary for Op {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        if g.gen_bool(1. / 10.) {
            return Restart;
        }

        let choice = g.gen_range(0, 8);

        match choice {
            0 => Set(Key::arbitrary(g), g.gen::<u8>()),
            1 => Merge(Key::arbitrary(g), g.gen::<u8>()),
            2 => Get(Key::arbitrary(g)),
            3 => GetLt(Key::arbitrary(g)),
            4 => GetGt(Key::arbitrary(g)),
            5 => Del(Key::arbitrary(g)),
            6 => Cas(Key::arbitrary(g), g.gen::<u8>(), g.gen::<u8>()),
            7 => Scan(Key::arbitrary(g), g.gen_range(-40, 40)),
            _ => panic!("impossible choice"),
        }
    }

    fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
        match *self {
            Set(ref k, v) => Box::new(k.shrink().map(move |sk| Set(sk, v))),
            Merge(ref k, v) => Box::new(k.shrink().map(move |k| Merge(k, v))),
            Get(ref k) => Box::new(k.shrink().map(Get)),
            GetLt(ref k) => Box::new(k.shrink().map(GetLt)),
            GetGt(ref k) => Box::new(k.shrink().map(GetGt)),
            Cas(ref k, old, new) => {
                Box::new(k.shrink().map(move |k| Cas(k, old, new)))
            }
            Scan(ref k, len) => Box::new(k.shrink().map(move |k| Scan(k, len))),
            Del(ref k) => Box::new(k.shrink().map(Del)),
            Restart => Box::new(vec![].into_iter()),
        }
    }
}

fn bytes_to_u16(v: &[u8]) -> u16 {
    assert_eq!(v.len(), 2);
    (u16::from(v[0]) << 8) + u16::from(v[1])
}

fn u16_to_bytes(u: u16) -> Vec<u8> {
    u.to_be_bytes().to_vec()
}

// just adds up values as if they were u16's
fn test_merge_operator(
    _k: &[u8],
    old: Option<&[u8]>,
    to_merge: &[u8],
) -> Option<Vec<u8>> {
    let base = old.unwrap_or(&[0, 0]);
    let base_n = bytes_to_u16(base);
    let new_n = base_n + u16::from(to_merge[0]);
    let ret = u16_to_bytes(new_n);
    Some(ret)
}

pub fn prop_tree_matches_btreemap(
    ops: Vec<Op>,
    snapshot_after: u8,
    flusher: bool,
    use_compression: bool,
) -> bool {
    use self::*;

    super::setup_logger();

    let config = ConfigBuilder::new()
        .temporary(true)
        .use_compression(use_compression)
        .snapshot_after_ops(u64::from(snapshot_after) + 1)
        .flush_every_ms(if flusher { Some(1) } else { None })
        .io_buf_size(10000)
        .cache_capacity(256)
        .idgen_persist_interval(1)
        .build();

    let mut tree = Db::start(config.clone()).unwrap();
    tree.set_merge_operator(test_merge_operator);

    let mut reference: BTreeMap<Key, u16> = BTreeMap::new();

    for op in ops {
        match op {
            Set(k, v) => {
                let old_actual = tree.insert(&k.0, vec![0, v]).unwrap();
                let old_reference = reference.insert(k.clone(), u16::from(v));
                assert_eq!(
                    old_actual.map(|v| bytes_to_u16(&*v)),
                    old_reference
                );
            }
            Merge(k, v) => {
                tree.merge(&k.0, vec![v]).unwrap();
                let entry = reference.entry(k).or_insert(0_u16);
                *entry += u16::from(v);
            }
            Get(k) => {
                let res1 = tree.get(&*k.0).unwrap().map(|v| bytes_to_u16(&*v));
                let res2 = reference.get(&k).cloned();
                assert_eq!(res1, res2);
            }
            GetLt(k) => {
                let res1 = tree.get_lt(&*k.0).unwrap().map(|v| v.0);
                let res2 = reference
                    .iter()
                    .rev()
                    .filter(|(key, _)| **key < k)
                    .nth(0)
                    .map(|(k, _v)| IVec::from(&*k.0));
                assert_eq!(
                    res1, res2,
                    "get_lt({:?}) should have returned {:?} \
                     but it returned {:?} instead. \
                     \n Db: {:?}",
                    k, res2, res1, tree
                );
            }
            GetGt(k) => {
                let res1 = tree.get_gt(&*k.0).unwrap().map(|v| v.0);
                let res2 = reference
                    .iter()
                    .filter(|(key, _)| **key > k)
                    .nth(0)
                    .map(|(k, _v)| IVec::from(&*k.0));
                assert_eq!(
                    res1, res2,
                    "get_gt({:?}) expected {:?} in tree {:?}",
                    k, res2, tree
                );
            }
            Del(k) => {
                tree.remove(&*k.0).unwrap();
                reference.remove(&k);
            }
            Cas(k, old, new) => {
                let tree_old = tree.get(&*k.0).unwrap();
                if let Some(old_tree) = tree_old {
                    if old_tree == *vec![0, old] {
                        tree.insert(&k.0, vec![0, new]).unwrap();
                    }
                }

                let ref_old = reference.get(&k).cloned();
                if ref_old == Some(u16::from(old)) {
                    reference.insert(k, u16::from(new));
                }
            }
            Scan(k, len) => {
                if len > 0 {
                    let mut tree_iter = tree
                        .range(&*k.0..)
                        .take(len.abs().try_into().unwrap())
                        .map(Result::unwrap);
                    let ref_iter = reference
                        .iter()
                        .filter(|&(ref rk, _rv)| **rk >= k)
                        .take(len.abs().try_into().unwrap())
                        .map(|(ref rk, ref rv)| (rk.0.clone(), **rv));

                    for r in ref_iter {
                        let tree_next = tree_iter.next().unwrap();
                        let lhs = (tree_next.0, &*tree_next.1);
                        let rhs = (r.0.clone(), &*u16_to_bytes(r.1));
                        assert_eq!(
                            (lhs.0.as_ref(), lhs.1),
                            (rhs.0.as_ref(), rhs.1),
                            "expected {:?} while iterating from {:?} on tree: {:?}",
                            rhs,
                            k,
                            tree
                        );
                    }
                } else {
                    let mut tree_iter = tree
                        .range(&*k.0..)
                        .rev()
                        .take(len.abs().try_into().unwrap())
                        .map(Result::unwrap);
                    let ref_iter = reference
                        .iter()
                        .rev()
                        .filter(|&(ref rk, _rv)| **rk >= k)
                        .take(len.abs().try_into().unwrap())
                        .map(|(ref rk, ref rv)| (rk.0.clone(), **rv));

                    for r in ref_iter {
                        let tree_next = tree_iter.next().unwrap();
                        let lhs = (tree_next.0, &*tree_next.1);
                        let rhs = (r.0.clone(), &*u16_to_bytes(r.1));
                        assert_eq!(
                            (lhs.0.as_ref(), lhs.1),
                            (rhs.0.as_ref(), rhs.1),
                            "expected {:?} while reverse iterating from {:?} on tree: {:?}",
                            rhs,
                            k,
                            tree
                        );
                    }
                }
            }
            Restart => {
                drop(tree);
                tree = Db::start(config.clone()).unwrap();
                tree.set_merge_operator(test_merge_operator);
            }
        }
    }

    let space_amplification = tree
        .space_amplification()
        .expect("should be able to read files and pages");

    assert!(
        space_amplification < MAX_SPACE_AMPLIFICATION,
        "space amplification was measured to be {}, \
         which is higher than the maximum of {}",
        space_amplification,
        MAX_SPACE_AMPLIFICATION
    );

    true
}

#[test]
fn test_fuzz_test() {
    let seed = [0; 32];
    fuzz_then_shrink(&seed);
    let seed = [0; 31];
    fuzz_then_shrink(&seed);
    let seed = [0; 33];
    fuzz_then_shrink(&seed);
    fuzz_then_shrink(&[]);
}
<commit_msg>only use compression when the feature is enabled<commit_after>use std::{collections::BTreeMap, convert::TryInto, fmt, panic};

use quickcheck::{Arbitrary, Gen, RngCore};
use rand::{rngs::StdRng, Rng, SeedableRng};
use rand_distr::{Distribution, Gamma};

use pagecache::MAX_SPACE_AMPLIFICATION;
use crate::*;

#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct Key(pub Vec<u8>);

impl fmt::Debug for Key {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Key(vec!{:?})", self.0)
    }
}

struct SledGen {
    r: StdRng,
    size: usize,
}

impl Gen for SledGen {
    fn size(&self) -> usize {
        self.size
    }
}

impl RngCore for SledGen {
    fn next_u32(&mut self) -> u32 {
        self.r.gen::<u32>()
    }

    fn next_u64(&mut self) -> u64 {
        self.r.gen::<u64>()
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        self.r.fill_bytes(dest)
    }

    fn try_fill_bytes(
        &mut self,
        dest: &mut [u8],
    ) -> std::result::Result<(), rand::Error> {
        self.r.try_fill_bytes(dest)
    }
}

pub fn fuzz_then_shrink(buf: &[u8]) {
    let use_compression = cfg!(feature = "compression") &&
        buf.get(0).unwrap_or(&0) % 2 == 0;

    let ops: Vec<Op> = buf
        .chunks(2)
        .map(|chunk| {
            let mut seed = [0_u8; 32];
            seed[0..chunk.len()].copy_from_slice(chunk);
            let rng: StdRng = SeedableRng::from_seed(seed);
            let mut sled_rng = SledGen { r: rng, size: 2 };

            Op::arbitrary(&mut sled_rng)
        })
        .collect();

    match panic::catch_unwind(move || {
        prop_tree_matches_btreemap(ops, 100, false, use_compression)
    }) {
        Ok(_) => {}
        Err(_e) => panic!("TODO"),
    }
}

impl Arbitrary for Key {
    #![allow(clippy::cast_possible_truncation)]
    #![allow(clippy::cast_precision_loss)]
    #![allow(clippy::cast_sign_loss)]

    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        if g.gen::<bool>() {
            let gs = g.size();
            let gamma = Gamma::new(0.3, gs as f64).unwrap();
            let v = gamma.sample(&mut rand::thread_rng());
            let len = if v > 30000.0 {
                10000
            } else {
                (v % 100.) as usize
            };

            let space = g.gen_range(0, gs) + 1;

            let inner = (0..len).map(|_| g.gen_range(0, space) as u8).collect();

            Self(inner)
        } else {
            let len = g.gen_range(0, 2);
            let mut inner = vec![];

            for _ in 0..len {
                inner.push(g.gen::<u8>());
            }

            Self(inner)
        }
    }

    fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
        // we only want to shrink on length, not byte values
        Box::new(
            self.0
                .len()
                .shrink()
                .zip(std::iter::repeat(self.0.clone()))
                .map(|(len, underlying)| Self(underlying[..len].to_vec())),
        )
    }
}

#[derive(Debug, Clone)]
pub enum Op {
    Set(Key, u8),
    Merge(Key, u8),
    Get(Key),
    GetLt(Key),
    GetGt(Key),
    Del(Key),
    Cas(Key, u8, u8),
    Scan(Key, isize),
    Restart,
}

use self::Op::{Cas, Del, Get, GetGt, GetLt, Merge, Restart, Scan, Set};

impl Arbitrary for Op {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        if g.gen_bool(1. / 10.) {
            return Restart;
        }

        let choice = g.gen_range(0, 8);

        match choice {
            0 => Set(Key::arbitrary(g), g.gen::<u8>()),
            1 => Merge(Key::arbitrary(g), g.gen::<u8>()),
            2 => Get(Key::arbitrary(g)),
            3 => GetLt(Key::arbitrary(g)),
            4 => GetGt(Key::arbitrary(g)),
            5 => Del(Key::arbitrary(g)),
            6 => Cas(Key::arbitrary(g), g.gen::<u8>(), g.gen::<u8>()),
            7 => Scan(Key::arbitrary(g), g.gen_range(-40, 40)),
            _ => panic!("impossible choice"),
        }
    }

    fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
        match *self {
            Set(ref k, v) => Box::new(k.shrink().map(move |sk| Set(sk, v))),
            Merge(ref k, v) => Box::new(k.shrink().map(move |k| Merge(k, v))),
            Get(ref k) => Box::new(k.shrink().map(Get)),
            GetLt(ref k) => Box::new(k.shrink().map(GetLt)),
            GetGt(ref k) => Box::new(k.shrink().map(GetGt)),
            Cas(ref k, old, new) => {
                Box::new(k.shrink().map(move |k| Cas(k, old, new)))
            }
            Scan(ref k, len) => Box::new(k.shrink().map(move |k| Scan(k, len))),
            Del(ref k) => Box::new(k.shrink().map(Del)),
            Restart => Box::new(vec![].into_iter()),
        }
    }
}

fn bytes_to_u16(v: &[u8]) -> u16 {
    assert_eq!(v.len(), 2);
    (u16::from(v[0]) << 8) + u16::from(v[1])
}

fn u16_to_bytes(u: u16) -> Vec<u8> {
    u.to_be_bytes().to_vec()
}

// just adds up values as if they were u16's
fn test_merge_operator(
    _k: &[u8],
    old: Option<&[u8]>,
    to_merge: &[u8],
) -> Option<Vec<u8>> {
    let base = old.unwrap_or(&[0, 0]);
    let base_n = bytes_to_u16(base);
    let new_n = base_n + u16::from(to_merge[0]);
    let ret = u16_to_bytes(new_n);
    Some(ret)
}

pub fn prop_tree_matches_btreemap(
    ops: Vec<Op>,
    snapshot_after: u8,
    flusher: bool,
    use_compression: bool,
) -> bool {
    use self::*;

    super::setup_logger();

    let use_compression = cfg!(feature = "compression") &&
        use_compression;

    let config = ConfigBuilder::new()
        .temporary(true)
        .use_compression(use_compression)
        .snapshot_after_ops(u64::from(snapshot_after) + 1)
        .flush_every_ms(if flusher { Some(1) } else { None })
        .io_buf_size(10000)
        .cache_capacity(256)
        .idgen_persist_interval(1)
        .build();

    let mut tree = Db::start(config.clone()).unwrap();
    tree.set_merge_operator(test_merge_operator);

    let mut reference: BTreeMap<Key, u16> = BTreeMap::new();

    for op in ops {
        match op {
            Set(k, v) => {
                let old_actual = tree.insert(&k.0, vec![0, v]).unwrap();
                let old_reference = reference.insert(k.clone(), u16::from(v));
                assert_eq!(
                    old_actual.map(|v| bytes_to_u16(&*v)),
                    old_reference
                );
            }
            Merge(k, v) => {
                tree.merge(&k.0, vec![v]).unwrap();
                let entry = reference.entry(k).or_insert(0_u16);
                *entry += u16::from(v);
            }
            Get(k) => {
                let res1 = tree.get(&*k.0).unwrap().map(|v| bytes_to_u16(&*v));
                let res2 = reference.get(&k).cloned();
                assert_eq!(res1, res2);
            }
            GetLt(k) => {
                let res1 = tree.get_lt(&*k.0).unwrap().map(|v| v.0);
                let res2 = reference
                    .iter()
                    .rev()
                    .filter(|(key, _)| **key < k)
                    .nth(0)
                    .map(|(k, _v)| IVec::from(&*k.0));
                assert_eq!(
                    res1, res2,
                    "get_lt({:?}) should have returned {:?} \
                     but it returned {:?} instead. \
                     \n Db: {:?}",
                    k, res2, res1, tree
                );
            }
            GetGt(k) => {
                let res1 = tree.get_gt(&*k.0).unwrap().map(|v| v.0);
                let res2 = reference
                    .iter()
                    .filter(|(key, _)| **key > k)
                    .nth(0)
                    .map(|(k, _v)| IVec::from(&*k.0));
                assert_eq!(
                    res1, res2,
                    "get_gt({:?}) expected {:?} in tree {:?}",
                    k, res2, tree
                );
            }
            Del(k) => {
                tree.remove(&*k.0).unwrap();
                reference.remove(&k);
            }
            Cas(k, old, new) => {
                let tree_old = tree.get(&*k.0).unwrap();
                if let Some(old_tree) = tree_old {
                    if old_tree == *vec![0, old] {
                        tree.insert(&k.0, vec![0, new]).unwrap();
                    }
                }

                let ref_old = reference.get(&k).cloned();
                if ref_old == Some(u16::from(old)) {
                    reference.insert(k, u16::from(new));
                }
            }
            Scan(k, len) => {
                if len > 0 {
                    let mut tree_iter = tree
                        .range(&*k.0..)
                        .take(len.abs().try_into().unwrap())
                        .map(Result::unwrap);
                    let ref_iter = reference
                        .iter()
                        .filter(|&(ref rk, _rv)| **rk >= k)
                        .take(len.abs().try_into().unwrap())
                        .map(|(ref rk, ref rv)| (rk.0.clone(), **rv));

                    for r in ref_iter {
                        let tree_next = tree_iter.next().unwrap();
                        let lhs = (tree_next.0, &*tree_next.1);
                        let rhs = (r.0.clone(), &*u16_to_bytes(r.1));
                        assert_eq!(
                            (lhs.0.as_ref(), lhs.1),
                            (rhs.0.as_ref(), rhs.1),
                            "expected {:?} while iterating from {:?} on tree: {:?}",
                            rhs,
                            k,
                            tree
                        );
                    }
                } else {
                    let mut tree_iter = tree
                        .range(&*k.0..)
                        .rev()
                        .take(len.abs().try_into().unwrap())
                        .map(Result::unwrap);
                    let ref_iter = reference
                        .iter()
                        .rev()
                        .filter(|&(ref rk, _rv)| **rk >= k)
                        .take(len.abs().try_into().unwrap())
                        .map(|(ref rk, ref rv)| (rk.0.clone(), **rv));

                    for r in ref_iter {
                        let tree_next = tree_iter.next().unwrap();
                        let lhs = (tree_next.0, &*tree_next.1);
                        let rhs = (r.0.clone(), &*u16_to_bytes(r.1));
                        assert_eq!(
                            (lhs.0.as_ref(), lhs.1),
                            (rhs.0.as_ref(), rhs.1),
                            "expected {:?} while reverse iterating from {:?} on tree: {:?}",
                            rhs,
                            k,
                            tree
                        );
                    }
                }
            }
            Restart => {
                drop(tree);
                tree = Db::start(config.clone()).unwrap();
                tree.set_merge_operator(test_merge_operator);
            }
        }
    }

    let space_amplification = tree
        .space_amplification()
        .expect("should be able to read files and pages");

    assert!(
        space_amplification < MAX_SPACE_AMPLIFICATION,
        "space amplification was measured to be {}, \
         which is higher than the maximum of {}",
        space_amplification,
        MAX_SPACE_AMPLIFICATION
    );

    true
}

#[test]
fn test_fuzz_test() {
    let seed = [0; 32];
    fuzz_then_shrink(&seed);
    let seed = [0; 31];
    fuzz_then_shrink(&seed);
    let seed = [0; 33];
    fuzz_then_shrink(&seed);
    fuzz_then_shrink(&[]);
}
<|endoftext|>