<commit_before>//! Generic matrix operations

use std;

///  A cairo_matrix_t holds an affine transformation, such as a scale, rotation, shear, or a combination of those. The transformation of a point (x, y) is given by:
///
/// ```
/// x_new = xx * x + xy * y + x0;
/// y_new = yx * x + yy * y + y0;
/// ```
///
/// double xx; xx component of the affine transformation
///
/// double yx; yx component of the affine transformation
///
/// double xy; xy component of the affine transformation
///
/// double yy; yy component of the affine transformation
///
/// double x0; X translation component of the affine transformation
///
/// double y0; Y translation component of the affine transformation
///
/// Since 1.0
pub struct Matrix {
  xx: f64,
  yx: f64,
  xy: f64,
  yy: f64,
  x0: f64,
  y0: f64
}

impl Matrix {
  ///  Sets matrix to be the affine transformation given by xx, yx, xy, yy, x0, y0. The transformation is given by:
  ///
  /// ```
  /// x_new = xx * x + xy * y + x0;
  /// y_new = yx * x + yy * y + y0;
  /// ```
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// xx : xx component of the affine transformation
  ///
  /// yx : yx component of the affine transformation
  ///
  /// xy : xy component of the affine transformation
  ///
  /// yy : yy component of the affine transformation
  ///
  /// x0 : X translation component of the affine transformation
  ///
  /// y0 : Y translation component of the affine transformation
  ///
  /// Since 1.0
  pub fn new(xx: f64, yx: f64, xy: f64, yy: f64, x0: f64, y0: f64) -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_init(&mut this, xx, yx, xy, yy, x0, y0);
      return this;
    }
  }

  ///  Modifies matrix to be an identity transformation.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// Since 1.0
  pub fn identity() -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_init_identity(&mut this);
      return this;
    }
  }

  ///  Initializes matrix to a transformation that translates by tx and ty in the X and Y dimensions, respectively.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// tx : amount to translate in the X direction
  ///
  /// ty : amount to translate in the Y direction
  ///
  /// Since 1.0
  pub fn for_translation(x0: f64, y0: f64) -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_init_translate(&mut this, x0, y0);
      return this;
    }
  }

  ///  Initializes matrix to a transformation that scales by sx and sy in the X and Y dimensions, respectively.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// sx : scale factor in the X direction
  ///
  /// sy : scale factor in the Y direction
  ///
  /// Since 1.0
  pub fn for_scale(sx: f64, sy: f64) -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_init_scale(&mut this, sx, sy);
      return this;
    }
  }

  ///  Initialized matrix to a transformation that rotates by radians.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// radians : angle of rotation, in radians. The direction of rotation is defined such that positive angles rotate in the direction from the positive X axis toward the positive Y axis. With the default axis orientation of cairo, positive angles rotate in a clockwise direction.
  ///
  /// Since 1.0
  pub fn for_rotation(radians: f64) -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_init_rotate(&mut this, radians);
      return this;
    }
  }

  ///  Multiplies the affine transformations in a and b together and stores the result in result. The effect of the resulting transformation is to first apply the transformation in a to the coordinates and then apply the transformation in b to the coordinates.
  ///
  /// It is allowable for result to be identical to either a or b.
  ///
  /// result : a cairo_matrix_t in which to store the result
  ///
  /// a : a cairo_matrix_t
  ///
  /// b : a cairo_matrix_t
  ///
  /// Since 1.0
  pub fn multiply(a: &Matrix, b: &Matrix) -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_multiply(&mut this, a, b);
      return this;
    }
  }

  ///  Applies a translation by tx, ty to the transformation in matrix. The effect of the new transformation is to first translate the coordinates by tx and ty, then apply the original transformation to the coordinates.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// tx : amount to translate in the X direction
  ///
  /// ty : amount to translate in the Y direction
  ///
  /// Since 1.0
  pub fn translate(&mut self, x0: f64, y0: f64) {
    unsafe {
      cairo_matrix_translate(self, x0, y0);
    }
  }

  ///  Applies scaling by sx, sy to the transformation in matrix. The effect of the new transformation is to first scale the coordinates by sx and sy, then apply the original transformation to the coordinates.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// sx : scale factor in the X direction
  ///
  /// sy : scale factor in the Y direction
  ///
  /// Since 1.0
  pub fn scale(&mut self, sx: f64, sy: f64) {
    unsafe {
      cairo_matrix_scale(self, sx, sy);
    }
  }

  ///  Applies rotation by radians to the transformation in matrix. The effect of the new transformation is to first rotate the coordinates by radians, then apply the original transformation to the coordinates.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// radians : angle of rotation, in radians. The direction of rotation is defined such that positive angles rotate in the direction from the positive X axis toward the positive Y axis. With the default axis orientation of cairo, positive angles rotate in a clockwise direction.
  ///
  /// Since 1.0
  pub fn rotate(&mut self, radians: f64) {
    unsafe {
      cairo_matrix_rotate(self, radians);
    }
  }

  ///  Transforms the distance vector (dx,dy) by matrix. This is similar to cairo_matrix_transform_point() except that the translation components of the transformation are ignored. The calculation of the returned vector is as follows:
  ///
  /// ```
  /// dx2 = dx1 * a + dy1 * c;
  /// dy2 = dx1 * b + dy1 * d;
  /// ```
  ///
  /// Affine transformations are position invariant, so the same vector always transforms to the same vector. If (x1,y1) transforms to (x2,y2) then (x1+dx1,y1+dy1) will transform to (x1+dx2,y1+dy2) for all values of x1 and x2.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// dx : X component of a distance vector. An in/out parameter
  ///
  /// dy : Y component of a distance vector. An in/out parameter
  ///
  /// Since 1.0
  pub fn transform_distance(&self, dx_r: f64, dy_r: f64) -> (f64, f64) {
    unsafe {
      let mut dx = dx_r;
      let mut dy = dy_r;
      cairo_matrix_transform_distance(self, &mut dx, &mut dy);
      return (dx, dy);
    }
  }

  /// Transforms the point (x, y) by matrix.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// x : X position. An in/out parameter
  ///
  /// y : Y position. An in/out parameter
  ///
  /// Since 1.0
  pub fn transform_point(&self, x_r: f64, y_r: f64) -> (f64, f64) {
    unsafe {
      let mut x = x_r;
      let mut y = y_r;
      cairo_matrix_transform_point(self, &mut x, &mut y);
      return (x, y);
    }
  }

  /// Changes matrix to be the inverse of its original value. Not all transformation matrices have inverses; if the matrix collapses points together (it is degenerate), then it has no inverse and this function will fail.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// Returns : If matrix has an inverse, modifies matrix to be the inverse matrix and returns CAIRO_STATUS_SUCCESS. Otherwise, returns CAIRO_STATUS_INVALID_MATRIX.
  ///
  /// Since 1.0
  pub fn invert(&mut self) -> super::Status {
    unsafe {
      let foreign_result = cairo_matrix_invert(self);
      return foreign_result;
    }
  }
}

extern {
  fn cairo_matrix_init(this: *mut Matrix, xx: f64, yx: f64, xy: f64, yy: f64, x0: f64, y0: f64);
  fn cairo_matrix_init_identity(this: *mut Matrix);
  fn cairo_matrix_init_translate(this: *mut Matrix, x0: f64, y0: f64);
  fn cairo_matrix_init_scale(this: *mut Matrix, sx: f64, sy: f64);
  fn cairo_matrix_init_rotate(this: *mut Matrix, radians: f64);
  fn cairo_matrix_multiply(this: *mut Matrix, a: *Matrix, b: *Matrix);
  fn cairo_matrix_translate(self_value: *mut Matrix, x0: f64, y0: f64);
  fn cairo_matrix_scale(self_value: *mut Matrix, sx: f64, sy: f64);
  fn cairo_matrix_rotate(self_value: *mut Matrix, radians: f64);
  fn cairo_matrix_transform_distance(self_value: *Matrix, dx: &mut f64, dy: &mut f64);
  fn cairo_matrix_transform_point(self_value: *Matrix, x: &mut f64, y: &mut f64);
  fn cairo_matrix_invert(self_value: *mut Matrix) -> super::Status;
}

<commit_msg>Documented members of Matrix.<commit_after>//! Generic matrix operations

use std;

///  A cairo_matrix_t holds an affine transformation, such as a scale, rotation, shear, or a combination of those. The transformation of a point (x, y) is given by:
///
/// ```
/// x_new = xx * x + xy * y + x0;
/// y_new = yx * x + yy * y + y0;
/// ```
///
/// Since 1.0
pub struct Matrix {
  /// double xx; xx component of the affine transformation
  xx: f64,
  /// double yx; yx component of the affine transformation
  yx: f64,
  /// double xy; xy component of the affine transformation
  xy: f64,
  /// double yy; yy component of the affine transformation
  yy: f64,
  /// double x0; X translation component of the affine transformation
  x0: f64,
  /// double y0; Y translation component of the affine transformation
  y0: f64
}

impl Matrix {
  ///  Sets matrix to be the affine transformation given by xx, yx, xy, yy, x0, y0. The transformation is given by:
  ///
  /// ```
  /// x_new = xx * x + xy * y + x0;
  /// y_new = yx * x + yy * y + y0;
  /// ```
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// xx : xx component of the affine transformation
  ///
  /// yx : yx component of the affine transformation
  ///
  /// xy : xy component of the affine transformation
  ///
  /// yy : yy component of the affine transformation
  ///
  /// x0 : X translation component of the affine transformation
  ///
  /// y0 : Y translation component of the affine transformation
  ///
  /// Since 1.0
  pub fn new(xx: f64, yx: f64, xy: f64, yy: f64, x0: f64, y0: f64) -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_init(&mut this, xx, yx, xy, yy, x0, y0);
      return this;
    }
  }

  ///  Modifies matrix to be an identity transformation.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// Since 1.0
  pub fn identity() -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_init_identity(&mut this);
      return this;
    }
  }

  ///  Initializes matrix to a transformation that translates by tx and ty in the X and Y dimensions, respectively.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// tx : amount to translate in the X direction
  ///
  /// ty : amount to translate in the Y direction
  ///
  /// Since 1.0
  pub fn for_translation(x0: f64, y0: f64) -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_init_translate(&mut this, x0, y0);
      return this;
    }
  }

  ///  Initializes matrix to a transformation that scales by sx and sy in the X and Y dimensions, respectively.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// sx : scale factor in the X direction
  ///
  /// sy : scale factor in the Y direction
  ///
  /// Since 1.0
  pub fn for_scale(sx: f64, sy: f64) -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_init_scale(&mut this, sx, sy);
      return this;
    }
  }

  ///  Initialized matrix to a transformation that rotates by radians.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// radians : angle of rotation, in radians. The direction of rotation is defined such that positive angles rotate in the direction from the positive X axis toward the positive Y axis. With the default axis orientation of cairo, positive angles rotate in a clockwise direction.
  ///
  /// Since 1.0
  pub fn for_rotation(radians: f64) -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_init_rotate(&mut this, radians);
      return this;
    }
  }

  ///  Multiplies the affine transformations in a and b together and stores the result in result. The effect of the resulting transformation is to first apply the transformation in a to the coordinates and then apply the transformation in b to the coordinates.
  ///
  /// It is allowable for result to be identical to either a or b.
  ///
  /// result : a cairo_matrix_t in which to store the result
  ///
  /// a : a cairo_matrix_t
  ///
  /// b : a cairo_matrix_t
  ///
  /// Since 1.0
  pub fn multiply(a: &Matrix, b: &Matrix) -> Matrix {
    unsafe {
      let mut this:Matrix = std::intrinsics::init();
      cairo_matrix_multiply(&mut this, a, b);
      return this;
    }
  }

  ///  Applies a translation by tx, ty to the transformation in matrix. The effect of the new transformation is to first translate the coordinates by tx and ty, then apply the original transformation to the coordinates.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// tx : amount to translate in the X direction
  ///
  /// ty : amount to translate in the Y direction
  ///
  /// Since 1.0
  pub fn translate(&mut self, x0: f64, y0: f64) {
    unsafe {
      cairo_matrix_translate(self, x0, y0);
    }
  }

  ///  Applies scaling by sx, sy to the transformation in matrix. The effect of the new transformation is to first scale the coordinates by sx and sy, then apply the original transformation to the coordinates.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// sx : scale factor in the X direction
  ///
  /// sy : scale factor in the Y direction
  ///
  /// Since 1.0
  pub fn scale(&mut self, sx: f64, sy: f64) {
    unsafe {
      cairo_matrix_scale(self, sx, sy);
    }
  }

  ///  Applies rotation by radians to the transformation in matrix. The effect of the new transformation is to first rotate the coordinates by radians, then apply the original transformation to the coordinates.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// radians : angle of rotation, in radians. The direction of rotation is defined such that positive angles rotate in the direction from the positive X axis toward the positive Y axis. With the default axis orientation of cairo, positive angles rotate in a clockwise direction.
  ///
  /// Since 1.0
  pub fn rotate(&mut self, radians: f64) {
    unsafe {
      cairo_matrix_rotate(self, radians);
    }
  }

  ///  Transforms the distance vector (dx,dy) by matrix. This is similar to cairo_matrix_transform_point() except that the translation components of the transformation are ignored. The calculation of the returned vector is as follows:
  ///
  /// ```
  /// dx2 = dx1 * a + dy1 * c;
  /// dy2 = dx1 * b + dy1 * d;
  /// ```
  ///
  /// Affine transformations are position invariant, so the same vector always transforms to the same vector. If (x1,y1) transforms to (x2,y2) then (x1+dx1,y1+dy1) will transform to (x1+dx2,y1+dy2) for all values of x1 and x2.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// dx : X component of a distance vector. An in/out parameter
  ///
  /// dy : Y component of a distance vector. An in/out parameter
  ///
  /// Since 1.0
  pub fn transform_distance(&self, dx_r: f64, dy_r: f64) -> (f64, f64) {
    unsafe {
      let mut dx = dx_r;
      let mut dy = dy_r;
      cairo_matrix_transform_distance(self, &mut dx, &mut dy);
      return (dx, dy);
    }
  }

  /// Transforms the point (x, y) by matrix.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// x : X position. An in/out parameter
  ///
  /// y : Y position. An in/out parameter
  ///
  /// Since 1.0
  pub fn transform_point(&self, x_r: f64, y_r: f64) -> (f64, f64) {
    unsafe {
      let mut x = x_r;
      let mut y = y_r;
      cairo_matrix_transform_point(self, &mut x, &mut y);
      return (x, y);
    }
  }

  /// Changes matrix to be the inverse of its original value. Not all transformation matrices have inverses; if the matrix collapses points together (it is degenerate), then it has no inverse and this function will fail.
  ///
  /// matrix : a cairo_matrix_t
  ///
  /// Returns : If matrix has an inverse, modifies matrix to be the inverse matrix and returns CAIRO_STATUS_SUCCESS. Otherwise, returns CAIRO_STATUS_INVALID_MATRIX.
  ///
  /// Since 1.0
  pub fn invert(&mut self) -> super::Status {
    unsafe {
      let foreign_result = cairo_matrix_invert(self);
      return foreign_result;
    }
  }
}

extern {
  fn cairo_matrix_init(this: *mut Matrix, xx: f64, yx: f64, xy: f64, yy: f64, x0: f64, y0: f64);
  fn cairo_matrix_init_identity(this: *mut Matrix);
  fn cairo_matrix_init_translate(this: *mut Matrix, x0: f64, y0: f64);
  fn cairo_matrix_init_scale(this: *mut Matrix, sx: f64, sy: f64);
  fn cairo_matrix_init_rotate(this: *mut Matrix, radians: f64);
  fn cairo_matrix_multiply(this: *mut Matrix, a: *Matrix, b: *Matrix);
  fn cairo_matrix_translate(self_value: *mut Matrix, x0: f64, y0: f64);
  fn cairo_matrix_scale(self_value: *mut Matrix, sx: f64, sy: f64);
  fn cairo_matrix_rotate(self_value: *mut Matrix, radians: f64);
  fn cairo_matrix_transform_distance(self_value: *Matrix, dx: &mut f64, dy: &mut f64);
  fn cairo_matrix_transform_point(self_value: *Matrix, x: &mut f64, y: &mut f64);
  fn cairo_matrix_invert(self_value: *mut Matrix) -> super::Status;
}

<|endoftext|>


<commit_before>use rustc::lint::*;
use rustc::hir::{Expr, ExprCall, ExprPath};
use utils::{get_trait_def_id, implements_trait, match_def_path, paths, span_lint};

/// **What it does:** This lint checks for usage of `std::mem::forget(t)` where `t` is `Drop`.
///
/// **Why is this bad?** `std::mem::forget(t)` prevents `t` from running its destructor, possibly causing leaks
///
/// **Known problems:** None.
///
/// **Example:** `mem::forget(Rc::new(55)))`
declare_lint! {
    pub MEM_FORGET,
    Allow,
    "`mem::forget` usage on `Drop` types is likely to cause memory leaks"
}

pub struct MemForget;

impl LintPass for MemForget {
    fn get_lints(&self) -> LintArray {
        lint_array![MEM_FORGET]
    }
}

impl LateLintPass for MemForget {
    fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
        if let ExprCall(ref path_expr, ref args) = e.node {
            if let ExprPath(None, _) = path_expr.node {
                let def_id = cx.tcx.def_map.borrow()[&path_expr.id].def_id();
                if match_def_path(cx, def_id, &paths::MEM_FORGET) {
                    if let Some(drop_trait_id) = get_trait_def_id(cx, &paths::DROP) {
                        let forgot_ty = cx.tcx.expr_ty(&args[0]);

                        if implements_trait(cx, forgot_ty, drop_trait_id, Vec::new()) {
                            span_lint(cx, MEM_FORGET, e.span, "usage of mem::forget on Drop type");
                        }
                    }
                }
            }
        }
    }
}
<commit_msg>Fixed destructor detection in mem_forget<commit_after>use rustc::lint::*;
use rustc::hir::{Expr, ExprCall, ExprPath};
use utils::{match_def_path, paths, span_lint};

/// **What it does:** This lint checks for usage of `std::mem::forget(t)` where `t` is `Drop`.
///
/// **Why is this bad?** `std::mem::forget(t)` prevents `t` from running its destructor, possibly causing leaks
///
/// **Known problems:** None.
///
/// **Example:** `mem::forget(Rc::new(55)))`
declare_lint! {
    pub MEM_FORGET,
    Allow,
    "`mem::forget` usage on `Drop` types is likely to cause memory leaks"
}

pub struct MemForget;

impl LintPass for MemForget {
    fn get_lints(&self) -> LintArray {
        lint_array![MEM_FORGET]
    }
}

impl LateLintPass for MemForget {
    fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
        if let ExprCall(ref path_expr, ref args) = e.node {
            if let ExprPath(None, _) = path_expr.node {
                let def_id = cx.tcx.def_map.borrow()[&path_expr.id].def_id();
                if match_def_path(cx, def_id, &paths::MEM_FORGET) {
                    let forgot_ty = cx.tcx.expr_ty(&args[0]);

                    if match forgot_ty.ty_adt_def() {
                        Some(def) => def.has_dtor(),
                        _ => false
                    } {
                        span_lint(cx, MEM_FORGET, e.span, "usage of mem::forget on Drop type");
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// vim: tw=80
use mockall::*;

// mock! should allow doc comments in all reasonable positions.  This test
// ensures that the code will compile.  mockall_derive has a unit test to ensure
// that the doc comments are correctly placed.

trait Tr {
    fn bar(&self);
}

mock!{
    /// Struct docs
    pub Foo {
        /// Method docs
        fn foo(&self);
    }
    trait Tr {
        /// Trait method docs
        fn bar(&self);
    }
}

<commit_msg>Deny missing docs in the mock docs test<commit_after>// vim: tw=80
#![deny(missing_docs)]

use mockall::*;

// mock! should allow doc comments in all reasonable positions.  This test
// ensures that the code will compile.  mockall_derive has a unit test to ensure
// that the doc comments are correctly placed.

trait Tr {
    fn bar(&self);
}

mock!{
    /// Struct docs
    pub Foo {
        /// Method docs
        fn foo(&self);
    }
    /// Trait docs
    trait Tr {
        /// Trait method docs
        fn bar(&self);
    }
}
<|endoftext|>


<commit_before>use petgraph::{EdgeDirection, Graph};
use petgraph::graph::{Edge, NodeIndex, EdgeIndex};
use super::ir;
use super::dot::{GraphDot, DotAttrBlock};

pub struct SSA {
	pub g: Graph<NodeData, EdgeData>
}

#[derive(Clone, Debug)]
pub enum NodeData {
	Op(ir::MOpcode),
	Comment(String),
	Const(u64),
	Phi(String),
	Undefined,
	Removed,
	BasicBlock
}

#[derive(Clone, Copy)]
pub enum EdgeData {
	Control(u8),
	Data(u8),
	ContainedInBB,
	ReplacedBy
}

impl SSA {
	pub fn new() -> SSA {
		SSA {g: Graph::new() }
	}

	pub fn add_op(&mut self, block: NodeIndex, opc: ir::MOpcode) -> NodeIndex {
		let n = self.g.add_node(NodeData::Op(opc));
		self.g.update_edge(n, block, EdgeData::ContainedInBB);
		n
	}

	pub fn add_comment(&mut self, block: NodeIndex, msg: &String) -> NodeIndex {
		let n = self.g.add_node(NodeData::Comment(msg.clone()));
		self.g.update_edge(n, block, EdgeData::ContainedInBB);
		n
	}

	pub fn add_const(&mut self, block: NodeIndex, value: u64) -> NodeIndex {
		let n = self.g.add_node(NodeData::Const(value));
		self.g.update_edge(n, block, EdgeData::ContainedInBB);
		n
	}

	pub fn add_phi(&mut self, block: NodeIndex) -> NodeIndex {
		let n = self.g.add_node(NodeData::Phi("".to_string()));
		self.g.update_edge(n, block, EdgeData::ContainedInBB);
		n
	}

	pub fn add_phi_comment(&mut self, block: NodeIndex, comment: &String) -> NodeIndex {
		let n = self.g.add_node(NodeData::Phi(comment.clone()));
		self.g.update_edge(n, block, EdgeData::ContainedInBB);
		n
	}

	pub fn add_block(&mut self) -> NodeIndex {
		self.g.add_node(NodeData::BasicBlock)
	}

	// TODO: Reuse code between args_of/uses_of/preds_of/succs_of

	pub fn args_of(&self, node: NodeIndex) -> Vec<NodeIndex> {
		let mut args = Vec::new();
		let mut walk = self.g.walk_edges_directed(node, EdgeDirection::Outgoing);
		while let Some((edge, othernode)) = walk.next_neighbor(&self.g) {
			if let EdgeData::Data(_) = self.g[edge] {
				args.push(othernode);
			}
		}
		args
	}

	pub fn uses_of(&self, node: NodeIndex) -> Vec<NodeIndex> {
		let mut uses = Vec::new();
		let mut walk = self.g.walk_edges_directed(node, EdgeDirection::Incoming);
		while let Some((edge, othernode)) = walk.next_neighbor(&self.g) {
			if let EdgeData::Data(_) = self.g[edge] {
				uses.push(othernode);
			}
		}
		uses
	}

	pub fn preds_of(&self, node: NodeIndex) -> Vec<NodeIndex> {
		let mut preds = Vec::new();
		let mut walk = self.g.walk_edges_directed(node, EdgeDirection::Incoming);
		while let Some((edge, othernode)) = walk.next_neighbor(&self.g) {
			if let EdgeData::Control(_) = self.g[edge] {
				preds.push(othernode);
			}
		}
		preds
	}

	pub fn succs_of(&self, node: NodeIndex) -> Vec<NodeIndex> {
		let mut succs = Vec::new();
		let mut walk = self.g.walk_edges_directed(node, EdgeDirection::Outgoing);
		while let Some((edge, othernode)) = walk.next_neighbor(&self.g) {
			if let EdgeData::Control(_) = self.g[edge] {
				succs.push(othernode);
			}
		}
		succs
	}

	pub fn block_of(&self, node: NodeIndex) -> NodeIndex {
		let mut walk = self.g.walk_edges_directed(node, EdgeDirection::Outgoing);
		while let Some((edge, othernode)) = walk.next_neighbor(&self.g) {
			if let EdgeData::ContainedInBB = self.g[edge] {
				return othernode
			}
		}
		return NodeIndex::end()
	}

	pub fn phi_use(&mut self, phi: NodeIndex, node: NodeIndex) {
		assert!(if let NodeData::Phi(_) = self.g[phi] { true } else { false });
		assert!(if let NodeData::Removed = self.g[node] { false } else { true });
		self.g.update_edge(phi, node, EdgeData::Data(0));
	}

	pub fn phi_unuse(&mut self, phi: NodeIndex, node: NodeIndex) {
		assert!(if let NodeData::Phi(_) = self.g[phi] { true } else { false });
		if let Option::Some(edge) = self.g.find_edge(phi, node) {
			self.g.remove_edge(edge);
		}
	}

	pub fn op_use(&mut self, node: NodeIndex, index: u8, argument: NodeIndex) {
		if argument == NodeIndex::end() { return }
		assert!(if let NodeData::Removed = self.g[argument] { false } else { true });
		// TODO: find existing edge
		self.g.add_edge(node, argument, EdgeData::Data(index));
	}

	pub fn replace(&mut self, node: NodeIndex, replacement: NodeIndex) {
		if node == replacement { return }

		let mut walk = self.g.walk_edges_directed(node, EdgeDirection::Incoming);
		let mut remove_us = Vec::<EdgeIndex>::new();
		while let Some((edge, othernode)) = walk.next_neighbor(&self.g) {
			if let EdgeData::Data(i) = self.g[edge] {
				match self.g[othernode] {
					NodeData::Op(_) => self.op_use(othernode, i, replacement),
					NodeData::Phi(_) => self.phi_use(othernode, replacement),
					_ => panic!()
				}
			}
			remove_us.push(edge);
		}
		self.g.add_node(NodeData::Removed);
		self.g.remove_node(node);
		self.g.add_edge(node, replacement, EdgeData::ReplacedBy);
	}

	pub fn cleanup(&mut self) {
		let mut i = 0;
		let mut n = self.g.node_count();
		while i < n {
			if {
				let ni = NodeIndex::new(i);
				match self.g[ni] {
					NodeData::Removed => true,
					NodeData::Comment(_) if self.g.first_edge(ni, EdgeDirection::Incoming) == Option::None => true,
					_ => false
				}
			} {
				self.g.remove_node(NodeIndex::new(i));
				n -= 1;
			} else {
				i += 1;
			}
		}
	}
}

impl GraphDot for SSA {
    type NodeType = NodeData;
    type EdgeType = Edge<EdgeData>;

    fn configure(&self) -> String {
        format!("digraph cfg {{\nsplines=\"true\";\n")
    }

    fn nodes(&self) -> Vec<Self::NodeType> {
        let res = self.g.raw_nodes().iter().map(|e| e.weight.clone()).collect();
        res
    }

    fn edges(&self) -> Vec<Self::EdgeType> {
        let res = self.g.raw_edges().to_vec();
        res
    }

    fn get_node(&self, n: usize) -> Option<&Self::NodeType> {
        self.g.node_weight(NodeIndex::new(n))
    }

    fn edge_source(&self, edge: &Edge<EdgeData>) -> usize {
		match edge.weight {
			EdgeData::Data(_) => edge.target().index(),
			_                 => edge.source().index()
		}
    }

    fn edge_target(&self, edge: &Edge<EdgeData>) -> usize {
		match edge.weight {
			EdgeData::Data(_) => edge.source().index(),
			_                 => edge.target().index()
		}
    }

    fn edge_skip(&self, edge: &Edge<EdgeData>) -> bool {
    	if let EdgeData::ContainedInBB = edge.weight {
    		if let NodeData::Phi(_) = self.g[edge.source()] {
    			false
    		} else {
 				true
 			}
		} else {
			false
    	}
    }

    fn edge_attrs(&self, edge: &Edge<EdgeData>) -> DotAttrBlock {
    	DotAttrBlock::Raw(match edge.weight {
    		EdgeData::Control(_)    => "[color=\"blue\"]",
    		EdgeData::Data(_)       => "[dir=\"back\"]",
    		EdgeData::ContainedInBB => "[color=\"gray\"]",
    		EdgeData::ReplacedBy    => "[color=\"red\"]"
    	}.to_string())
    }

    fn node_attrs(&self, node: &NodeData) -> DotAttrBlock {
    	let l = format!("{:?}", node);
        DotAttrBlock::Raw(format!(" [label=\"{}\"]", l.replace("\"", "\\\"")))
    }
}
<commit_msg>modify SSA::args_of to return arguments of operation in correct order<commit_after>use petgraph::{EdgeDirection, Graph};
use petgraph::graph::{Edge, NodeIndex, EdgeIndex};
use super::ir;
use super::dot::{GraphDot, DotAttrBlock};

pub struct SSA {
	pub g: Graph<NodeData, EdgeData>
}

#[derive(Clone, Debug)]
pub enum NodeData {
	Op(ir::MOpcode),
	Comment(String),
	Const(u64),
	Phi(String),
	Undefined,
	Removed,
	BasicBlock
}

#[derive(Clone, Copy)]
pub enum EdgeData {
	Control(u8),
	Data(u8),
	ContainedInBB,
	ReplacedBy
}

impl SSA {
	pub fn new() -> SSA {
		SSA {g: Graph::new() }
	}

	pub fn add_op(&mut self, block: NodeIndex, opc: ir::MOpcode) -> NodeIndex {
		let n = self.g.add_node(NodeData::Op(opc));
		self.g.update_edge(n, block, EdgeData::ContainedInBB);
		n
	}

	pub fn add_comment(&mut self, block: NodeIndex, msg: &String) -> NodeIndex {
		let n = self.g.add_node(NodeData::Comment(msg.clone()));
		self.g.update_edge(n, block, EdgeData::ContainedInBB);
		n
	}

	pub fn add_const(&mut self, block: NodeIndex, value: u64) -> NodeIndex {
		let n = self.g.add_node(NodeData::Const(value));
		self.g.update_edge(n, block, EdgeData::ContainedInBB);
		n
	}

	pub fn add_phi(&mut self, block: NodeIndex) -> NodeIndex {
		let n = self.g.add_node(NodeData::Phi("".to_string()));
		self.g.update_edge(n, block, EdgeData::ContainedInBB);
		n
	}

	pub fn add_phi_comment(&mut self, block: NodeIndex, comment: &String) -> NodeIndex {
		let n = self.g.add_node(NodeData::Phi(comment.clone()));
		self.g.update_edge(n, block, EdgeData::ContainedInBB);
		n
	}

	pub fn add_block(&mut self) -> NodeIndex {
		self.g.add_node(NodeData::BasicBlock)
	}

	// TODO: Reuse code between args_of/uses_of/preds_of/succs_of

	pub fn args_of(&self, node: NodeIndex) -> Vec<NodeIndex> {
		let mut args = vec![NodeIndex::end(), NodeIndex::end()]; // Vec::new();
		let mut walk = self.g.walk_edges_directed(node, EdgeDirection::Outgoing);
		while let Some((edge, othernode)) = walk.next_neighbor(&self.g) {
			if let EdgeData::Data(index) = self.g[edge] {
				args[index] = othernode;
				//args.push(othernode);
			}
		}
		let mut i = args.len();
		while i > 0 && args[i-1] == NodeIndex::end() {
			i -= 1;
		}
		args.truncate(i);
		args
	}

	pub fn uses_of(&self, node: NodeIndex) -> Vec<NodeIndex> {
		let mut uses = Vec::new();
		let mut walk = self.g.walk_edges_directed(node, EdgeDirection::Incoming);
		while let Some((edge, othernode)) = walk.next_neighbor(&self.g) {
			if let EdgeData::Data(_) = self.g[edge] {
				uses.push(othernode);
			}
		}
		uses
	}

	pub fn preds_of(&self, node: NodeIndex) -> Vec<NodeIndex> {
		let mut preds = Vec::new();
		let mut walk = self.g.walk_edges_directed(node, EdgeDirection::Incoming);
		while let Some((edge, othernode)) = walk.next_neighbor(&self.g) {
			if let EdgeData::Control(_) = self.g[edge] {
				preds.push(othernode);
			}
		}
		preds
	}

	pub fn succs_of(&self, node: NodeIndex) -> Vec<NodeIndex> {
		let mut succs = Vec::new();
		let mut walk = self.g.walk_edges_directed(node, EdgeDirection::Outgoing);
		while let Some((edge, othernode)) = walk.next_neighbor(&self.g) {
			if let EdgeData::Control(_) = self.g[edge] {
				succs.push(othernode);
			}
		}
		succs
	}

	pub fn block_of(&self, node: NodeIndex) -> NodeIndex {
		let mut walk = self.g.walk_edges_directed(node, EdgeDirection::Outgoing);
		while let Some((edge, othernode)) = walk.next_neighbor(&self.g) {
			if let EdgeData::ContainedInBB = self.g[edge] {
				return othernode
			}
		}
		return NodeIndex::end()
	}

	pub fn phi_use(&mut self, phi: NodeIndex, node: NodeIndex) {
		assert!(if let NodeData::Phi(_) = self.g[phi] { true } else { false });
		assert!(if let NodeData::Removed = self.g[node] { false } else { true });
		self.g.update_edge(phi, node, EdgeData::Data(0));
	}

	pub fn phi_unuse(&mut self, phi: NodeIndex, node: NodeIndex) {
		assert!(if let NodeData::Phi(_) = self.g[phi] { true } else { false });
		if let Option::Some(edge) = self.g.find_edge(phi, node) {
			self.g.remove_edge(edge);
		}
	}

	pub fn op_use(&mut self, node: NodeIndex, index: u8, argument: NodeIndex) {
		if argument == NodeIndex::end() { return }
		assert!(if let NodeData::Removed = self.g[argument] { false } else { true });
		// TODO: find existing edge
		self.g.add_edge(node, argument, EdgeData::Data(index));
	}

	pub fn replace(&mut self, node: NodeIndex, replacement: NodeIndex) {
		if node == replacement { return }

		let mut walk = self.g.walk_edges_directed(node, EdgeDirection::Incoming);
		let mut remove_us = Vec::<EdgeIndex>::new();
		while let Some((edge, othernode)) = walk.next_neighbor(&self.g) {
			if let EdgeData::Data(i) = self.g[edge] {
				match self.g[othernode] {
					NodeData::Op(_) => self.op_use(othernode, i, replacement),
					NodeData::Phi(_) => self.phi_use(othernode, replacement),
					_ => panic!()
				}
			}
			remove_us.push(edge);
		}
		self.g.add_node(NodeData::Removed);
		self.g.remove_node(node);
		self.g.add_edge(node, replacement, EdgeData::ReplacedBy);
	}

	pub fn cleanup(&mut self) {
		let mut i = 0;
		let mut n = self.g.node_count();
		while i < n {
			if {
				let ni = NodeIndex::new(i);
				match self.g[ni] {
					NodeData::Removed => true,
					NodeData::Comment(_) if self.g.first_edge(ni, EdgeDirection::Incoming) == Option::None => true,
					_ => false
				}
			} {
				self.g.remove_node(NodeIndex::new(i));
				n -= 1;
			} else {
				i += 1;
			}
		}
	}
}

impl GraphDot for SSA {
    type NodeType = NodeData;
    type EdgeType = Edge<EdgeData>;

    fn configure(&self) -> String {
        format!("digraph cfg {{\nsplines=\"true\";\n")
    }

    fn nodes(&self) -> Vec<Self::NodeType> {
        let res = self.g.raw_nodes().iter().map(|e| e.weight.clone()).collect();
        res
    }

    fn edges(&self) -> Vec<Self::EdgeType> {
        let res = self.g.raw_edges().to_vec();
        res
    }

    fn get_node(&self, n: usize) -> Option<&Self::NodeType> {
        self.g.node_weight(NodeIndex::new(n))
    }

    fn edge_source(&self, edge: &Edge<EdgeData>) -> usize {
		match edge.weight {
			EdgeData::Data(_) => edge.target().index(),
			_                 => edge.source().index()
		}
    }

    fn edge_target(&self, edge: &Edge<EdgeData>) -> usize {
		match edge.weight {
			EdgeData::Data(_) => edge.source().index(),
			_                 => edge.target().index()
		}
    }

    fn edge_skip(&self, edge: &Edge<EdgeData>) -> bool {
    	if let EdgeData::ContainedInBB = edge.weight {
    		if let NodeData::Phi(_) = self.g[edge.source()] {
    			false
    		} else {
 				true
 			}
		} else {
			false
    	}
    }

    fn edge_attrs(&self, edge: &Edge<EdgeData>) -> DotAttrBlock {
    	DotAttrBlock::Raw(match edge.weight {
    		EdgeData::Control(_)    => "[color=\"blue\"]",
    		EdgeData::Data(_)       => "[dir=\"back\"]",
    		EdgeData::ContainedInBB => "[color=\"gray\"]",
    		EdgeData::ReplacedBy    => "[color=\"red\"]"
    	}.to_string())
    }

    fn node_attrs(&self, node: &NodeData) -> DotAttrBlock {
    	let l = format!("{:?}", node);
        DotAttrBlock::Raw(format!(" [label=\"{}\"]", l.replace("\"", "\\\"")))
    }
}
<|endoftext|>


<commit_before>use std::net::SocketAddr;

use hyper::header;
use hyper::method::Method;

use url::Position;

use urlencoded;

use unicase::UniCase;

use iron;
use iron::prelude::*;

use models;

header! { (XForwardedHost, "X-Forwarded-Host") => [String] }
header! { (XForwardedPort, "X-Forwarded-Port") => [u16] }
header! { (XForwardedProto, "X-Forwarded-Proto") => [String] }
header! { (XForwardedFor, "X-Forwarded-For") => [SocketAddr] }

pub struct XForwardedMiddleware;

impl iron::middleware::BeforeMiddleware for XForwardedMiddleware {
    fn before(&self, request: &mut Request) -> IronResult<()> {
        macro_rules! h {
            ($x:ty) => {{
                // FIXME: https://github.com/hyperium/hyper/issues/891
                let rv = request.headers.get::<$x>()
                    .expect("Missing header. Turn off use_proxy_headers or set proxy headers.")
                    .0.clone();
                assert!(request.headers.remove::<$x>());
                rv
            }}
        }
        let host = h!(XForwardedHost);
        let port = h!(XForwardedPort);
        let scheme = h!(XForwardedProto);
        let remote_addr = h!(XForwardedFor);

        // FIXME: https://github.com/iron/iron/pull/475
        let mut url = request.url.clone().into_generic_url();
        url.set_host(Some(&host)).unwrap();
        url.set_port(Some(port)).unwrap();
        url.set_scheme(&scheme).unwrap();

        request.url = iron::Url::from_generic_url(url).unwrap();
        request.remote_addr = remote_addr;
        Ok(())
    }
}

pub struct SecurityHeaderMiddleware;

impl iron::middleware::AfterMiddleware for SecurityHeaderMiddleware {
    fn after(&self, request: &mut Request, mut response: Response) -> IronResult<Response> {
        Self::set_security_headers(&request, &mut response);
        Ok(response)
    }

    fn catch(&self, request: &mut Request, mut error: IronError) -> IronResult<Response> {
        Self::set_security_headers(&request, &mut error.response);
        Err(error)
    }
}

impl SecurityHeaderMiddleware {
    fn set_security_headers(rq: &Request, r: &mut Response) {
        Self::set_cors_headers(rq, r);
        r.headers.set_raw("X-Content-Type-Options", vec![b"nosniff".to_vec()]);
        r.headers.set_raw("X-XSS-Protection", vec![b"1; mode=block".to_vec()]);

        let mut csp = vec!["default-src 'self'"];

        if rq.url.path()[0] != "storage" {
            // It's probably fine to embed user storage data into other documents

            // Prevent clickjacking attacks like described in OAuth RFC
            // https://tools.ietf.org/html/rfc6749#section-10.13
            r.headers.set_raw("X-Frame-Options", vec![b"DENY".to_vec()]);

            // This is a newer way to do what X-Frame-Options does
            // http://www.w3.org/TR/CSP11/#frame-ancestors-and-frame-options
            csp.push("frame-ancestors 'none'");
        };
        r.headers.set_raw("Content-Security-Policy", vec![csp.join(";").as_bytes().to_vec()]);
    }

    /// Required by remoteStorage spec
    fn set_cors_headers(rq: &Request, r: &mut Response) {
        match &rq.url.path()[0][..] {
            ".well-known" | "storage" => (),
            _ => return
        };

        let origin = match rq.headers.get_raw("Origin") {
            Some(x) => if x.len() == 1 {
                match String::from_utf8(x.to_owned().into_iter().next().unwrap()) {
                    Ok(x) => x,
                    Err(_) => return
                }
            } else {
                return;
            },
            None => return
        };

        r.headers.set(header::AccessControlAllowOrigin::Value(origin));
        r.headers.set(header::AccessControlExposeHeaders(vec![
            UniCase("ETag".to_owned()),
            UniCase("Content-Length".to_owned())
        ]));
        r.headers.set(header::AccessControlAllowMethods(vec![Method::Get, Method::Put, Method::Delete]));
        r.headers.set(header::AccessControlAllowHeaders(vec![
            UniCase("Authorization".to_owned()),
            UniCase("Content-Type".to_owned()),
            UniCase("Origin".to_owned()),
            UniCase("If-Match".to_owned()),
            UniCase("If-None-Match".to_owned()),
        ]));
    }
}

pub trait EtagMatcher {
    fn matches_etag(&self, given: Option<&str>) -> bool;
}

impl EtagMatcher for header::IfNoneMatch {
    fn matches_etag(&self, given: Option<&str>) -> bool {
        match *self {
            header::IfNoneMatch::Any => given.is_some(),
            header::IfNoneMatch::Items(ref values) => {
                match given {
                    Some(given_value) => values.iter().any(|val| val.tag() == &given_value[..]),
                    None => false
                }
            }
        }
    }
}

impl EtagMatcher for header::IfMatch {
    fn matches_etag(&self, given: Option<&str>) -> bool {
        match *self {
            header::IfMatch::Any => given.is_some(),
            header::IfMatch::Items(ref values) => {
                match given {
                    Some(given_value) => values.iter().any(|val| val.tag() == &given_value[..]),
                    None => false
                }
            }
        }
    }
}

pub fn preconditions_ok(request: &Request, etag: Option<&str>) -> bool {
    if let Some(header) = request.headers.get::<header::IfNoneMatch>() {
        if header.matches_etag(etag) {
            return false
        }
    };

    if let Some(header) = request.headers.get::<header::IfMatch>() {
        if !header.matches_etag(etag) {
            return false
        }
    };
    true
}

pub trait FormDataHelper<K: ?Sized, V> {
    fn get_only<Q: AsRef<K>>(&self, k: Q) -> Option<&String>;
}

impl FormDataHelper<str, String> for urlencoded::QueryMap {
    fn get_only<Q: AsRef<str>>(&self, k: Q) -> Option<&String> {
        match self.get(&k.as_ref().to_owned()) {
            Some(x) if x.len() == 1 => Some(&x[0]),
            _ => None
        }
    }
}

pub fn get_account_id(user: &models::User, request: &Request) -> String {
    // FIXME: https://github.com/iron/iron/pull/475
    let url = request.url.clone().into_generic_url();
    let netloc = &url[Position::BeforeHost..Position::AfterPort];
    format!("{}@{}", user.userid, netloc)
}
<commit_msg>Better errors<commit_after>use std::net::SocketAddr;

use hyper::header;
use hyper::method::Method;

use url::Position;

use urlencoded;

use unicase::UniCase;

use iron;
use iron::prelude::*;

use models;

header! { (XForwardedHost, "X-Forwarded-Host") => [String] }
header! { (XForwardedPort, "X-Forwarded-Port") => [u16] }
header! { (XForwardedProto, "X-Forwarded-Proto") => [String] }
header! { (XForwardedFor, "X-Forwarded-For") => [SocketAddr] }

pub struct XForwardedMiddleware;

impl iron::middleware::BeforeMiddleware for XForwardedMiddleware {
    fn before(&self, request: &mut Request) -> IronResult<()> {
        macro_rules! h {
            ($x:path, $n:expr) => {{
                // FIXME: https://github.com/hyperium/hyper/issues/891
                let rv = match request.headers.get::<$x>() {
                    Some(x) => x.0.clone(),
                    None => {
                        panic!("Missing header: {:?}. Turn off use_proxy_headers or set proxy headers.", $n);
                    }
                };
                assert!(request.headers.remove::<$x>());
                rv
            }}
        }
        let host = h!(XForwardedHost, "X-Forwarded-Host");
        let port = h!(XForwardedPort, "X-Forwarded-Port");
        let scheme = h!(XForwardedProto, "X-Forwarded-Proto");
        let remote_addr = h!(XForwardedFor, "X-Forwarded-For");

        // FIXME: https://github.com/iron/iron/pull/475
        let mut url = request.url.clone().into_generic_url();
        url.set_host(Some(&host)).unwrap();
        url.set_port(Some(port)).unwrap();
        url.set_scheme(&scheme).unwrap();

        request.url = iron::Url::from_generic_url(url).unwrap();
        request.remote_addr = remote_addr;
        Ok(())
    }
}

pub struct SecurityHeaderMiddleware;

impl iron::middleware::AfterMiddleware for SecurityHeaderMiddleware {
    fn after(&self, request: &mut Request, mut response: Response) -> IronResult<Response> {
        Self::set_security_headers(&request, &mut response);
        Ok(response)
    }

    fn catch(&self, request: &mut Request, mut error: IronError) -> IronResult<Response> {
        Self::set_security_headers(&request, &mut error.response);
        Err(error)
    }
}

impl SecurityHeaderMiddleware {
    fn set_security_headers(rq: &Request, r: &mut Response) {
        Self::set_cors_headers(rq, r);
        r.headers.set_raw("X-Content-Type-Options", vec![b"nosniff".to_vec()]);
        r.headers.set_raw("X-XSS-Protection", vec![b"1; mode=block".to_vec()]);

        let mut csp = vec!["default-src 'self'"];

        if rq.url.path()[0] != "storage" {
            // It's probably fine to embed user storage data into other documents

            // Prevent clickjacking attacks like described in OAuth RFC
            // https://tools.ietf.org/html/rfc6749#section-10.13
            r.headers.set_raw("X-Frame-Options", vec![b"DENY".to_vec()]);

            // This is a newer way to do what X-Frame-Options does
            // http://www.w3.org/TR/CSP11/#frame-ancestors-and-frame-options
            csp.push("frame-ancestors 'none'");
        };
        r.headers.set_raw("Content-Security-Policy", vec![csp.join(";").as_bytes().to_vec()]);
    }

    /// Required by remoteStorage spec
    fn set_cors_headers(rq: &Request, r: &mut Response) {
        match &rq.url.path()[0][..] {
            ".well-known" | "storage" => (),
            _ => return
        };

        let origin = match rq.headers.get_raw("Origin") {
            Some(x) => if x.len() == 1 {
                match String::from_utf8(x.to_owned().into_iter().next().unwrap()) {
                    Ok(x) => x,
                    Err(_) => return
                }
            } else {
                return;
            },
            None => return
        };

        r.headers.set(header::AccessControlAllowOrigin::Value(origin));
        r.headers.set(header::AccessControlExposeHeaders(vec![
            UniCase("ETag".to_owned()),
            UniCase("Content-Length".to_owned())
        ]));
        r.headers.set(header::AccessControlAllowMethods(vec![Method::Get, Method::Put, Method::Delete]));
        r.headers.set(header::AccessControlAllowHeaders(vec![
            UniCase("Authorization".to_owned()),
            UniCase("Content-Type".to_owned()),
            UniCase("Origin".to_owned()),
            UniCase("If-Match".to_owned()),
            UniCase("If-None-Match".to_owned()),
        ]));
    }
}

pub trait EtagMatcher {
    fn matches_etag(&self, given: Option<&str>) -> bool;
}

impl EtagMatcher for header::IfNoneMatch {
    fn matches_etag(&self, given: Option<&str>) -> bool {
        match *self {
            header::IfNoneMatch::Any => given.is_some(),
            header::IfNoneMatch::Items(ref values) => {
                match given {
                    Some(given_value) => values.iter().any(|val| val.tag() == &given_value[..]),
                    None => false
                }
            }
        }
    }
}

impl EtagMatcher for header::IfMatch {
    fn matches_etag(&self, given: Option<&str>) -> bool {
        match *self {
            header::IfMatch::Any => given.is_some(),
            header::IfMatch::Items(ref values) => {
                match given {
                    Some(given_value) => values.iter().any(|val| val.tag() == &given_value[..]),
                    None => false
                }
            }
        }
    }
}

pub fn preconditions_ok(request: &Request, etag: Option<&str>) -> bool {
    if let Some(header) = request.headers.get::<header::IfNoneMatch>() {
        if header.matches_etag(etag) {
            return false
        }
    };

    if let Some(header) = request.headers.get::<header::IfMatch>() {
        if !header.matches_etag(etag) {
            return false
        }
    };
    true
}

pub trait FormDataHelper<K: ?Sized, V> {
    fn get_only<Q: AsRef<K>>(&self, k: Q) -> Option<&String>;
}

impl FormDataHelper<str, String> for urlencoded::QueryMap {
    fn get_only<Q: AsRef<str>>(&self, k: Q) -> Option<&String> {
        match self.get(&k.as_ref().to_owned()) {
            Some(x) if x.len() == 1 => Some(&x[0]),
            _ => None
        }
    }
}

pub fn get_account_id(user: &models::User, request: &Request) -> String {
    // FIXME: https://github.com/iron/iron/pull/475
    let url = request.url.clone().into_generic_url();
    let netloc = &url[Position::BeforeHost..Position::AfterPort];
    format!("{}@{}", user.userid, netloc)
}
<|endoftext|>


<commit_before>use std::fmt;
use std::io;
use std::mem;
use std::ptr;

use winapi::shared::ntdef::HANDLE;
use winapi::um::handleapi::*;
use winapi::um::minwinbase::*;
use winapi::um::synchapi::*;

/// A wrapper around `OVERLAPPED` to provide "rustic" accessors and
/// initializers.
pub struct Overlapped(OVERLAPPED);

impl fmt::Debug for Overlapped {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "OVERLAPPED")
    }
}

unsafe impl Send for Overlapped {}
unsafe impl Sync for Overlapped {}

impl Overlapped {
    /// Creates a new zeroed out instance of an overlapped I/O tracking state.
    ///
    /// This is suitable for passing to methods which will then later get
    /// notified via an I/O Completion Port.
    pub fn zero() -> Overlapped {
        Overlapped(unsafe { mem::zeroed() })
    }

    /// Creates a new `Overlapped` with an initialized non-null `hEvent`.  The caller is
    /// responsible for calling `CloseHandle` on the `hEvent` field of the returned
    /// `Overlapped`.
    pub fn initialize_with_event() -> io::Result<Overlapped> {
        let event = unsafe {CreateEventW(ptr::null_mut(), 1i32, 0i32, ptr::null())};
        if event == INVALID_HANDLE_VALUE {
            return Err(io::Error::last_os_error());
        }
        let mut overlapped = Self::zero();
        overlapped.set_event(event);
        Ok(overlapped)
    }

    /// Creates a new `Overlapped` function pointer from the underlying
    /// `OVERLAPPED`, wrapping in the "rusty" wrapper for working with
    /// accessors.
    ///
    /// # Unsafety
    ///
    /// This function doesn't validate `ptr` nor the lifetime of the returned
    /// pointer at all, it's recommended to use this method with extreme
    /// caution.
    pub unsafe fn from_raw<'a>(ptr: *mut OVERLAPPED) -> &'a mut Overlapped {
        &mut *(ptr as *mut Overlapped)
    }

    /// Gain access to the raw underlying data
    pub fn raw(&self) -> *mut OVERLAPPED {
        &self.0 as *const _ as *mut _
    }

    /// Sets the offset inside this overlapped structure.
    ///
    /// Note that for I/O operations in general this only has meaning for I/O
    /// handles that are on a seeking device that supports the concept of an
    /// offset.
    pub fn set_offset(&mut self, offset: u64) {
        let s = unsafe { self.0.u.s_mut() };
        s.Offset = offset as u32;
        s.OffsetHigh = (offset >> 32) as u32;
    }

    /// Reads the offset inside this overlapped structure.
    pub fn offset(&self) -> u64 {
        let s = unsafe { self.0.u.s() };
        (s.Offset as u64) | ((s.OffsetHigh as u64) << 32)
    }

    /// Sets the `hEvent` field of this structure.
    ///
    /// The event specified can be null.
    pub fn set_event(&mut self, event: HANDLE) {
        self.0.hEvent = event;
    }

    /// Reads the `hEvent` field of this structure, may return null.
    pub fn event(&self) -> HANDLE {
        self.0.hEvent
    }
}
<commit_msg>NULL instead of INVALID_HANDLE for CreateEventW<commit_after>use std::fmt;
use std::io;
use std::mem;
use std::ptr;

use winapi::shared::ntdef::{
    HANDLE,
    NULL,
};
use winapi::um::handleapi::*;
use winapi::um::minwinbase::*;
use winapi::um::synchapi::*;

/// A wrapper around `OVERLAPPED` to provide "rustic" accessors and
/// initializers.
pub struct Overlapped(OVERLAPPED);

impl fmt::Debug for Overlapped {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "OVERLAPPED")
    }
}

unsafe impl Send for Overlapped {}
unsafe impl Sync for Overlapped {}

impl Overlapped {
    /// Creates a new zeroed out instance of an overlapped I/O tracking state.
    ///
    /// This is suitable for passing to methods which will then later get
    /// notified via an I/O Completion Port.
    pub fn zero() -> Overlapped {
        Overlapped(unsafe { mem::zeroed() })
    }

    /// Creates a new `Overlapped` with an initialized non-null `hEvent`.  The caller is
    /// responsible for calling `CloseHandle` on the `hEvent` field of the returned
    /// `Overlapped`.
    pub fn initialize_with_event() -> io::Result<Overlapped> {
        let event = unsafe {CreateEventW(ptr::null_mut(), 1i32, 0i32, ptr::null())};
        if event == NULL {
            return Err(io::Error::last_os_error());
        }
        let mut overlapped = Self::zero();
        overlapped.set_event(event);
        Ok(overlapped)
    }

    /// Creates a new `Overlapped` function pointer from the underlying
    /// `OVERLAPPED`, wrapping in the "rusty" wrapper for working with
    /// accessors.
    ///
    /// # Unsafety
    ///
    /// This function doesn't validate `ptr` nor the lifetime of the returned
    /// pointer at all, it's recommended to use this method with extreme
    /// caution.
    pub unsafe fn from_raw<'a>(ptr: *mut OVERLAPPED) -> &'a mut Overlapped {
        &mut *(ptr as *mut Overlapped)
    }

    /// Gain access to the raw underlying data
    pub fn raw(&self) -> *mut OVERLAPPED {
        &self.0 as *const _ as *mut _
    }

    /// Sets the offset inside this overlapped structure.
    ///
    /// Note that for I/O operations in general this only has meaning for I/O
    /// handles that are on a seeking device that supports the concept of an
    /// offset.
    pub fn set_offset(&mut self, offset: u64) {
        let s = unsafe { self.0.u.s_mut() };
        s.Offset = offset as u32;
        s.OffsetHigh = (offset >> 32) as u32;
    }

    /// Reads the offset inside this overlapped structure.
    pub fn offset(&self) -> u64 {
        let s = unsafe { self.0.u.s() };
        (s.Offset as u64) | ((s.OffsetHigh as u64) << 32)
    }

    /// Sets the `hEvent` field of this structure.
    ///
    /// The event specified can be null.
    pub fn set_event(&mut self, event: HANDLE) {
        self.0.hEvent = event;
    }

    /// Reads the `hEvent` field of this structure, may return null.
    pub fn event(&self) -> HANDLE {
        self.0.hEvent
    }
}
<|endoftext|>


<commit_before>use common::*;

mod rsa;

/// An installable package for Ox
pub struct Package {
    // TODO: Many of these uses String where other types can be used (when integreting with octavo)
    /// The host (where the package can be found)
    pub host: String,
    /// The name of this package
    pub name: String,
    /// The version of this package
    pub version: String,
    /// Description
    pub desc: String,
    //    /// The developer's public key
    //    pub dev: String,
    //    /// The developer's signature of this package
    //    pub dev_signature: String,
    //    /// Signatures of the developers public key from people who trusts the developers.
    //    pub trust: Vec<String>,
    //    /// The signatures of this package
    //    pub signatures: Vec<String>,
    /// The files this package will create on the computer.
    pub files: Vec<String>,
}

pub fn get_package(host: String, name: String, version: String) -> Package {
    let con = File::open("tcp://".to_string() + host);

    con.write("GET /ox/".to_string() + version + "-".to_string() + name + " HTTP/1.1".to_string());

    let resp;

    {
        let res = Vec::new();
        con.read_to_end(&mut res);

        resp = String::from_utf8(&res).split("\n".to_string());
    }

    let mut name = "".to_string();
    let mut desc = "".to_string();
    let mut host = "".to_string();
    let mut files = "".to_string();
    let mut version = "".to_string();

    for i in resp {
        let data = i.substr(5, i.len() - 5);
        let key = i.substr(0, 4);

        if key == "name".to_string() {
            name = data;
        } else if key == "desc".to_string() {
            desc = data;
        } else if key == "host".to_string() {
            host = data;
        } else if key == "file".to_string() {
            files = data;
        } else if key == "vers".to_string() {
            version = data;
        }
    }

    Package {
        host: host,
        name: name,
        desc: desc,
        files: files.split(",".to_string()).collect::<Vec<_>>(),
        version: version,
    }
}
<commit_msg>Small changes<commit_after>use common::*;

mod rsa;

/// An installable package for Ox
pub struct Package {
    // TODO: Many of these uses String where other types can be used (when integreting with octavo)
    /// The host (where the package can be found)
    pub host: String,
    /// The name of this package
    pub name: String,
    /// The version of this package
    pub version: String,
    /// Description
    pub desc: String,
    //    /// The developer's public key
    //    pub dev: String,
    //    /// The developer's signature of this package
    //    pub dev_signature: String,
    //    /// Signatures of the developers public key from people who trusts the developers.
    //    // TODO: Move this to other file
    //    pub trust: Vec<String>,
    //    /// The signatures of this package
    //    pub signatures: Vec<String>,
    /// The files this package will create on the computer.
    pub files: Vec<String>,
}

pub fn get_package(host: String, name: String, version: String) -> Package {
    let con = File::open("tcp://".to_string() + host);

    con.write("GET /ox/".to_string() + version + "-".to_string() + name + " HTTP/1.1".to_string());

    let resp;

    {
        let res = Vec::new();
        con.read_to_end(&mut res);

        resp = String::from_utf8(&res).split("\n".to_string());
    }

    let mut name = "".to_string();
    let mut desc = "".to_string();
    let mut host = "".to_string();
    let mut files = "".to_string();
    let mut version = "".to_string();

    for i in resp {
        let data = i.substr(5, i.len() - 5);
        let key = i.substr(0, 4);

        if key == "name".to_string() {
            name = data;
        } else if key == "desc".to_string() {
            desc = data;
        } else if key == "host".to_string() {
            host = data;
        } else if key == "file".to_string() {
            files = data;
        } else if key == "vers".to_string() {
            version = data;
        }
    }

    Package {
        host: host,
        name: name,
        desc: desc,
        files: files.split(",".to_string()).collect::<Vec<_>>(),
        version: version,
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 David Stainton <dstainton415@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! TCP packet abstraction

use packet::Packet;
use packet::ip::IpNextHeaderProtocol;

use pnet_macros::types::*;

use std::net::{Ipv4Addr, Ipv6Addr};

/// Represents a TCP Packet
#[packet]
pub struct Tcp {
    source: u16be,
    destination: u16be,
    #[payload]
    payload: Vec<u8>
}

#[test]
fn tcp_header_ipv4_test() {
    use pnet::packet::ip::IpNextHeaderProtocols;
    use pnet::packet::ipv4::MutableIpv4Packet;

    let mut packet = [0u8; 20 + 8 + 4];
    let ipv4_source = Ipv4Addr::new(192, 168, 0, 1);
    let ipv4_destination = Ipv4Addr::new(192, 168, 0, 199);
    let next_level_protocol = IpNextHeaderProtocols::Tcp;
    {
        let mut ip_header = MutableIpv4Packet::new(&mut packet[..]).unwrap();
        ip_header.set_next_level_protocol(next_level_protocol);
        ip_header.set_source(ipv4_source);
        ip_header.set_destination(ipv4_destination);
    }

    // Set data
    packet[20 + 8 + 0] = 't' as u8;
    packet[20 + 8 + 1] = 'e' as u8;
    packet[20 + 8 + 2] = 's' as u8;
    packet[20 + 8 + 3] = 't' as u8;

    {
        let mut tcp_header = MutableTcpPacket::new(&mut packet[20..]).unwrap();
        tcp_header.set_source(12345);
        assert_eq!(tcp_header.get_source(), 12345);

        tcp_header.set_destination(54321);
        assert_eq!(tcp_header.get_destination(), 54321);

    }

    let ref_packet = [0x30, 0x39, /* source */
                     0xd4, 0x31];  /* destination */
    assert_eq!(&ref_packet[..], &packet[20 .. 24]);
}

#[test]
fn tcp_header_ipv6_test() {
    use packet::ip::{IpNextHeaderProtocols};
    use packet::ipv6::{MutableIpv6Packet};

    let mut packet = [0u8; 40 + 8 + 4];
    let next_header = IpNextHeaderProtocols::Tcp;
    let ipv6_source = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
    let ipv6_destination = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
    {
        let mut ip_header = MutableIpv6Packet::new(&mut packet[..]).unwrap();
        ip_header.set_next_header(next_header);
        ip_header.set_source(ipv6_source);
        ip_header.set_destination(ipv6_destination);
    }

    // Set data
    packet[40 + 8 + 0] = 't' as u8;
    packet[40 + 8 + 1] = 'e' as u8;
    packet[40 + 8 + 2] = 's' as u8;
    packet[40 + 8 + 3] = 't' as u8;

    {
        let mut tcp_header = MutableTcpPacket::new(&mut packet[40..]).unwrap();
        tcp_header.set_source(12345);
        assert_eq!(tcp_header.get_source(), 12345);

        tcp_header.set_destination(54321);
        assert_eq!(tcp_header.get_destination(), 54321);
    }

    let ref_packet = [0x30, 0x39,  /* source */
                     0xd4, 0x31];  /* destination */
    assert_eq!(&ref_packet[..], &packet[40 .. 44]);
}
<commit_msg>Add sequence and acknowledgement fields<commit_after>// Copyright (c) 2015 David Stainton <dstainton415@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! TCP packet abstraction

use packet::Packet;
use packet::ip::IpNextHeaderProtocol;

use pnet_macros::types::*;

use std::net::{Ipv4Addr, Ipv6Addr};

/// Represents a TCP Packet
#[packet]
pub struct Tcp {
    source: u16be,
    destination: u16be,
    sequence: u32be,
    acknowledgement: u32be,
    #[payload]
    payload: Vec<u8>
}

#[test]
fn tcp_header_ipv4_test() {
    use pnet::packet::ip::IpNextHeaderProtocols;
    use pnet::packet::ipv4::MutableIpv4Packet;

    const IPV4_HEADER_LEN: usize = 20;
    const TCP_HEADER_LEN: usize = 12;
    const PAYLOAD_LEN: usize = 4;

    let mut packet = [0u8; IPV4_HEADER_LEN + TCP_HEADER_LEN + PAYLOAD_LEN];

    let ipv4_source = Ipv4Addr::new(192, 168, 0, 1);
    let ipv4_destination = Ipv4Addr::new(192, 168, 0, 199);
    let next_level_protocol = IpNextHeaderProtocols::Tcp;
    {
        let mut ip_header = MutableIpv4Packet::new(&mut packet[..]).unwrap();
        ip_header.set_next_level_protocol(next_level_protocol);
        ip_header.set_source(ipv4_source);
        ip_header.set_destination(ipv4_destination);
    }

    // Set data
    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 0] = 't' as u8;
    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 1] = 'e' as u8;
    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 2] = 's' as u8;
    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 3] = 't' as u8;

    {
        let mut tcp_header = MutableTcpPacket::new(&mut packet[20..]).unwrap();
        tcp_header.set_source(12345);
        assert_eq!(tcp_header.get_source(), 12345);

        tcp_header.set_destination(54321);
        assert_eq!(tcp_header.get_destination(), 54321);

        tcp_header.set_sequence(3456);
        assert_eq!(tcp_header.get_sequence(), 3456);

        tcp_header.set_acknowledgement(7799);
        assert_eq!(tcp_header.get_acknowledgement(), 7799);
    }

    let ref_packet = [0x30, 0x39,  // source
                      0xd4, 0x31,  // destination
                      0x00, 0x00,  // sequence
                      0x0d, 0x80,
                      0x00, 0x00,  // acknowledgement
                      0x1e, 0x77];

    assert_eq!(&ref_packet[..], &packet[IPV4_HEADER_LEN .. IPV4_HEADER_LEN + TCP_HEADER_LEN]);
}

#[test]
fn tcp_header_ipv6_test() {
    use packet::ip::{IpNextHeaderProtocols};
    use packet::ipv6::{MutableIpv6Packet};

    const IPV6_HEADER_LEN: usize = 40;
    const TCP_HEADER_LEN: usize = 12;
    const PAYLOAD_LEN: usize = 4;

    let mut packet = [0u8; IPV6_HEADER_LEN + TCP_HEADER_LEN + PAYLOAD_LEN];

    let next_header = IpNextHeaderProtocols::Tcp;
    let ipv6_source = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
    let ipv6_destination = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
    {
        let mut ip_header = MutableIpv6Packet::new(&mut packet[..]).unwrap();
        ip_header.set_next_header(next_header);
        ip_header.set_source(ipv6_source);
        ip_header.set_destination(ipv6_destination);
    }

    // Set data
    packet[IPV6_HEADER_LEN + TCP_HEADER_LEN + 0] = 't' as u8;
    packet[IPV6_HEADER_LEN + TCP_HEADER_LEN + 1] = 'e' as u8;
    packet[IPV6_HEADER_LEN + TCP_HEADER_LEN + 2] = 's' as u8;
    packet[IPV6_HEADER_LEN + TCP_HEADER_LEN + 3] = 't' as u8;

    {
        let mut tcp_header = MutableTcpPacket::new(&mut packet[IPV6_HEADER_LEN..]).unwrap();
        tcp_header.set_source(12345);
        assert_eq!(tcp_header.get_source(), 12345);

        tcp_header.set_destination(54321);
        assert_eq!(tcp_header.get_destination(), 54321);

        tcp_header.set_sequence(3456);
        assert_eq!(tcp_header.get_sequence(), 3456);

        tcp_header.set_acknowledgement(7799);
        assert_eq!(tcp_header.get_acknowledgement(), 7799);
    }

    let ref_packet = [0x30, 0x39,  // source
                      0xd4, 0x31,  // destination
                      0x00, 0x00,  // sequence
                      0x0d, 0x80,
                      0x00, 0x00,  // acknowledgement
                      0x1e, 0x77];

    assert_eq!(&ref_packet[..], &packet[IPV6_HEADER_LEN .. IPV6_HEADER_LEN + TCP_HEADER_LEN]);
}
<|endoftext|>


<commit_before>//! The parser module is responsible for parsing FITS files.

use std::str;
use std::str::FromStr;
use nom::{is_alphanumeric};
use super::types::{Fits, PrimaryHeader, KeywordRecord, Keyword, BlankRecord};

named!(fits<&[u8], Fits>,
       do_parse!(
           ph: primary_header >>
               many0!(take!(2880)) >>
               (Fits::new(ph))
       ));

named!(primary_header<&[u8], PrimaryHeader>,
       do_parse!(
           records: many0!(keyword_record) >>
               end_record >>
               many0!(blank_record) >>
               (PrimaryHeader::new(records))
       ));

named!(keyword_record<&[u8], KeywordRecord>,
       do_parse!(
           key: keyword  >>
               tag!("= ") >>
               take!(70) >>
               (KeywordRecord::new(key))
       ));

named!(keyword<&[u8], Keyword>,
       map_res!(
           map_res!(
               take!(8),
               str::from_utf8),
           Keyword::from_str
       ));

named!(valuecomment<&[u8], (&[u8],Option<&[u8]>)>,
       flat_map!(
           take!(70),
           pair!(
               value,
               opt!(comment)
           )));

named!(value<&[u8], &[u8]>,
       is_not!("/") // TODO Differentiate on the possible value types
);

named!(comment<&[u8], &[u8]>,
       do_parse!(
           tag!("/") >>
               comment: take_while!(is_comment_character) >>
               (comment)
       ));

fn is_comment_character(chr: u8) -> bool {
    32u8 <= chr && chr <= 126u8
}

named!(end_record<&[u8], Keyword>,
       map!(
           flat_map!(
               take!(80),
               pair!(tag!("END"), many0!(tag!(" ")))
           ),
           |_| { Keyword::END }
       ));

named!(blank_record<&[u8], BlankRecord>,
       map!(
           count!(tag!(" "), 80),
           |_| { BlankRecord }
       ));

#[cfg(test)]
mod tests {
    use nom::{IResult};
    use super::super::types::{Fits, PrimaryHeader, KeywordRecord, Keyword, BlankRecord};
    use super::{fits, primary_header, keyword_record, keyword, valuecomment, end_record, blank_record};

    #[test]
    fn it_should_parse_a_fits_file(){
        let data = include_bytes!("../../assets/images/k2-trappist1-unofficial-tpf-long-cadence.fits");

        let result = fits(data);

        match result {
            IResult::Done(_, f) => {
                assert_eq!(f, Fits::new(long_cadence_header()));
            },
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }

    #[test]
    fn primary_header_should_parse_a_primary_header(){
        let data = include_bytes!("../../assets/images/k2-trappist1-unofficial-tpf-long-cadence.fits");

        let result = primary_header(&data[0..(2*2880)]);

        match result {
            IResult::Done(_, h) => assert_eq!(h, long_cadence_header()),
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }

    fn long_cadence_header() -> PrimaryHeader {
        PrimaryHeader::new(vec!(
            KeywordRecord::new(Keyword::SIMPLE),
            KeywordRecord::new(Keyword::BITPIX),
            KeywordRecord::new(Keyword::NAXIS),
            KeywordRecord::new(Keyword::EXTEND),
            KeywordRecord::new(Keyword::NEXTEND),
            KeywordRecord::new(Keyword::EXTNAME),
            KeywordRecord::new(Keyword::EXTVER),
            KeywordRecord::new(Keyword::ORIGIN),
            KeywordRecord::new(Keyword::DATE),
            KeywordRecord::new(Keyword::CREATOR),
            KeywordRecord::new(Keyword::PROCVER),
            KeywordRecord::new(Keyword::FILEVER),
            KeywordRecord::new(Keyword::TIMVERSN),
            KeywordRecord::new(Keyword::TELESCOP),
            KeywordRecord::new(Keyword::INSTRUME),
            KeywordRecord::new(Keyword::OBJECT),
            KeywordRecord::new(Keyword::KEPLERID),
            KeywordRecord::new(Keyword::CHANNEL),
            KeywordRecord::new(Keyword::MODULE),
            KeywordRecord::new(Keyword::OUTPUT),
            KeywordRecord::new(Keyword::CAMPAIGN),
            KeywordRecord::new(Keyword::DATA_REL),
            KeywordRecord::new(Keyword::OBSMODE),
            KeywordRecord::new(Keyword::MISSION),
            KeywordRecord::new(Keyword::TTABLEID),
            KeywordRecord::new(Keyword::RADESYS),
            KeywordRecord::new(Keyword::RA_OBJ),
            KeywordRecord::new(Keyword::DEC_OBJ),
            KeywordRecord::new(Keyword::EQUINOX),
            KeywordRecord::new(Keyword::PMRA),
            KeywordRecord::new(Keyword::PMDEC),
            KeywordRecord::new(Keyword::PMTOTAL),
            KeywordRecord::new(Keyword::PARALLAX),
            KeywordRecord::new(Keyword::GLON),
            KeywordRecord::new(Keyword::GLAT),
            KeywordRecord::new(Keyword::GMAG),
            KeywordRecord::new(Keyword::RMAG),
            KeywordRecord::new(Keyword::IMAG),
            KeywordRecord::new(Keyword::ZMAG),
            KeywordRecord::new(Keyword::JMAG),
            KeywordRecord::new(Keyword::HMAG),
            KeywordRecord::new(Keyword::KMAG),
            KeywordRecord::new(Keyword::KEPMAG),
            KeywordRecord::new(Keyword::GRCOLOR),
            KeywordRecord::new(Keyword::JKCOLOR),
            KeywordRecord::new(Keyword::GKCOLOR),
            KeywordRecord::new(Keyword::TEFF),
            KeywordRecord::new(Keyword::LOGG),
            KeywordRecord::new(Keyword::FEH),
            KeywordRecord::new(Keyword::EBMINUSV),
            KeywordRecord::new(Keyword::AV),
            KeywordRecord::new(Keyword::RADIUS),
            KeywordRecord::new(Keyword::TMINDEX),
            KeywordRecord::new(Keyword::CHECKSUM),
            KeywordRecord::new(Keyword::DATASUM),
        ))
    }

    #[test]
    fn keyword_record_should_parse_a_keyword_record(){
        let data = "OBJECT  = 'EPIC 200164267'     / string version of target id                    "
            .as_bytes();

        let result = keyword_record(data);

        match result {
            IResult::Done(_,k) => assert_eq!(k, KeywordRecord::new(Keyword::OBJECT)),
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }

    #[test]
    fn valuecomment_should_parse_a_valuecomment(){
        let data = "'EPIC 200164267'     / string version of target id                    "
            .as_bytes();

        let result = valuecomment(data);

        match result {
            IResult::Done(_, (value, comment)) => {
                assert_eq!(value, &b"'EPIC 200164267'     "[..]);
                assert_eq!(comment, Option::Some(&b" string version of target id                    "[..]));
            },
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }

    #[test]
    fn keyword_should_parse_a_keyword(){
        let data = "OBJECT  "
            .as_bytes();

        let result = keyword(data);

        match result {
            IResult::Done(_, keyword) => assert_eq!(keyword, Keyword::OBJECT),
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }

    #[test]
    fn end_record_should_parse_an_END_record(){
        let data = "END                                                                             "
            .as_bytes();

        let result = end_record(data);

        match result {
            IResult::Done(_, keyword) => assert_eq!(keyword, Keyword::END),
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }

    #[test]
    fn blank_record_should_parse_a_BLANK_record(){
        let data = "                                                                                "
            .as_bytes();

        let result = blank_record(data);

        match result {
            IResult::Done(_, record) => assert_eq!(record, BlankRecord),
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }
}
<commit_msg>Make valuecomment return a &str and Option<&str> tuple<commit_after>//! The parser module is responsible for parsing FITS files.

use std::str;
use std::str::FromStr;
use nom::{is_alphanumeric};
use super::types::{Fits, PrimaryHeader, KeywordRecord, Keyword, BlankRecord};

named!(fits<&[u8], Fits>,
       do_parse!(
           ph: primary_header >>
               many0!(take!(2880)) >>
               (Fits::new(ph))
       ));

named!(primary_header<&[u8], PrimaryHeader>,
       do_parse!(
           records: many0!(keyword_record) >>
               end_record >>
               many0!(blank_record) >>
               (PrimaryHeader::new(records))
       ));

named!(keyword_record<&[u8], KeywordRecord>,
       do_parse!(
           key: keyword  >>
               tag!("= ") >>
               take!(70) >>
               (KeywordRecord::new(key))
       ));

named!(keyword<&[u8], Keyword>,
       map_res!(
           map_res!(
               take!(8),
               str::from_utf8),
           Keyword::from_str
       ));

named!(valuecomment<&[u8], (&str, Option<&str>)>,
       flat_map!(
           take!(70),
           pair!(
               value,
               opt!(comment)
           )));

named!(value<&[u8], &str>,
       map_res!(
           is_not!("/"), // TODO Differentiate on the possible value types
           str::from_utf8
       )
);

named!(comment<&[u8], &str>,
       map_res!(
           do_parse!(
               tag!("/") >>
                   comment: take_while!(is_comment_character) >>
                   (comment)
           ),
           str::from_utf8
       ));

fn is_comment_character(chr: u8) -> bool {
    32u8 <= chr && chr <= 126u8
}

named!(end_record<&[u8], Keyword>,
       map!(
           flat_map!(
               take!(80),
               pair!(tag!("END"), many0!(tag!(" ")))
           ),
           |_| { Keyword::END }
       ));

named!(blank_record<&[u8], BlankRecord>,
       map!(
           count!(tag!(" "), 80),
           |_| { BlankRecord }
       ));

#[cfg(test)]
mod tests {
    use nom::{IResult};
    use super::super::types::{Fits, PrimaryHeader, KeywordRecord, Keyword, BlankRecord};
    use super::{fits, primary_header, keyword_record, keyword, valuecomment, end_record, blank_record};

    #[test]
    fn it_should_parse_a_fits_file(){
        let data = include_bytes!("../../assets/images/k2-trappist1-unofficial-tpf-long-cadence.fits");

        let result = fits(data);

        match result {
            IResult::Done(_, f) => {
                assert_eq!(f, Fits::new(long_cadence_header()));
            },
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }

    #[test]
    fn primary_header_should_parse_a_primary_header(){
        let data = include_bytes!("../../assets/images/k2-trappist1-unofficial-tpf-long-cadence.fits");

        let result = primary_header(&data[0..(2*2880)]);

        match result {
            IResult::Done(_, h) => assert_eq!(h, long_cadence_header()),
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }

    fn long_cadence_header() -> PrimaryHeader {
        PrimaryHeader::new(vec!(
            KeywordRecord::new(Keyword::SIMPLE),
            KeywordRecord::new(Keyword::BITPIX),
            KeywordRecord::new(Keyword::NAXIS),
            KeywordRecord::new(Keyword::EXTEND),
            KeywordRecord::new(Keyword::NEXTEND),
            KeywordRecord::new(Keyword::EXTNAME),
            KeywordRecord::new(Keyword::EXTVER),
            KeywordRecord::new(Keyword::ORIGIN),
            KeywordRecord::new(Keyword::DATE),
            KeywordRecord::new(Keyword::CREATOR),
            KeywordRecord::new(Keyword::PROCVER),
            KeywordRecord::new(Keyword::FILEVER),
            KeywordRecord::new(Keyword::TIMVERSN),
            KeywordRecord::new(Keyword::TELESCOP),
            KeywordRecord::new(Keyword::INSTRUME),
            KeywordRecord::new(Keyword::OBJECT),
            KeywordRecord::new(Keyword::KEPLERID),
            KeywordRecord::new(Keyword::CHANNEL),
            KeywordRecord::new(Keyword::MODULE),
            KeywordRecord::new(Keyword::OUTPUT),
            KeywordRecord::new(Keyword::CAMPAIGN),
            KeywordRecord::new(Keyword::DATA_REL),
            KeywordRecord::new(Keyword::OBSMODE),
            KeywordRecord::new(Keyword::MISSION),
            KeywordRecord::new(Keyword::TTABLEID),
            KeywordRecord::new(Keyword::RADESYS),
            KeywordRecord::new(Keyword::RA_OBJ),
            KeywordRecord::new(Keyword::DEC_OBJ),
            KeywordRecord::new(Keyword::EQUINOX),
            KeywordRecord::new(Keyword::PMRA),
            KeywordRecord::new(Keyword::PMDEC),
            KeywordRecord::new(Keyword::PMTOTAL),
            KeywordRecord::new(Keyword::PARALLAX),
            KeywordRecord::new(Keyword::GLON),
            KeywordRecord::new(Keyword::GLAT),
            KeywordRecord::new(Keyword::GMAG),
            KeywordRecord::new(Keyword::RMAG),
            KeywordRecord::new(Keyword::IMAG),
            KeywordRecord::new(Keyword::ZMAG),
            KeywordRecord::new(Keyword::JMAG),
            KeywordRecord::new(Keyword::HMAG),
            KeywordRecord::new(Keyword::KMAG),
            KeywordRecord::new(Keyword::KEPMAG),
            KeywordRecord::new(Keyword::GRCOLOR),
            KeywordRecord::new(Keyword::JKCOLOR),
            KeywordRecord::new(Keyword::GKCOLOR),
            KeywordRecord::new(Keyword::TEFF),
            KeywordRecord::new(Keyword::LOGG),
            KeywordRecord::new(Keyword::FEH),
            KeywordRecord::new(Keyword::EBMINUSV),
            KeywordRecord::new(Keyword::AV),
            KeywordRecord::new(Keyword::RADIUS),
            KeywordRecord::new(Keyword::TMINDEX),
            KeywordRecord::new(Keyword::CHECKSUM),
            KeywordRecord::new(Keyword::DATASUM),
        ))
    }

    #[test]
    fn keyword_record_should_parse_a_keyword_record(){
        let data = "OBJECT  = 'EPIC 200164267'     / string version of target id                    "
            .as_bytes();

        let result = keyword_record(data);

        match result {
            IResult::Done(_,k) => assert_eq!(k, KeywordRecord::new(Keyword::OBJECT)),
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }

    #[test]
    fn valuecomment_should_parse_a_valuecomment(){
        let data = "'EPIC 200164267'     / string version of target id                    "
            .as_bytes();

        let result = valuecomment(data);

        match result {
            IResult::Done(_, (value, comment)) => {
                assert_eq!(value, "'EPIC 200164267'     ");
                assert_eq!(comment, Option::Some(" string version of target id                    "));
            },
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }

    #[test]
    fn keyword_should_parse_a_keyword(){
        let data = "OBJECT  "
            .as_bytes();

        let result = keyword(data);

        match result {
            IResult::Done(_, keyword) => assert_eq!(keyword, Keyword::OBJECT),
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }

    #[test]
    fn end_record_should_parse_an_END_record(){
        let data = "END                                                                             "
            .as_bytes();

        let result = end_record(data);

        match result {
            IResult::Done(_, keyword) => assert_eq!(keyword, Keyword::END),
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }

    #[test]
    fn blank_record_should_parse_a_BLANK_record(){
        let data = "                                                                                "
            .as_bytes();

        let result = blank_record(data);

        match result {
            IResult::Done(_, record) => assert_eq!(record, BlankRecord),
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }
}
<|endoftext|>


<commit_before>//! # Command Parser
//!
//! The `commands::parser` module provides:
//!
//! * Functionality for building a tree of commands based on their names.
//! * Parsing tokenized input to select a command. Input tokenization can
//!   be performed by the `commands::tokenizer` module.
//! * Validating parameters.
//! * Performing completion on commands and parameters.
//!
//! The parser is still a work in progress but is rapidly advancing.

pub mod nodes;
pub mod completion;

use std::collections::HashMap;
use std::rc::Rc;
use parser::nodes::*;
use tokenizer::{Token, TokenType};
use parser::completion::{Complete, Completion};

/// Command parser
///
/// The lifetime parameter `'p` refers to the lifetime of the
/// root node of the command tree that was used to create this
/// parser.
///
/// The lifetime parameter `'p` refers to the lifetime of the parser
/// and of the tokens passed into this parser.
pub struct Parser<'p> {
    current_node: &'p Rc<Node>,
    /// The nodes which have been accepted during `parse` or `advance`.
    pub nodes: Vec<&'p Rc<Node>>,
    /// The tokens which have been accepted during `parse` or `advance`.
    pub tokens: Vec<&'p Token<'p>>,
    commands: Vec<&'p Rc<CommandNode>>,
    parameters: HashMap<String, String>,
}

impl<'p> Parser<'p> {
    /// Construct a parser with a root node.
    pub fn new(initial_node: &'p Rc<Node>) -> Parser<'p> {
        Parser {
            current_node: initial_node,
            nodes: vec![],
            tokens: vec![],
            commands: vec![],
            parameters: HashMap::new(),
        }
    }

    /// Given an optional token, get the possible valid completions
    /// for the current parser state.
    pub fn complete(&self, token: Option<&'p Token<'p>>) -> Vec<Completion> {
        fn possible_completion(node: &Rc<Node>, parser: &Parser, token: Option<&Token>) -> bool {
            // To be a possible completion, the node should not be
            // hidden, it should be acceptable, and if there's a token,
            // it should be a valid match for the node.
            !node.hidden() && node.acceptable(parser) &&
            match token {
                Some(t) => node.matches(parser, t),
                _ => true,
            }
        }
        self.current_node
            .successors()
            .into_iter()
            .filter(|n| possible_completion(n, self, token))
            .map(|n| n.complete(token))
            .collect::<Vec<_>>()
    }

    /// Parse a vector of tokens, advancing through the
    /// node hierarchy.
    pub fn parse(&mut self, tokens: Vec<&'p Token<'p>>) {
        for token in tokens {
            match token.token_type {
                TokenType::Invalid => unreachable!(),
                TokenType::Whitespace => {}
                TokenType::Word => self.advance(token),
            }
        }
    }

    /// Parse a single token, advancing through the node hierarchy.
    pub fn advance(&mut self, token: &'p Token<'p>) {
        let matches = self.current_node
                          .successors()
                          .into_iter()
                          .filter(|n| n.acceptable(self) && n.matches(self, token))
                          .collect::<Vec<_>>();
        match matches.len() {
            1 => {
                let matching_node = &matches[0];
                matching_node.accept(self, token);
                self.current_node = matching_node.clone();
                self.nodes.push(matching_node);
                self.tokens.push(token);
            }
            0 => panic!("No matches for '{}'.", token.text),
            _ => panic!("Ambiguous matches for '{}'.", token.text),
        }
    }

    /// Execute the command that has been accepted by the parser.
    ///
    /// * XXX: This should be returning a Result probably.
    pub fn execute(&self) {
        if !self.commands.is_empty() {
            unimplemented!();
            // self.commands[0].execute(self)
        }
    }

    /// Verify that the parser is in a valid state with
    /// respect to having accepted a command and all
    /// required parameters.
    ///
    /// * XXX: This should be returning Option or Result
    ///        with an enum for the various error conditions.
    pub fn verify(&self) -> bool {
        if self.commands.is_empty() {
            // XXX: We'll want an enum error here with a Result.
            return false;
        } else {
            for expected in self.commands[0].parameters() {
                if expected.required() && !self.parameters.contains_key(expected.name()) {
                    return false;
                }
            }
        }
        true
    }
}

trait Acceptable {
    fn acceptable(&self, parser: &Parser) -> bool;
}

impl Acceptable for Node {
    fn acceptable(&self, _parser: &Parser) -> bool {
        unimplemented!();
        // !parser.nodes.contains(self)
    }
}

impl Acceptable for RepeatableNode {
    fn acceptable(&self, _parser: &Parser) -> bool {
        if self.repeatable() {
            return true;
        }
        unimplemented!()
        // This should check nodes.contains, but then go on to check
        // for a repeat marker and whether or not that's been seen.
    }
}

trait Matches {
    fn matches(&self, parser: &Parser, token: &Token) -> bool;
}

impl Matches for Node {
    fn matches(&self, _parser: &Parser, token: &Token) -> bool {
        self.name().starts_with(token.text)
    }
}

trait Accept {
    fn accept<'p>(&'p self, parser: &mut Parser<'p>, token: &Token);
}

impl Accept for Node {
    fn accept<'p>(&'p self, _parser: &mut Parser<'p>, _token: &Token) {}
}

impl Accept for Rc<CommandNode> {
    fn accept<'p>(&'p self, parser: &mut Parser<'p>, _token: &Token) {
        if let Some(_) = self.handler() {
            parser.commands.push(self)
        }
    }
}

impl Accept for Rc<ParameterNode> {
    fn accept<'p>(&'p self, parser: &mut Parser<'p>, token: &Token) {
        if self.repeatable() {
            unimplemented!();
        } else {
            parser.parameters.insert(self.name().clone(), token.text.to_string());
        }
    }
}
<commit_msg>Parser: Simplify complete: Remove local function.<commit_after>//! # Command Parser
//!
//! The `commands::parser` module provides:
//!
//! * Functionality for building a tree of commands based on their names.
//! * Parsing tokenized input to select a command. Input tokenization can
//!   be performed by the `commands::tokenizer` module.
//! * Validating parameters.
//! * Performing completion on commands and parameters.
//!
//! The parser is still a work in progress but is rapidly advancing.

pub mod nodes;
pub mod completion;

use std::collections::HashMap;
use std::rc::Rc;
use parser::nodes::*;
use tokenizer::{Token, TokenType};
use parser::completion::{Complete, Completion};

/// Command parser
///
/// The lifetime parameter `'p` refers to the lifetime of the
/// root node of the command tree that was used to create this
/// parser.
///
/// The lifetime parameter `'p` refers to the lifetime of the parser
/// and of the tokens passed into this parser.
pub struct Parser<'p> {
    current_node: &'p Rc<Node>,
    /// The nodes which have been accepted during `parse` or `advance`.
    pub nodes: Vec<&'p Rc<Node>>,
    /// The tokens which have been accepted during `parse` or `advance`.
    pub tokens: Vec<&'p Token<'p>>,
    commands: Vec<&'p Rc<CommandNode>>,
    parameters: HashMap<String, String>,
}

impl<'p> Parser<'p> {
    /// Construct a parser with a root node.
    pub fn new(initial_node: &'p Rc<Node>) -> Parser<'p> {
        Parser {
            current_node: initial_node,
            nodes: vec![],
            tokens: vec![],
            commands: vec![],
            parameters: HashMap::new(),
        }
    }

    /// Given an optional token, get the possible valid completions
    /// for the current parser state.
    pub fn complete(&self, token: Option<&'p Token<'p>>) -> Vec<Completion> {
        self.current_node
            .successors()
            .into_iter()
            .filter(|n| {
                // To be a possible completion, the node should not be
                // hidden, it should be acceptable, and if there's a token,
                // it should be a valid match for the node.
                !n.hidden() && n.acceptable(self) &&
                match token {
                    Some(t) => n.matches(self, t),
                    _ => true,
                }
            })
            .map(|n| n.complete(token))
            .collect::<Vec<_>>()
    }

    /// Parse a vector of tokens, advancing through the
    /// node hierarchy.
    pub fn parse(&mut self, tokens: Vec<&'p Token<'p>>) {
        for token in tokens {
            match token.token_type {
                TokenType::Invalid => unreachable!(),
                TokenType::Whitespace => {}
                TokenType::Word => self.advance(token),
            }
        }
    }

    /// Parse a single token, advancing through the node hierarchy.
    pub fn advance(&mut self, token: &'p Token<'p>) {
        let matches = self.current_node
                          .successors()
                          .into_iter()
                          .filter(|n| n.acceptable(self) && n.matches(self, token))
                          .collect::<Vec<_>>();
        match matches.len() {
            1 => {
                let matching_node = &matches[0];
                matching_node.accept(self, token);
                self.current_node = matching_node.clone();
                self.nodes.push(matching_node);
                self.tokens.push(token);
            }
            0 => panic!("No matches for '{}'.", token.text),
            _ => panic!("Ambiguous matches for '{}'.", token.text),
        }
    }

    /// Execute the command that has been accepted by the parser.
    ///
    /// * XXX: This should be returning a Result probably.
    pub fn execute(&self) {
        if !self.commands.is_empty() {
            unimplemented!();
            // self.commands[0].execute(self)
        }
    }

    /// Verify that the parser is in a valid state with
    /// respect to having accepted a command and all
    /// required parameters.
    ///
    /// * XXX: This should be returning Option or Result
    ///        with an enum for the various error conditions.
    pub fn verify(&self) -> bool {
        if self.commands.is_empty() {
            // XXX: We'll want an enum error here with a Result.
            return false;
        } else {
            for expected in self.commands[0].parameters() {
                if expected.required() && !self.parameters.contains_key(expected.name()) {
                    return false;
                }
            }
        }
        true
    }
}

trait Acceptable {
    fn acceptable(&self, parser: &Parser) -> bool;
}

impl Acceptable for Node {
    fn acceptable(&self, _parser: &Parser) -> bool {
        unimplemented!();
        // !parser.nodes.contains(self)
    }
}

impl Acceptable for RepeatableNode {
    fn acceptable(&self, _parser: &Parser) -> bool {
        if self.repeatable() {
            return true;
        }
        unimplemented!()
        // This should check nodes.contains, but then go on to check
        // for a repeat marker and whether or not that's been seen.
    }
}

trait Matches {
    fn matches(&self, parser: &Parser, token: &Token) -> bool;
}

impl Matches for Node {
    fn matches(&self, _parser: &Parser, token: &Token) -> bool {
        self.name().starts_with(token.text)
    }
}

trait Accept {
    fn accept<'p>(&'p self, parser: &mut Parser<'p>, token: &Token);
}

impl Accept for Node {
    fn accept<'p>(&'p self, _parser: &mut Parser<'p>, _token: &Token) {}
}

impl Accept for Rc<CommandNode> {
    fn accept<'p>(&'p self, parser: &mut Parser<'p>, _token: &Token) {
        if let Some(_) = self.handler() {
            parser.commands.push(self)
        }
    }
}

impl Accept for Rc<ParameterNode> {
    fn accept<'p>(&'p self, parser: &mut Parser<'p>, token: &Token) {
        if self.repeatable() {
            unimplemented!();
        } else {
            parser.parameters.insert(self.name().clone(), token.text.to_string());
        }
    }
}
<|endoftext|>