<commit_before>use common::{R};
use lapack;
use lapack::lapack_int;
use dense_matrix::DenseMatrix;
use monomial::{Monomial};
use polynomial::{PolyBorrowingMons};
use mesh::{Mesh, FENum, OShape, SideFace};
use wg_basis::{WgBasis};

use std::num;
use std::vec;

/** Method of Projection onto a Subspace
 * -------------------------------------
 * <Proj(g), e_i> = <g, e_i> for all basis elements e_i in the subspace.
 * Since Proj(g) = sum_j{ a_j e_j } for some a_j's, this gives us a linear system
 *   sum_j { <e_j, e_i> a_j } = <g, e_i>
 * which we solve for the a_j.
 */

pub struct Projector<'self,Mon,MeshT> {

  basis: &'self WgBasis<Mon,MeshT>,

  // Pre-calculated L2 inner products between basis elements supported on the same faces of reference oriented shapes.
  // Only the upper triangle part of each matrix should be used, the contents of the lower parts are undefined.
  ips_int_mons_by_oshape: ~[DenseMatrix],          // by fe oriented shape, then (int mon num, int mon num)
  ips_side_mons_by_oshape_side: ~[~[DenseMatrix]], // by fe oriented shape, then side face, then (side mon #, side mon #)

  // Work matrices for lapack to avoid allocations and because lapack enjoys writing over its inputs.
  lapack_ips_int_mons: ~DenseMatrix,
  lapack_ips_side_mons: ~DenseMatrix,
  lapack_pivots: ~[lapack_int],
  lapack_pivots_buf: *mut lapack_int,
  lapack_int_proj_rhs: ~DenseMatrix,
  lapack_side_proj_rhs: ~DenseMatrix,
}

impl <'self,Mon:Monomial,MeshT:Mesh<Mon>> Projector<'self,Mon,MeshT> {

  pub fn new(basis: &'self WgBasis<Mon,MeshT>) -> Projector<'self,Mon,MeshT> {
    Projector::with_rhs_cols_capacity(basis, 1000u)
  }

  pub fn with_rhs_cols_capacity(basis: &'self WgBasis<Mon,MeshT>, init_rhs_cols_capacity: uint) -> Projector<'self,Mon,MeshT> {
    lapack::init(); // TODO: Move this to main when available.

    let mesh = basis.mesh();

    let ips_int_mons_by_oshape = {
      let int_mons = basis.ref_int_mons();
      vec::from_fn(mesh.num_oriented_element_shapes(), |os| {
        DenseMatrix::upper_triangle_from_fn(int_mons.len(), |i,j| {
          mesh.intg_facerel_mon_on_oshape_int(int_mons[i] * int_mons[j], OShape(os))
        })
      })
    };

    let ips_side_mons_by_oshape_side = vec::from_fn(mesh.num_oriented_element_shapes(), |os| {
      vec::from_fn(mesh.num_side_faces_for_shape(OShape(os)), |sf| {
        let side_mons = basis.side_mons_for_oshape_side(OShape(os), SideFace(sf));
        DenseMatrix::upper_triangle_from_fn(side_mons.len(), |i,j| {
          mesh.intg_facerel_mon_on_oshape_side(side_mons[i] * side_mons[j], OShape(os), SideFace(sf))
        })
      })
    });

    let (num_int_mons, num_side_mons) = (basis.mons_per_fe_int(), basis.mons_per_fe_side());
    let lapack_ips_int_mons = ~DenseMatrix::from_elem(num_int_mons, num_int_mons, 0 as R);
    let lapack_ips_side_mons = ~DenseMatrix::from_elem(num_side_mons, num_side_mons, 0 as R);
    let mut lapack_pivots = vec::from_elem(num::max(num_int_mons, num_side_mons), 0 as lapack_int);
    let lapack_pivots_buf = vec::raw::to_mut_ptr(lapack_pivots);
    let init_num_rhs_cols = init_rhs_cols_capacity;
    let lapack_int_proj_rhs = ~DenseMatrix::from_elem(num_int_mons, init_num_rhs_cols, 0 as R);
    let lapack_side_proj_rhs = ~DenseMatrix::from_elem(num_side_mons, init_num_rhs_cols, 0 as R);

    Projector {
      basis: basis,
      ips_int_mons_by_oshape: ips_int_mons_by_oshape,
      ips_side_mons_by_oshape_side: ips_side_mons_by_oshape_side,
      lapack_ips_int_mons: lapack_ips_int_mons,
      lapack_ips_side_mons: lapack_ips_side_mons,
      lapack_pivots: lapack_pivots,
      lapack_pivots_buf: lapack_pivots_buf,
      lapack_int_proj_rhs: lapack_int_proj_rhs,
      lapack_side_proj_rhs: lapack_side_proj_rhs,
    }
  }

  /// Returns the projections of function g to the spaces spanned by the basis functions supported on
  /// the interiors of the given finite elements in turn. The monomials of the returned polynomials are
  /// gauranteed to be in order of their ascending face monomial numbers, which is the same order in
  /// which the monomials appear in the basis.
  #[fixed_stack_segment]
  #[inline(never)]
  pub fn projs_to_span_fes_int_supp_basis_els(&mut self,
         g: &fn(&[R]) -> R, fes: &[FENum], fes_oshape: OShape) -> ~[PolyBorrowingMons<'self,Mon>] {

    let int_mons = self.basis.ref_int_mons();

    let sol_as_col_maj_vec = unsafe {

      // Prepare system matrix a.
      let a = {
        self.lapack_ips_int_mons.fill_upper_triangle_from(&self.ips_int_mons_by_oshape[*fes_oshape]);
        self.lapack_ips_int_mons.mut_col_maj_data_ptr()
      };

      // Prepare right hand side b matrix, one column per fe to be projected onto.
      let b = {
        //   - Set the proper number of columns for our sequence of fes, recreate matrix if necessary.
        if self.lapack_int_proj_rhs.capacity_cols >= fes.len() {
          self.lapack_int_proj_rhs.set_num_cols(fes.len());
        } else {
          self.lapack_int_proj_rhs = ~DenseMatrix::of_size_with_cols_capacity(int_mons.len(), fes.len(), 3*fes.len()/2);
        }
        //   - Fill the rhs matrix with inner products between g and our interior monomials (rows) on the fes (cols).
        self.lapack_int_proj_rhs.fill_from_fn(|r,c| {
          let mon = int_mons[r].clone();
          let fe = fes[c];
          self.basis.mesh.intg_global_fn_x_facerel_mon_on_fe_int(|x| g(x), mon, fe)
        });
        self.lapack_int_proj_rhs.mut_col_maj_data_ptr()
      };

      lapack::solve_symmetric_as_col_maj_with_ut_sys(a, int_mons.len() as lapack_int,
                                                     b, fes.len() as lapack_int,
                                                     self.lapack_pivots_buf);

      vec::from_buf(b as *R, int_mons.len() * fes.len())
    };

    sol_as_col_maj_vec
      .chunk_iter(int_mons.len()) // Chunk into columns representing the projection coefficients.
      .map(|proj_coefs| PolyBorrowingMons { coefs: proj_coefs.to_owned(), mons: int_mons })
      .collect()
  }

  /// Returns the projections of function g to the spaces spanned by the basis functions supported on
  /// the given side face of the given finite elements in turn. The monomials of the returned polynomials
  /// are gauranteed to be in order of their ascending face monomial numbers, which is the same order in
  /// which the monomials appear in the basis.
  #[fixed_stack_segment]
  #[inline(never)]
  pub fn projs_to_span_fes_side_supp_basis_els(&mut self,
         g: &fn(&[R]) -> R, fes: &[FENum], fes_oshape: OShape, side_face: SideFace) -> ~[PolyBorrowingMons<'self,Mon>] {

    let side_mons = self.basis.side_mons_for_oshape_side(fes_oshape, side_face);

    let sol_as_col_maj_vec = unsafe {

      // Prepare system matrix a.
      let a = {
        self.lapack_ips_side_mons.fill_upper_triangle_from(&self.ips_side_mons_by_oshape_side[*fes_oshape][*side_face]);
        self.lapack_ips_side_mons.mut_col_maj_data_ptr()
      };

      // Prepare right hand side b matrix, one column per fe to be projected onto.
      let b = {
        //   - Set the proper number of columns for our sequence of fes, recreate matrix if necessary.
        if self.lapack_side_proj_rhs.capacity_cols >= fes.len() {
          self.lapack_side_proj_rhs.set_num_cols(fes.len());
        } else {
          self.lapack_side_proj_rhs = ~DenseMatrix::of_size_with_cols_capacity(side_mons.len(), fes.len(), 3*fes.len()/2);
        }
        //   - Fill the rhs matrix with inner products between g and our side monomials (rows) on the fes (cols).
        self.lapack_side_proj_rhs.fill_from_fn(|r,c| {
          let mon = side_mons[r].clone();
          let fe = fes[c];
          self.basis.mesh.intg_global_fn_x_facerel_mon_on_fe_side(|x| g(x), mon, fe, side_face)
        });
        self.lapack_side_proj_rhs.mut_col_maj_data_ptr()
      };

      lapack::solve_symmetric_as_col_maj_with_ut_sys(a, side_mons.len() as lapack_int,
                                                     b, fes.len() as lapack_int,
                                                     self.lapack_pivots_buf);

      vec::from_buf(b as *R, side_mons.len() * fes.len())
    };

    sol_as_col_maj_vec
      .chunk_iter(side_mons.len()) // Chunk into columns representing the projection coefficients.
      .map(|proj_coefs| PolyBorrowingMons { coefs: proj_coefs.to_owned(), mons: side_mons })
      .collect()
  }

  #[fixed_stack_segment]
  #[inline(never)]
  pub fn proj_int_mons_to_span_oshape_side_supp_basis_els(&mut self,
     int_mons: &[Mon], oshape: OShape, side_face: SideFace) -> ~[PolyBorrowingMons<'self,Mon>] {

    let side_mons = self.basis.side_mons_for_oshape_side(oshape, side_face);

    let sol_as_col_maj_vec = unsafe {

      // Prepare system matrix a, consisting of inner products between basis elements supported on the side.
      let a = {
        self.lapack_ips_side_mons.fill_upper_triangle_from(&self.ips_side_mons_by_oshape_side[*oshape][*side_face]);
        self.lapack_ips_side_mons.mut_col_maj_data_ptr()
      };

      // Prepare right hand side b matrix, one column per interior monomial to be projected onto the side.
      let b = {
        //   - Set the proper number of columns for our sequence of fes, recreate matrix if necessary.
        if self.lapack_side_proj_rhs.capacity_cols >= int_mons.len() {
          self.lapack_side_proj_rhs.set_num_cols(int_mons.len());
        } else {
          self.lapack_side_proj_rhs = ~DenseMatrix::of_size_with_cols_capacity(side_mons.len(), int_mons.len(), 3*int_mons.len()/2);
        }
        //   - Fill the rhs matrix with inner products between our side monomials (rows) and the interior monomials (cols) to be projected.
        self.lapack_side_proj_rhs.fill_from_fn(|r,c| {
          let (int_mon, side_basis_mon) = (int_mons[c].clone(), side_mons[r].clone());
          self.basis.mesh.intg_intrel_mon_x_siderel_mon_on_oshape_side(int_mon, side_basis_mon, oshape, side_face)
        });
        self.lapack_side_proj_rhs.mut_col_maj_data_ptr()
      };

      lapack::solve_symmetric_as_col_maj_with_ut_sys(a, side_mons.len() as lapack_int,
                                                     b, int_mons.len() as lapack_int,
                                                     self.lapack_pivots_buf);

      vec::from_buf(b as *R, side_mons.len() * int_mons.len())
    };

    sol_as_col_maj_vec
      .chunk_iter(side_mons.len()) // Chunk into columns representing the projection coefficients.
      .map(|proj_coefs| PolyBorrowingMons { coefs: proj_coefs.to_owned(), mons: side_mons })
      .collect()
  }

} // impl Projector

<commit_msg>Add basis accessor.<commit_after>use common::{R};
use lapack;
use lapack::lapack_int;
use dense_matrix::DenseMatrix;
use monomial::{Monomial};
use polynomial::{PolyBorrowingMons};
use mesh::{Mesh, FENum, OShape, SideFace};
use wg_basis::{WgBasis};

use std::num;
use std::vec;

/** Method of Projection onto a Subspace
 * -------------------------------------
 * <Proj(g), e_i> = <g, e_i> for all basis elements e_i in the subspace.
 * Since Proj(g) = sum_j{ a_j e_j } for some a_j's, this gives us a linear system
 *   sum_j { <e_j, e_i> a_j } = <g, e_i>
 * which we solve for the a_j.
 */

pub struct Projector<'self,Mon,MeshT> {

  basis: &'self WgBasis<Mon,MeshT>,

  // Pre-calculated L2 inner products between basis elements supported on the same faces of reference oriented shapes.
  // Only the upper triangle part of each matrix should be used, the contents of the lower parts are undefined.
  ips_int_mons_by_oshape: ~[DenseMatrix],          // by fe oriented shape, then (int mon num, int mon num)
  ips_side_mons_by_oshape_side: ~[~[DenseMatrix]], // by fe oriented shape, then side face, then (side mon #, side mon #)

  // Work matrices for lapack to avoid allocations and because lapack enjoys writing over its inputs.
  lapack_ips_int_mons: ~DenseMatrix,
  lapack_ips_side_mons: ~DenseMatrix,
  lapack_pivots: ~[lapack_int],
  lapack_pivots_buf: *mut lapack_int,
  lapack_int_proj_rhs: ~DenseMatrix,
  lapack_side_proj_rhs: ~DenseMatrix,
}

impl <'self,Mon:Monomial,MeshT:Mesh<Mon>> Projector<'self,Mon,MeshT> {

  pub fn new(basis: &'self WgBasis<Mon,MeshT>) -> Projector<'self,Mon,MeshT> {
    Projector::with_rhs_cols_capacity(basis, 1000u)
  }

  pub fn with_rhs_cols_capacity(basis: &'self WgBasis<Mon,MeshT>, init_rhs_cols_capacity: uint) -> Projector<'self,Mon,MeshT> {
    lapack::init(); // TODO: Move this to main when available.

    let mesh = basis.mesh();

    let ips_int_mons_by_oshape = {
      let int_mons = basis.ref_int_mons();
      vec::from_fn(mesh.num_oriented_element_shapes(), |os| {
        DenseMatrix::upper_triangle_from_fn(int_mons.len(), |i,j| {
          mesh.intg_facerel_mon_on_oshape_int(int_mons[i] * int_mons[j], OShape(os))
        })
      })
    };

    let ips_side_mons_by_oshape_side = vec::from_fn(mesh.num_oriented_element_shapes(), |os| {
      vec::from_fn(mesh.num_side_faces_for_shape(OShape(os)), |sf| {
        let side_mons = basis.side_mons_for_oshape_side(OShape(os), SideFace(sf));
        DenseMatrix::upper_triangle_from_fn(side_mons.len(), |i,j| {
          mesh.intg_facerel_mon_on_oshape_side(side_mons[i] * side_mons[j], OShape(os), SideFace(sf))
        })
      })
    });

    let (num_int_mons, num_side_mons) = (basis.mons_per_fe_int(), basis.mons_per_fe_side());
    let lapack_ips_int_mons = ~DenseMatrix::from_elem(num_int_mons, num_int_mons, 0 as R);
    let lapack_ips_side_mons = ~DenseMatrix::from_elem(num_side_mons, num_side_mons, 0 as R);
    let mut lapack_pivots = vec::from_elem(num::max(num_int_mons, num_side_mons), 0 as lapack_int);
    let lapack_pivots_buf = vec::raw::to_mut_ptr(lapack_pivots);
    let init_num_rhs_cols = init_rhs_cols_capacity;
    let lapack_int_proj_rhs = ~DenseMatrix::from_elem(num_int_mons, init_num_rhs_cols, 0 as R);
    let lapack_side_proj_rhs = ~DenseMatrix::from_elem(num_side_mons, init_num_rhs_cols, 0 as R);

    Projector {
      basis: basis,
      ips_int_mons_by_oshape: ips_int_mons_by_oshape,
      ips_side_mons_by_oshape_side: ips_side_mons_by_oshape_side,
      lapack_ips_int_mons: lapack_ips_int_mons,
      lapack_ips_side_mons: lapack_ips_side_mons,
      lapack_pivots: lapack_pivots,
      lapack_pivots_buf: lapack_pivots_buf,
      lapack_int_proj_rhs: lapack_int_proj_rhs,
      lapack_side_proj_rhs: lapack_side_proj_rhs,
    }
  }

  #[inline]
  pub fn basis(&self) -> &'self WgBasis<Mon,MeshT> {
    self.basis
  }

  /// Returns the projections of function g to the spaces spanned by the basis functions supported on
  /// the interiors of the given finite elements in turn. The monomials of the returned polynomials are
  /// gauranteed to be in order of their ascending face monomial numbers, which is the same order in
  /// which the monomials appear in the basis.
  #[fixed_stack_segment]
  #[inline(never)]
  pub fn projs_to_span_fes_int_supp_basis_els(&mut self,
         g: &fn(&[R]) -> R, fes: &[FENum], fes_oshape: OShape) -> ~[PolyBorrowingMons<'self,Mon>] {

    let int_mons = self.basis.ref_int_mons();

    let sol_as_col_maj_vec = unsafe {

      // Prepare system matrix a.
      let a = {
        self.lapack_ips_int_mons.fill_upper_triangle_from(&self.ips_int_mons_by_oshape[*fes_oshape]);
        self.lapack_ips_int_mons.mut_col_maj_data_ptr()
      };

      // Prepare right hand side b matrix, one column per fe to be projected onto.
      let b = {
        //   - Set the proper number of columns for our sequence of fes, recreate matrix if necessary.
        if self.lapack_int_proj_rhs.capacity_cols >= fes.len() {
          self.lapack_int_proj_rhs.set_num_cols(fes.len());
        } else {
          self.lapack_int_proj_rhs = ~DenseMatrix::of_size_with_cols_capacity(int_mons.len(), fes.len(), 3*fes.len()/2);
        }
        //   - Fill the rhs matrix with inner products between g and our interior monomials (rows) on the fes (cols).
        self.lapack_int_proj_rhs.fill_from_fn(|r,c| {
          let mon = int_mons[r].clone();
          let fe = fes[c];
          self.basis.mesh.intg_global_fn_x_facerel_mon_on_fe_int(|x| g(x), mon, fe)
        });
        self.lapack_int_proj_rhs.mut_col_maj_data_ptr()
      };

      lapack::solve_symmetric_as_col_maj_with_ut_sys(a, int_mons.len() as lapack_int,
                                                     b, fes.len() as lapack_int,
                                                     self.lapack_pivots_buf);

      vec::from_buf(b as *R, int_mons.len() * fes.len())
    };

    sol_as_col_maj_vec
      .chunk_iter(int_mons.len()) // Chunk into columns representing the projection coefficients.
      .map(|proj_coefs| PolyBorrowingMons { coefs: proj_coefs.to_owned(), mons: int_mons })
      .collect()
  }

  /// Returns the projections of function g to the spaces spanned by the basis functions supported on
  /// the given side face of the given finite elements in turn. The monomials of the returned polynomials
  /// are gauranteed to be in order of their ascending face monomial numbers, which is the same order in
  /// which the monomials appear in the basis.
  #[fixed_stack_segment]
  #[inline(never)]
  pub fn projs_to_span_fes_side_supp_basis_els(&mut self,
         g: &fn(&[R]) -> R, fes: &[FENum], fes_oshape: OShape, side_face: SideFace) -> ~[PolyBorrowingMons<'self,Mon>] {

    let side_mons = self.basis.side_mons_for_oshape_side(fes_oshape, side_face);

    let sol_as_col_maj_vec = unsafe {

      // Prepare system matrix a.
      let a = {
        self.lapack_ips_side_mons.fill_upper_triangle_from(&self.ips_side_mons_by_oshape_side[*fes_oshape][*side_face]);
        self.lapack_ips_side_mons.mut_col_maj_data_ptr()
      };

      // Prepare right hand side b matrix, one column per fe to be projected onto.
      let b = {
        //   - Set the proper number of columns for our sequence of fes, recreate matrix if necessary.
        if self.lapack_side_proj_rhs.capacity_cols >= fes.len() {
          self.lapack_side_proj_rhs.set_num_cols(fes.len());
        } else {
          self.lapack_side_proj_rhs = ~DenseMatrix::of_size_with_cols_capacity(side_mons.len(), fes.len(), 3*fes.len()/2);
        }
        //   - Fill the rhs matrix with inner products between g and our side monomials (rows) on the fes (cols).
        self.lapack_side_proj_rhs.fill_from_fn(|r,c| {
          let mon = side_mons[r].clone();
          let fe = fes[c];
          self.basis.mesh.intg_global_fn_x_facerel_mon_on_fe_side(|x| g(x), mon, fe, side_face)
        });
        self.lapack_side_proj_rhs.mut_col_maj_data_ptr()
      };

      lapack::solve_symmetric_as_col_maj_with_ut_sys(a, side_mons.len() as lapack_int,
                                                     b, fes.len() as lapack_int,
                                                     self.lapack_pivots_buf);

      vec::from_buf(b as *R, side_mons.len() * fes.len())
    };

    sol_as_col_maj_vec
      .chunk_iter(side_mons.len()) // Chunk into columns representing the projection coefficients.
      .map(|proj_coefs| PolyBorrowingMons { coefs: proj_coefs.to_owned(), mons: side_mons })
      .collect()
  }

  #[fixed_stack_segment]
  #[inline(never)]
  pub fn proj_int_mons_to_span_oshape_side_supp_basis_els(&mut self,
     int_mons: &[Mon], oshape: OShape, side_face: SideFace) -> ~[PolyBorrowingMons<'self,Mon>] {

    let side_mons = self.basis.side_mons_for_oshape_side(oshape, side_face);

    let sol_as_col_maj_vec = unsafe {

      // Prepare system matrix a, consisting of inner products between basis elements supported on the side.
      let a = {
        self.lapack_ips_side_mons.fill_upper_triangle_from(&self.ips_side_mons_by_oshape_side[*oshape][*side_face]);
        self.lapack_ips_side_mons.mut_col_maj_data_ptr()
      };

      // Prepare right hand side b matrix, one column per interior monomial to be projected onto the side.
      let b = {
        //   - Set the proper number of columns for our sequence of fes, recreate matrix if necessary.
        if self.lapack_side_proj_rhs.capacity_cols >= int_mons.len() {
          self.lapack_side_proj_rhs.set_num_cols(int_mons.len());
        } else {
          self.lapack_side_proj_rhs = ~DenseMatrix::of_size_with_cols_capacity(side_mons.len(), int_mons.len(), 3*int_mons.len()/2);
        }
        //   - Fill the rhs matrix with inner products between our side monomials (rows) and the interior monomials (cols) to be projected.
        self.lapack_side_proj_rhs.fill_from_fn(|r,c| {
          let (int_mon, side_basis_mon) = (int_mons[c].clone(), side_mons[r].clone());
          self.basis.mesh.intg_intrel_mon_x_siderel_mon_on_oshape_side(int_mon, side_basis_mon, oshape, side_face)
        });
        self.lapack_side_proj_rhs.mut_col_maj_data_ptr()
      };

      lapack::solve_symmetric_as_col_maj_with_ut_sys(a, side_mons.len() as lapack_int,
                                                     b, int_mons.len() as lapack_int,
                                                     self.lapack_pivots_buf);

      vec::from_buf(b as *R, side_mons.len() * int_mons.len())
    };

    sol_as_col_maj_vec
      .chunk_iter(side_mons.len()) // Chunk into columns representing the projection coefficients.
      .map(|proj_coefs| PolyBorrowingMons { coefs: proj_coefs.to_owned(), mons: side_mons })
      .collect()
  }

} // impl Projector

<|endoftext|>


<commit_before>use tile::Tile;
use util::Grid;
use std::ops::{Index};
use na::Vec2;

pub struct Level<T> {
    tiles: Grid<T>,
}

impl<T> Level<T> {
    pub fn get_width(&self) -> usize {
        self.tiles.get_width()
    }

    pub fn get_height(&self) -> usize {
        self.tiles.get_height()
    }

    pub fn get_tile(&self, x: usize, y: usize) -> Option<&T> {
        if x < self.get_width() && y < self.get_height() {
            self.tiles[(x, y)]
        } else {
            None
        }
    }

    pub fn get_tile_with_vec(&self, pos: &Vec2<usize>) -> Option<&T> {
        self.get_tile(pos.x, pos.y)
    }

    pub fn get_tile_with_tuple(&self, (x, y): (usize, usize)) -> Option<&T> {
        self.get_tile(x,y)
    }

    pub fn get_mut_tile(&mut self, x: usize, y: usize) -> Option<&mut T> {
        if x < self.get_width() && y < self.get_height() {
            self.tiles[(x, y)].as_mut()
        } else {
            None
        }
    }

    pub fn get_mut_tile_with_vec(&mut self, pos: &Vec2<usize>) -> Option<&mut T> {
        self.get_mut_tile(pos.x, pos.y)
    }

    pub fn get_mut_tile_with_tuple(&mut self, (x, y): (usize, usize)) -> Option<&mut T> {
        self.get_mut_tile(x,y)
    }

    pub fn apply<F>(&mut self, gen: F) -> &mut Level<T> where F: FnOnce(&mut Level<T>) {
        gen(self);
        self
    }

}

impl<T: Clone> Level<T> {
    pub fn fill_with(&mut self, tile: T) {
        let width = self.tiles.get_width();
        let height = self.tiles.get_height();

        for x in 0..width {
            for y in 0..height {
                self.tiles[(x, y)] = Some(tile.clone());
            }
        }
    }

    pub fn new(width: usize, height: usize) -> Level<T> {
        Level{
            tiles: Grid::new_filled_with(None ,width, height),
        }
    }

    pub fn new_filled_with(tile: Option<T>, width: usize, height: usize) -> Level<T> {
        Level{
            tiles: Grid::new_filled_with(tile, width, height),
        }
    }
}

<<<<<<< Updated upstream
static NONE: &'static Option<()> = &None;

impl<T> Index<(usize, usize)> for Level<T> {
    type Output= Option<T>;

    fn index(&self, (x, y): (usize, usize)) -> &Option<T>{
        if x < self.get_width() && y < self.get_height() {
            &self.tiles[(x, y)]
        } else {
             unsafe{&*(NONE as *const _ as *const _)} //delmas pointer magic
        }
    }
}

impl<T> Index<Vec2<usize>> for Level<T> {
    type Output= Option<T>;

    fn index(&self, vec: Vec2<usize>) -> &Option<T>{
        if vec.x < self.get_width() && vec.y < self.get_height() {
            &self.tiles[(vec.x, vec.y)]
        } else {
             unsafe{&*(NONE as *const _ as *const _)} //delmas pointer magic
        }
    }
}

=======
>>>>>>> Stashed changes
pub fn fill_dead_end_tiles(level: &mut Level<Tile>) -> bool {
    let mut deadends = Vec::new();
    for y in 0..level.get_height() {
        for x in 0..level.get_width() {
            if let Some(n) = level.get_tile(x, y) {
                if let &Tile::Floor(_) = n {
                    if is_deadend(level, x, y) {
                        deadends.push((x,y));
                    }
                }
            }
        }
    }
    let mut filled_deadend = false;
    for &(x,y) in &deadends {
        if let Some(tile) = level.get_mut_tile(x, y) {
            *tile = Tile::Wall(0);
            filled_deadend = true;
        }
    }
    filled_deadend
}

pub fn is_deadend(level: &Level<Tile>, x: usize, y: usize) -> bool {
    use util::Direction;
    let mut paths = 0;
    for dir in Direction::get_orthogonal_dirs() {
        let vector = dir.get_vec();
        let coord = match (add_isize_to_usize(vector.x, x), add_isize_to_usize(vector.y, y)) {
            (Some(x), Some(y)) => (x,y),
            _ => continue,
        };

        if let Some(&Tile::Floor(_)) = level.get_tile_with_tuple(coord) {
            paths += 1;
        }
    }
    paths < 2
}

fn add_isize_to_usize(i: isize, mut u: usize,) -> Option<usize> {
    if i < 0 && u != 0 {
        u -= (-i) as usize;
    } else if i >= 0 && u < usize::max_value() {
        u += i as usize;
    } else {
        return None
    }
    Some(u)
}
<commit_msg>still continuing the level to generic refactor<commit_after>use tile::Tile;
use util::Grid;
use std::ops::{Index};
use na::Vec2;

pub struct Level<T> {
    tiles: Grid<T>,
}

impl<T> Level<T> {
    pub fn get_width(&self) -> usize {
        self.tiles.get_width()
    }

    pub fn get_height(&self) -> usize {
        self.tiles.get_height()
    }

    pub fn get_tile(&self, x: usize, y: usize) -> Option<&T> {
        if x < self.get_width() && y < self.get_height() {
            self.tiles[(x, y)]
        } else {
            None
        }
    }

    pub fn get_tile_with_vec(&self, pos: &Vec2<usize>) -> Option<&T> {
        self.get_tile(pos.x, pos.y)
    }

    pub fn get_tile_with_tuple(&self, (x, y): (usize, usize)) -> Option<&T> {
        self.get_tile(x,y)
    }

    pub fn get_mut_tile(&mut self, x: usize, y: usize) -> Option<&mut T> {
        if x < self.get_width() && y < self.get_height() {
            self.tiles[(x, y)].as_mut()
        } else {
            None
        }
    }

    pub fn get_mut_tile_with_vec(&mut self, pos: &Vec2<usize>) -> Option<&mut T> {
        self.get_mut_tile(pos.x, pos.y)
    }

    pub fn get_mut_tile_with_tuple(&mut self, (x, y): (usize, usize)) -> Option<&mut T> {
        self.get_mut_tile(x,y)
    }

    pub fn apply<F>(&mut self, gen: F) -> &mut Level<T> where F: FnOnce(&mut Level<T>) {
        gen(self);
        self
    }

}

impl<T: Clone> Level<T> {
    pub fn fill_with(&mut self, tile: T) {
        let width = self.tiles.get_width();
        let height = self.tiles.get_height();

        for x in 0..width {
            for y in 0..height {
                self.tiles[(x, y)] = Some(tile.clone());
            }
        }
    }

    pub fn new(width: usize, height: usize) -> Level<T> {
        Level{
            tiles: Grid::new_filled_with(None ,width, height),
        }
    }

    pub fn new_filled_with(tile: Option<T>, width: usize, height: usize) -> Level<T> {
        Level{
            tiles: Grid::new_filled_with(tile, width, height),
        }
    }
}

pub fn fill_dead_end_tiles(level: &mut Level<Tile>) -> bool {
    let mut deadends = Vec::new();
    for y in 0..level.get_height() {
        for x in 0..level.get_width() {
            if let Some(n) = level.get_tile(x, y) {
                if let &Tile::Floor(_) = n {
                    if is_deadend(level, x, y) {
                        deadends.push((x,y));
                    }
                }
            }
        }
    }
    let mut filled_deadend = false;
    for &(x,y) in &deadends {
        if let Some(tile) = level.get_mut_tile(x, y) {
            *tile = Tile::Wall(0);
            filled_deadend = true;
        }
    }
    filled_deadend
}

pub fn is_deadend(level: &Level<Tile>, x: usize, y: usize) -> bool {
    use util::Direction;
    let mut paths = 0;
    for dir in Direction::get_orthogonal_dirs() {
        let vector = dir.get_vec();
        let coord = match (add_isize_to_usize(vector.x, x), add_isize_to_usize(vector.y, y)) {
            (Some(x), Some(y)) => (x,y),
            _ => continue,
        };

        if let Some(&Tile::Floor(_)) = level.get_tile_with_tuple(coord) {
            paths += 1;
        }
    }
    paths < 2
}

fn add_isize_to_usize(i: isize, mut u: usize,) -> Option<usize> {
    if i < 0 && u != 0 {
        u -= (-i) as usize;
    } else if i >= 0 && u < usize::max_value() {
        u += i as usize;
    } else {
        return None
    }
    Some(u)
}
<|endoftext|>


<commit_before>use luminance_gl::gl33::Tessellation;
use std::collections::BTreeMap;
//use std::fs::File;
//use std::io::Read;
use std::path::{Path, PathBuf};
use wavefront_obj::{self, obj};

// FIXME: implement materials
type Material = ();

pub type Vertex = (VertexPos, VertexNor, VertexTexCoord);
pub type VertexPos = [f32; 3];
pub type VertexNor = [f32; 3];
pub type VertexTexCoord = [f32; 2];

pub struct Model<'a> {
  parts: Vec<Part<'a>>
}

impl<'a> Model<'a> {
  pub fn from_parts(parts: Vec<Part<'a>>) -> Self {
    Model {
      parts: parts
    }
  }
}

pub struct Part<'a> {
  tess: Tessellation,
  mat: Option<&'a Material>
}

impl<'a> Part<'a> {
  pub fn new(tess: Tessellation, mat: Option<&'a Material>) -> Self {
    Part {
      tess: tess,
      mat: mat
    }
  }

  pub fn tessellation(&self) -> &Tessellation {
    &self.tess
  }

  pub fn material(&self) -> Option<&Material> {
    self.mat.clone()
  }
}

// FIXME: review all the code bellow
////pub fn load<P>(path: P, mode: tessellation::Mode) -> Result<gl33::Tessellation, TessellationError> where P: AsRef<Path> {
////  let path = path.as_ref();
////
////  info!("loading tessellation: \x1b[35m{:?}", path);
////
////  let mut input = String::new();
////
////  // load the data directly into memory; no buffering nor streaming
////  {
////    let mut file = try!(File::open(path).map_err(|e| TessellationError::FileNotFound(path.to_path_buf(), format!("{:?}", e))));
////    let _ = file.read_to_string(&mut input);
////  }
////
////  // parse the obj file and convert it
////  let obj_set = try!(obj::parse(input).map_err(TessellationError::ParseFailed));
////
////  convert_obj(obj_set, mode)
////}
////
////// Turn a loaded wavefront obj object into a `Model`
////fn convert_obj(obj_set: obj::ObjSet, mode: tessellation::Mode) -> Result<gl33::Tessellation, TessellationError> {
////  if obj_set.objects.len() != 1 {
////    return Err(TessellationError::MultiObjects);
////  }
////
////  let obj = &obj_set.objects[0];
////  info!("  found object \x1b[35m{}", obj.name);
////
////  // interleave the vertices
////  let interleaved_vertices = interleave_vertices(&obj.vertices, &obj.normals, &obj.tex_vertices);
////
////  Err(TessellationError::Error)
////}

// Convert wavefront_obj’s Geometry into a pair of vertices and indices.
//
// This function will regenerate the indices on the fly based on which are used in the shapes in the
// geometry. It’s used to create independent tessellation.
fn convert_geometry(geo: &obj::Geometry, positions: &[obj::Vertex], normals: &[obj::Normal], tvertices: &[obj::TVertex]) -> Result<(Vec<Vertex>, Vec<u32>), ModelError> {
  let mut vertices = Vec::new(); // FIXME: better allocation scheme?
  let mut indices = Vec::new();
  let mut index_map = BTreeMap::new();

  for prim in geo.shapes.iter().map(|s| s.primitive) {
    let keys = try!(create_keys_from_primitive(prim));

    for key in keys {
      match index_map.get(&key).map(|&i| i) {
        Some(index) => {
          // that triplet already exists; just append the index in the indices buffer
          indices.push(index);
        },
        None => {
          // this is a new, not yet discovered triplet; create the corresponding vertex and add it
          // to the vertices buffer, and map the triplet to the index in the indices buffer
          let vertex = interleave_vertex(&positions[key.0], &normals[key.1], &tvertices[key.2]);
          let index = vertices.len() as u32;

          vertices.push(vertex);
          indices.push(index);
          index_map.insert(key, index);
        }
      }
    }
  }

  Ok((vertices, indices))
}

// Create triplet keys from wavefront_obj primitives. If any primitive doesn’t have all the triplet
// information (position, normal, tex), a ModelError::UnsupportedVertex error is returned instead.
fn create_keys_from_primitive(prim: obj::Primitive) -> Result<Vec<(usize, usize, usize)>, ModelError> {
  match prim {
    obj::Primitive::Point(i) => {
      let a = try!(vtnindex_to_key(i));
      Ok(vec![a])
    },
    obj::Primitive::Line(i, j) => {
      let a = try!(vtnindex_to_key(i));
      let b = try!(vtnindex_to_key(j));
      Ok(vec![a, b])
    },
    obj::Primitive::Triangle(i, j, k) => {
      let a = try!(vtnindex_to_key(i));
      let b = try!(vtnindex_to_key(j));
      let c = try!(vtnindex_to_key(k));
      Ok(vec![a, b, c])
    }
  }
}

// Convert from a wavefront_obj VTNIndex into our triplet, raising error if not possible.
fn vtnindex_to_key(i: obj::VTNIndex) -> Result<(usize, usize, usize), ModelError> {
  match i {
    (pi, Some(ti), Some(ni)) => Ok((pi, ni, ti)),
    _ => Err(ModelError::UnsupportedVertex)
  }
}

fn interleave_vertex(p: &obj::Vertex, n: &obj::Normal, t: &obj::TVertex) -> Vertex {
  (convert_vertex(p), convert_nor(n), convert_tvertex(t))
}

fn convert_vertex(v: &obj::Vertex) -> VertexPos {
  [v.x as f32, v.y as f32, v.z as f32]
}

fn convert_nor(n: &obj::Normal) -> VertexNor {
  convert_vertex(n)
}

fn convert_tvertex(t: &obj::TVertex) -> VertexTexCoord {
  [t.x as f32, t.y as f32]
}

////mod hot {
////  use super::{TessellationError, Vertex};
////
////  use luminance::tessellation;
////  use luminance_gl::gl33;
////  use resource::ResourceManager;
////  use std::ops::Deref;
////  use std::path::{Path, PathBuf};
////
////  pub struct Tessellation {
////    path: PathBuf,
////    mode: tessellation::Mode,
////    tess: gl33::Tessellation
////  }
////
////  impl Tessellation {
////    fn load<P>(manager: &mut ResourceManager, path: P, mode: tessellation::Mode) -> Result<Self, TessellationError> where P: AsRef<Path> {
////      Err(TessellationError::Error)
////    }
////  }
////
////  impl Deref for Tessellation {
////    type Target = gl33::Tessellation;
////
////    fn deref(&self) -> &Self::Target {
////      &self.tess
////    }
////  }
////}
////
pub enum ModelError {
  FileNotFound(PathBuf, String),
  ParseFailed(wavefront_obj::ParseError),
  MultiObjects,
  UnsupportedVertex
}
<commit_msg>Fixed private type in interface (Material). (#3, #9)<commit_after>use luminance_gl::gl33::Tessellation;
use std::collections::BTreeMap;
//use std::fs::File;
//use std::io::Read;
use std::path::{Path, PathBuf};
use wavefront_obj::{self, obj};

// FIXME: implement materials
pub type Material = ();

pub type Vertex = (VertexPos, VertexNor, VertexTexCoord);
pub type VertexPos = [f32; 3];
pub type VertexNor = [f32; 3];
pub type VertexTexCoord = [f32; 2];

pub struct Model<'a> {
  parts: Vec<Part<'a>>
}

impl<'a> Model<'a> {
  pub fn from_parts(parts: Vec<Part<'a>>) -> Self {
    Model {
      parts: parts
    }
  }
}

pub struct Part<'a> {
  tess: Tessellation,
  mat: Option<&'a Material>
}

impl<'a> Part<'a> {
  pub fn new(tess: Tessellation, mat: Option<&'a Material>) -> Self {
    Part {
      tess: tess,
      mat: mat
    }
  }

  pub fn tessellation(&self) -> &Tessellation {
    &self.tess
  }

  pub fn material(&self) -> Option<&Material> {
    self.mat.clone()
  }
}

// FIXME: review all the code bellow
////pub fn load<P>(path: P, mode: tessellation::Mode) -> Result<gl33::Tessellation, TessellationError> where P: AsRef<Path> {
////  let path = path.as_ref();
////
////  info!("loading tessellation: \x1b[35m{:?}", path);
////
////  let mut input = String::new();
////
////  // load the data directly into memory; no buffering nor streaming
////  {
////    let mut file = try!(File::open(path).map_err(|e| TessellationError::FileNotFound(path.to_path_buf(), format!("{:?}", e))));
////    let _ = file.read_to_string(&mut input);
////  }
////
////  // parse the obj file and convert it
////  let obj_set = try!(obj::parse(input).map_err(TessellationError::ParseFailed));
////
////  convert_obj(obj_set, mode)
////}
////
////// Turn a loaded wavefront obj object into a `Model`
////fn convert_obj(obj_set: obj::ObjSet, mode: tessellation::Mode) -> Result<gl33::Tessellation, TessellationError> {
////  if obj_set.objects.len() != 1 {
////    return Err(TessellationError::MultiObjects);
////  }
////
////  let obj = &obj_set.objects[0];
////  info!("  found object \x1b[35m{}", obj.name);
////
////  // interleave the vertices
////  let interleaved_vertices = interleave_vertices(&obj.vertices, &obj.normals, &obj.tex_vertices);
////
////  Err(TessellationError::Error)
////}

// Convert wavefront_obj’s Geometry into a pair of vertices and indices.
//
// This function will regenerate the indices on the fly based on which are used in the shapes in the
// geometry. It’s used to create independent tessellation.
fn convert_geometry(geo: &obj::Geometry, positions: &[obj::Vertex], normals: &[obj::Normal], tvertices: &[obj::TVertex]) -> Result<(Vec<Vertex>, Vec<u32>), ModelError> {
  let mut vertices = Vec::new(); // FIXME: better allocation scheme?
  let mut indices = Vec::new();
  let mut index_map = BTreeMap::new();

  for prim in geo.shapes.iter().map(|s| s.primitive) {
    let keys = try!(create_keys_from_primitive(prim));

    for key in keys {
      match index_map.get(&key).map(|&i| i) {
        Some(index) => {
          // that triplet already exists; just append the index in the indices buffer
          indices.push(index);
        },
        None => {
          // this is a new, not yet discovered triplet; create the corresponding vertex and add it
          // to the vertices buffer, and map the triplet to the index in the indices buffer
          let vertex = interleave_vertex(&positions[key.0], &normals[key.1], &tvertices[key.2]);
          let index = vertices.len() as u32;

          vertices.push(vertex);
          indices.push(index);
          index_map.insert(key, index);
        }
      }
    }
  }

  Ok((vertices, indices))
}

// Create triplet keys from wavefront_obj primitives. If any primitive doesn’t have all the triplet
// information (position, normal, tex), a ModelError::UnsupportedVertex error is returned instead.
fn create_keys_from_primitive(prim: obj::Primitive) -> Result<Vec<(usize, usize, usize)>, ModelError> {
  match prim {
    obj::Primitive::Point(i) => {
      let a = try!(vtnindex_to_key(i));
      Ok(vec![a])
    },
    obj::Primitive::Line(i, j) => {
      let a = try!(vtnindex_to_key(i));
      let b = try!(vtnindex_to_key(j));
      Ok(vec![a, b])
    },
    obj::Primitive::Triangle(i, j, k) => {
      let a = try!(vtnindex_to_key(i));
      let b = try!(vtnindex_to_key(j));
      let c = try!(vtnindex_to_key(k));
      Ok(vec![a, b, c])
    }
  }
}

// Convert from a wavefront_obj VTNIndex into our triplet, raising error if not possible.
fn vtnindex_to_key(i: obj::VTNIndex) -> Result<(usize, usize, usize), ModelError> {
  match i {
    (pi, Some(ti), Some(ni)) => Ok((pi, ni, ti)),
    _ => Err(ModelError::UnsupportedVertex)
  }
}

fn interleave_vertex(p: &obj::Vertex, n: &obj::Normal, t: &obj::TVertex) -> Vertex {
  (convert_vertex(p), convert_nor(n), convert_tvertex(t))
}

fn convert_vertex(v: &obj::Vertex) -> VertexPos {
  [v.x as f32, v.y as f32, v.z as f32]
}

fn convert_nor(n: &obj::Normal) -> VertexNor {
  convert_vertex(n)
}

fn convert_tvertex(t: &obj::TVertex) -> VertexTexCoord {
  [t.x as f32, t.y as f32]
}

////mod hot {
////  use super::{TessellationError, Vertex};
////
////  use luminance::tessellation;
////  use luminance_gl::gl33;
////  use resource::ResourceManager;
////  use std::ops::Deref;
////  use std::path::{Path, PathBuf};
////
////  pub struct Tessellation {
////    path: PathBuf,
////    mode: tessellation::Mode,
////    tess: gl33::Tessellation
////  }
////
////  impl Tessellation {
////    fn load<P>(manager: &mut ResourceManager, path: P, mode: tessellation::Mode) -> Result<Self, TessellationError> where P: AsRef<Path> {
////      Err(TessellationError::Error)
////    }
////  }
////
////  impl Deref for Tessellation {
////    type Target = gl33::Tessellation;
////
////    fn deref(&self) -> &Self::Target {
////      &self.tess
////    }
////  }
////}
////
pub enum ModelError {
  FileNotFound(PathBuf, String),
  ParseFailed(wavefront_obj::ParseError),
  MultiObjects,
  UnsupportedVertex
}
<|endoftext|>


<commit_before>extern crate piston_window;
extern crate image as im;
extern crate vecmath;

use im::GenericImage;
use piston_window::*;
use vecmath::*;

fn main() {
    let opengl = OpenGL::V3_2;
    let (width, height) = (300, 300);
    let window: PistonWindow =
        WindowSettings::new("piston: paint", (width, height))
        .exit_on_esc(true)
        .opengl(opengl)
        .build()
        .unwrap();

    let mut canvas = im::ImageBuffer::new(width, height);
    let mut draw = false;
    let mut texture = Texture::from_image(
            &mut *window.factory.borrow_mut(),
            &canvas,
            &TextureSettings::new()
        ).unwrap();

    let mut last_pos = None;

    for e in window {
        e.draw_2d(|c, g| {
            clear([1.0; 4], g);
            image(&texture, c.transform, g);
        });
        if let Some(button) = e.press_args() {
            if button == Button::Mouse(MouseButton::Left) {
                draw = true;
                last_pos = e.mouse_cursor_args()
            }
        };
        if let Some(button) = e.release_args() {
            if button == Button::Mouse(MouseButton::Left) {
                draw = false;
                last_pos = None
            }
        };
        if draw {
            if let Some(pos) = e.mouse_cursor_args() {
                let (x, y) = (pos[0] as f32, pos[1] as f32);

                match last_pos {
                    Some(p) => {
                        let (last_x, last_y) = (p[0] as f32, p[1] as f32);
                        let distance = vec2_len(vec2_sub(p, pos)) as u32;

                        for i in 0..distance {
                            let diff_x = x - last_x;
                            let diff_y = y - last_y;
                            let delta = i as f32 / distance as f32;
                            let new_x = (last_x + (diff_x * delta)) as u32;
                            let new_y = (last_y + (diff_y * delta)) as u32;
                            if new_x < width && new_y < height {
                                canvas.put_pixel(new_x, new_y, im::Rgba([0, 0, 0, 255]));
                                texture.update(&mut*e.factory.borrow_mut(), &canvas).unwrap();
                            };
                        };
                    },
                    None => {}
                };

                last_pos = Some(pos)
            };

        }
    }
}

<commit_msg>condence single type match into if let<commit_after>extern crate piston_window;
extern crate image as im;
extern crate vecmath;

use im::GenericImage;
use piston_window::*;
use vecmath::*;

fn main() {
    let opengl = OpenGL::V3_2;
    let (width, height) = (300, 300);
    let window: PistonWindow =
        WindowSettings::new("piston: paint", (width, height))
        .exit_on_esc(true)
        .opengl(opengl)
        .build()
        .unwrap();

    let mut canvas = im::ImageBuffer::new(width, height);
    let mut draw = false;
    let mut texture = Texture::from_image(
            &mut *window.factory.borrow_mut(),
            &canvas,
            &TextureSettings::new()
        ).unwrap();

    let mut last_pos = None;

    for e in window {
        e.draw_2d(|c, g| {
            clear([1.0; 4], g);
            image(&texture, c.transform, g);
        });
        if let Some(button) = e.press_args() {
            if button == Button::Mouse(MouseButton::Left) {
                draw = true;
                last_pos = e.mouse_cursor_args()
            }
        };
        if let Some(button) = e.release_args() {
            if button == Button::Mouse(MouseButton::Left) {
                draw = false;
                last_pos = None
            }
        };
        if draw {
            if let Some(pos) = e.mouse_cursor_args() {
                let (x, y) = (pos[0] as f32, pos[1] as f32);

                if let Some(p) = last_pos {
                    let (last_x, last_y) = (p[0] as f32, p[1] as f32);
                    let distance = vec2_len(vec2_sub(p, pos)) as u32;

                    for i in 0..distance {
                        let diff_x = x - last_x;
                        let diff_y = y - last_y;
                        let delta = i as f32 / distance as f32;
                        let new_x = (last_x + (diff_x * delta)) as u32;
                        let new_y = (last_y + (diff_y * delta)) as u32;
                        if new_x < width && new_y < height {
                            canvas.put_pixel(new_x, new_y, im::Rgba([0, 0, 0, 255]));
                            texture.update(&mut*e.factory.borrow_mut(), &canvas).unwrap();
                        };
                    };
                };

                last_pos = Some(pos)
            };

        }
    }
}

<|endoftext|>


<commit_before>#![allow(clippy::rc_buffer)] // inner value is mutated before being shared (`Rc::get_mut`)

use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Context, Poll};

use actix_http::{http::Method, Error};
use actix_service::{Service, ServiceFactory};
use futures_util::future::{ready, FutureExt, LocalBoxFuture};

use crate::extract::FromRequest;
use crate::guard::{self, Guard};
use crate::handler::{Handler, HandlerService};
use crate::responder::Responder;
use crate::service::{ServiceRequest, ServiceResponse};
use crate::HttpResponse;

type BoxedRouteService = Box<
    dyn Service<
        ServiceRequest,
        Response = ServiceResponse,
        Error = Error,
        Future = LocalBoxFuture<'static, Result<ServiceResponse, Error>>,
    >,
>;

type BoxedRouteNewService = Box<
    dyn ServiceFactory<
        ServiceRequest,
        Config = (),
        Response = ServiceResponse,
        Error = Error,
        InitError = (),
        Service = BoxedRouteService,
        Future = LocalBoxFuture<'static, Result<BoxedRouteService, ()>>,
    >,
>;

/// Resource route definition
///
/// Route uses builder-like pattern for configuration.
/// If handler is not explicitly set, default *404 Not Found* handler is used.
pub struct Route {
    service: BoxedRouteNewService,
    guards: Rc<Vec<Box<dyn Guard>>>,
}

impl Route {
    /// Create new route which matches any request.
    #[allow(clippy::new_without_default)]
    pub fn new() -> Route {
        Route {
            service: Box::new(RouteNewService::new(HandlerService::new(|| {
                ready(HttpResponse::NotFound())
            }))),
            guards: Rc::new(Vec::new()),
        }
    }

    pub(crate) fn take_guards(&mut self) -> Vec<Box<dyn Guard>> {
        std::mem::take(Rc::get_mut(&mut self.guards).unwrap())
    }
}

impl ServiceFactory<ServiceRequest> for Route {
    type Config = ();
    type Response = ServiceResponse;
    type Error = Error;
    type InitError = ();
    type Service = RouteService;
    type Future = CreateRouteService;

    fn new_service(&self, _: ()) -> Self::Future {
        CreateRouteService {
            fut: self.service.new_service(()),
            guards: self.guards.clone(),
        }
    }
}

pub struct CreateRouteService {
    fut: LocalBoxFuture<'static, Result<BoxedRouteService, ()>>,
    guards: Rc<Vec<Box<dyn Guard>>>,
}

impl Future for CreateRouteService {
    type Output = Result<RouteService, ()>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let this = self.get_mut();

        match this.fut.as_mut().poll(cx)? {
            Poll::Ready(service) => Poll::Ready(Ok(RouteService {
                service,
                guards: this.guards.clone(),
            })),
            Poll::Pending => Poll::Pending,
        }
    }
}

pub struct RouteService {
    service: BoxedRouteService,
    guards: Rc<Vec<Box<dyn Guard>>>,
}

impl RouteService {
    pub fn check(&self, req: &mut ServiceRequest) -> bool {
        for f in self.guards.iter() {
            if !f.check(req.head()) {
                return false;
            }
        }
        true
    }
}

impl Service<ServiceRequest> for RouteService {
    type Response = ServiceResponse;
    type Error = Error;
    type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;

    fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.service.poll_ready(cx)
    }

    fn call(&self, req: ServiceRequest) -> Self::Future {
        self.service.call(req)
    }
}

impl Route {
    /// Add method guard to the route.
    ///
    /// ```rust
    /// # use actix_web::*;
    /// # fn main() {
    /// App::new().service(web::resource("/path").route(
    ///     web::get()
    ///         .method(http::Method::CONNECT)
    ///         .guard(guard::Header("content-type", "text/plain"))
    ///         .to(|req: HttpRequest| HttpResponse::Ok()))
    /// );
    /// # }
    /// ```
    pub fn method(mut self, method: Method) -> Self {
        Rc::get_mut(&mut self.guards)
            .unwrap()
            .push(Box::new(guard::Method(method)));
        self
    }

    /// Add guard to the route.
    ///
    /// ```rust
    /// # use actix_web::*;
    /// # fn main() {
    /// App::new().service(web::resource("/path").route(
    ///     web::route()
    ///         .guard(guard::Get())
    ///         .guard(guard::Header("content-type", "text/plain"))
    ///         .to(|req: HttpRequest| HttpResponse::Ok()))
    /// );
    /// # }
    /// ```
    pub fn guard<F: Guard + 'static>(mut self, f: F) -> Self {
        Rc::get_mut(&mut self.guards).unwrap().push(Box::new(f));
        self
    }

    /// Set handler function, use request extractors for parameters.
    ///
    /// ```rust
    /// use actix_web::{web, http, App};
    /// use serde_derive::Deserialize;
    ///
    /// #[derive(Deserialize)]
    /// struct Info {
    ///     username: String,
    /// }
    ///
    /// /// extract path info using serde
    /// async fn index(info: web::Path<Info>) -> String {
    ///     format!("Welcome {}!", info.username)
    /// }
    ///
    /// fn main() {
    ///     let app = App::new().service(
    ///         web::resource("/{username}/index.html") // <- define path parameters
    ///             .route(web::get().to(index))        // <- register handler
    ///     );
    /// }
    /// ```
    ///
    /// It is possible to use multiple extractors for one handler function.
    ///
    /// ```rust
    /// # use std::collections::HashMap;
    /// # use serde_derive::Deserialize;
    /// use actix_web::{web, App};
    ///
    /// #[derive(Deserialize)]
    /// struct Info {
    ///     username: String,
    /// }
    ///
    /// /// extract path info using serde
    /// async fn index(path: web::Path<Info>, query: web::Query<HashMap<String, String>>, body: web::Json<Info>) -> String {
    ///     format!("Welcome {}!", path.username)
    /// }
    ///
    /// fn main() {
    ///     let app = App::new().service(
    ///         web::resource("/{username}/index.html") // <- define path parameters
    ///             .route(web::get().to(index))
    ///     );
    /// }
    /// ```
    pub fn to<F, T, R>(mut self, handler: F) -> Self
    where
        F: Handler<T, R>,
        T: FromRequest + 'static,
        R: Future + 'static,
        R::Output: Responder + 'static,
    {
        self.service = Box::new(RouteNewService::new(HandlerService::new(handler)));
        self
    }
}

struct RouteNewService<T>
where
    T: ServiceFactory<ServiceRequest, Error = Error>,
{
    service: T,
}

impl<T> RouteNewService<T>
where
    T: ServiceFactory<ServiceRequest, Config = (), Response = ServiceResponse, Error = Error>,
    T::Future: 'static,
    T::Service: 'static,
    <T::Service as Service<ServiceRequest>>::Future: 'static,
{
    pub fn new(service: T) -> Self {
        RouteNewService { service }
    }
}

impl<T> ServiceFactory<ServiceRequest> for RouteNewService<T>
where
    T: ServiceFactory<ServiceRequest, Config = (), Response = ServiceResponse, Error = Error>,
    T::Future: 'static,
    T::Service: 'static,
    <T::Service as Service<ServiceRequest>>::Future: 'static,
{
    type Response = ServiceResponse;
    type Error = Error;
    type Config = ();
    type Service = BoxedRouteService;
    type InitError = ();
    type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;

    fn new_service(&self, _: ()) -> Self::Future {
        self.service
            .new_service(())
            .map(|result| match result {
                Ok(service) => {
                    let service = Box::new(RouteServiceWrapper { service }) as _;
                    Ok(service)
                }
                Err(_) => Err(()),
            })
            .boxed_local()
    }
}

struct RouteServiceWrapper<T: Service<ServiceRequest>> {
    service: T,
}

impl<T> Service<ServiceRequest> for RouteServiceWrapper<T>
where
    T::Future: 'static,
    T: Service<ServiceRequest, Response = ServiceResponse, Error = Error>,
{
    type Response = ServiceResponse;
    type Error = Error;
    type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;

    fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.service.poll_ready(cx)
    }

    fn call(&self, req: ServiceRequest) -> Self::Future {
        Box::pin(self.service.call(req))
    }
}

#[cfg(test)]
mod tests {
    use std::time::Duration;

    use actix_rt::time::sleep;
    use bytes::Bytes;
    use serde_derive::Serialize;

    use crate::http::{Method, StatusCode};
    use crate::test::{call_service, init_service, read_body, TestRequest};
    use crate::{error, web, App, HttpResponse};

    #[derive(Serialize, PartialEq, Debug)]
    struct MyObject {
        name: String,
    }

    #[actix_rt::test]
    async fn test_route() {
        let srv = init_service(
            App::new()
                .service(
                    web::resource("/test")
                        .route(web::get().to(HttpResponse::Ok))
                        .route(web::put().to(|| async {
                            Err::<HttpResponse, _>(error::ErrorBadRequest("err"))
                        }))
                        .route(web::post().to(|| async {
                            sleep(Duration::from_millis(100)).await;
                            Ok::<_, ()>(HttpResponse::Created())
                        }))
                        .route(web::delete().to(|| async {
                            sleep(Duration::from_millis(100)).await;
                            Err::<HttpResponse, _>(error::ErrorBadRequest("err"))
                        })),
                )
                .service(web::resource("/json").route(web::get().to(|| async {
                    sleep(Duration::from_millis(25)).await;
                    web::Json(MyObject {
                        name: "test".to_string(),
                    })
                }))),
        )
        .await;

        let req = TestRequest::with_uri("/test")
            .method(Method::GET)
            .to_request();
        let resp = call_service(&srv, req).await;
        assert_eq!(resp.status(), StatusCode::OK);

        let req = TestRequest::with_uri("/test")
            .method(Method::POST)
            .to_request();
        let resp = call_service(&srv, req).await;
        assert_eq!(resp.status(), StatusCode::CREATED);

        let req = TestRequest::with_uri("/test")
            .method(Method::PUT)
            .to_request();
        let resp = call_service(&srv, req).await;
        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);

        let req = TestRequest::with_uri("/test")
            .method(Method::DELETE)
            .to_request();
        let resp = call_service(&srv, req).await;
        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);

        let req = TestRequest::with_uri("/test")
            .method(Method::HEAD)
            .to_request();
        let resp = call_service(&srv, req).await;
        assert_eq!(resp.status(), StatusCode::METHOD_NOT_ALLOWED);

        let req = TestRequest::with_uri("/json").to_request();
        let resp = call_service(&srv, req).await;
        assert_eq!(resp.status(), StatusCode::OK);

        let body = read_body(resp).await;
        assert_eq!(body, Bytes::from_static(b"{\"name\":\"test\"}"));
    }
}
<commit_msg>refactor boxed route (#2033)<commit_after>#![allow(clippy::rc_buffer)] // inner value is mutated before being shared (`Rc::get_mut`)

use std::{future::Future, rc::Rc};

use actix_http::{http::Method, Error};
use actix_service::{
    boxed::{self, BoxService, BoxServiceFactory},
    Service, ServiceFactory,
};
use futures_core::future::LocalBoxFuture;

use crate::extract::FromRequest;
use crate::guard::{self, Guard};
use crate::handler::{Handler, HandlerService};
use crate::responder::Responder;
use crate::service::{ServiceRequest, ServiceResponse};
use crate::HttpResponse;

/// Resource route definition
///
/// Route uses builder-like pattern for configuration.
/// If handler is not explicitly set, default *404 Not Found* handler is used.
pub struct Route {
    service: BoxServiceFactory<(), ServiceRequest, ServiceResponse, Error, ()>,
    guards: Rc<Vec<Box<dyn Guard>>>,
}

impl Route {
    /// Create new route which matches any request.
    #[allow(clippy::new_without_default)]
    pub fn new() -> Route {
        Route {
            service: boxed::factory(HandlerService::new(HttpResponse::NotFound)),
            guards: Rc::new(Vec::new()),
        }
    }

    pub(crate) fn take_guards(&mut self) -> Vec<Box<dyn Guard>> {
        std::mem::take(Rc::get_mut(&mut self.guards).unwrap())
    }
}

impl ServiceFactory<ServiceRequest> for Route {
    type Response = ServiceResponse;
    type Error = Error;
    type Config = ();
    type Service = RouteService;
    type InitError = ();
    type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;

    fn new_service(&self, _: ()) -> Self::Future {
        let fut = self.service.new_service(());
        let guards = self.guards.clone();

        Box::pin(async move {
            let service = fut.await?;
            Ok(RouteService { service, guards })
        })
    }
}

pub struct RouteService {
    service: BoxService<ServiceRequest, ServiceResponse, Error>,
    guards: Rc<Vec<Box<dyn Guard>>>,
}

impl RouteService {
    pub fn check(&self, req: &mut ServiceRequest) -> bool {
        for f in self.guards.iter() {
            if !f.check(req.head()) {
                return false;
            }
        }
        true
    }
}

impl Service<ServiceRequest> for RouteService {
    type Response = ServiceResponse;
    type Error = Error;
    type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;

    actix_service::forward_ready!(service);

    fn call(&self, req: ServiceRequest) -> Self::Future {
        self.service.call(req)
    }
}

impl Route {
    /// Add method guard to the route.
    ///
    /// ```rust
    /// # use actix_web::*;
    /// # fn main() {
    /// App::new().service(web::resource("/path").route(
    ///     web::get()
    ///         .method(http::Method::CONNECT)
    ///         .guard(guard::Header("content-type", "text/plain"))
    ///         .to(|req: HttpRequest| HttpResponse::Ok()))
    /// );
    /// # }
    /// ```
    pub fn method(mut self, method: Method) -> Self {
        Rc::get_mut(&mut self.guards)
            .unwrap()
            .push(Box::new(guard::Method(method)));
        self
    }

    /// Add guard to the route.
    ///
    /// ```rust
    /// # use actix_web::*;
    /// # fn main() {
    /// App::new().service(web::resource("/path").route(
    ///     web::route()
    ///         .guard(guard::Get())
    ///         .guard(guard::Header("content-type", "text/plain"))
    ///         .to(|req: HttpRequest| HttpResponse::Ok()))
    /// );
    /// # }
    /// ```
    pub fn guard<F: Guard + 'static>(mut self, f: F) -> Self {
        Rc::get_mut(&mut self.guards).unwrap().push(Box::new(f));
        self
    }

    /// Set handler function, use request extractors for parameters.
    ///
    /// ```rust
    /// use actix_web::{web, http, App};
    /// use serde_derive::Deserialize;
    ///
    /// #[derive(Deserialize)]
    /// struct Info {
    ///     username: String,
    /// }
    ///
    /// /// extract path info using serde
    /// async fn index(info: web::Path<Info>) -> String {
    ///     format!("Welcome {}!", info.username)
    /// }
    ///
    /// fn main() {
    ///     let app = App::new().service(
    ///         web::resource("/{username}/index.html") // <- define path parameters
    ///             .route(web::get().to(index))        // <- register handler
    ///     );
    /// }
    /// ```
    ///
    /// It is possible to use multiple extractors for one handler function.
    ///
    /// ```rust
    /// # use std::collections::HashMap;
    /// # use serde_derive::Deserialize;
    /// use actix_web::{web, App};
    ///
    /// #[derive(Deserialize)]
    /// struct Info {
    ///     username: String,
    /// }
    ///
    /// /// extract path info using serde
    /// async fn index(path: web::Path<Info>, query: web::Query<HashMap<String, String>>, body: web::Json<Info>) -> String {
    ///     format!("Welcome {}!", path.username)
    /// }
    ///
    /// fn main() {
    ///     let app = App::new().service(
    ///         web::resource("/{username}/index.html") // <- define path parameters
    ///             .route(web::get().to(index))
    ///     );
    /// }
    /// ```
    pub fn to<F, T, R>(mut self, handler: F) -> Self
    where
        F: Handler<T, R>,
        T: FromRequest + 'static,
        R: Future + 'static,
        R::Output: Responder + 'static,
    {
        self.service = boxed::factory(HandlerService::new(handler));
        self
    }
}

#[cfg(test)]
mod tests {
    use std::time::Duration;

    use actix_rt::time::sleep;
    use bytes::Bytes;
    use serde_derive::Serialize;

    use crate::http::{Method, StatusCode};
    use crate::test::{call_service, init_service, read_body, TestRequest};
    use crate::{error, web, App, HttpResponse};

    #[derive(Serialize, PartialEq, Debug)]
    struct MyObject {
        name: String,
    }

    #[actix_rt::test]
    async fn test_route() {
        let srv = init_service(
            App::new()
                .service(
                    web::resource("/test")
                        .route(web::get().to(HttpResponse::Ok))
                        .route(web::put().to(|| async {
                            Err::<HttpResponse, _>(error::ErrorBadRequest("err"))
                        }))
                        .route(web::post().to(|| async {
                            sleep(Duration::from_millis(100)).await;
                            Ok::<_, ()>(HttpResponse::Created())
                        }))
                        .route(web::delete().to(|| async {
                            sleep(Duration::from_millis(100)).await;
                            Err::<HttpResponse, _>(error::ErrorBadRequest("err"))
                        })),
                )
                .service(web::resource("/json").route(web::get().to(|| async {
                    sleep(Duration::from_millis(25)).await;
                    web::Json(MyObject {
                        name: "test".to_string(),
                    })
                }))),
        )
        .await;

        let req = TestRequest::with_uri("/test")
            .method(Method::GET)
            .to_request();
        let resp = call_service(&srv, req).await;
        assert_eq!(resp.status(), StatusCode::OK);

        let req = TestRequest::with_uri("/test")
            .method(Method::POST)
            .to_request();
        let resp = call_service(&srv, req).await;
        assert_eq!(resp.status(), StatusCode::CREATED);

        let req = TestRequest::with_uri("/test")
            .method(Method::PUT)
            .to_request();
        let resp = call_service(&srv, req).await;
        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);

        let req = TestRequest::with_uri("/test")
            .method(Method::DELETE)
            .to_request();
        let resp = call_service(&srv, req).await;
        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);

        let req = TestRequest::with_uri("/test")
            .method(Method::HEAD)
            .to_request();
        let resp = call_service(&srv, req).await;
        assert_eq!(resp.status(), StatusCode::METHOD_NOT_ALLOWED);

        let req = TestRequest::with_uri("/json").to_request();
        let resp = call_service(&srv, req).await;
        assert_eq!(resp.status(), StatusCode::OK);

        let body = read_body(resp).await;
        assert_eq!(body, Bytes::from_static(b"{\"name\":\"test\"}"));
    }
}
<|endoftext|>


<commit_before>
use std::collections::hashmap::HashMap;
use uuid::Uuid;

use graphics::*;

use event::{
    Event,
    Behavior,
    State,
    Running,
};

use Sprite;

use animation::{
    Animation,
    AnimationState,
};

/// A scene is used to manage sprite's life and run animation with sprite
pub struct Scene<I: ImageSize> {
    children: Vec<Sprite<I>>,
    children_index: HashMap<Uuid, uint>,
    running: HashMap<Uuid,
        Vec<(Behavior<Animation>, State<Animation, AnimationState>, bool)>>,
}

impl<I: ImageSize> Scene<I> {
    /// Create a new scene
    pub fn new() -> Scene<I> {
        Scene {
            children: Vec::new(),
            children_index: HashMap::new(),
            running: HashMap::new(),
        }
    }

    /// Update animation's state
    pub fn event(&mut self, e: &Event) {
        // regenerate the animations and their states
        let running = self.running.clone();
        self.running.clear();

        for (id, animations) in running.into_iter() {
            let mut new_animations = Vec::new();

            for (b, mut a, paused) in animations.into_iter() {
                if paused {
                    new_animations.push((b, a, paused));
                    continue;
                }

                let sprite = self.child_mut(id).unwrap();
                let (status, _) = a.event(e, |_, dt, animation, s| {
                    let (state, status, remain) = {
                        let start_state;
                        let state = match *s {
                            None => { start_state = animation.to_state(sprite); &start_state },
                            Some(ref state) => state,
                        };
                        state.update(sprite, dt)
                    };
                    *s = state;
                    (status, remain)
                });

                match status {
                    // the behavior is still running, add it for next update
                    Running => {
                        new_animations.push((b, a, paused));
                    },
                    _ => {},
                }
            }

            if new_animations.len() > 0 {
                self.running.insert(id, new_animations);
            }
        }
    }

    /// Render this scene
    pub fn draw<B: BackEnd<I>>(&self, c: &Context, b: &mut B) {
        for child in self.children.iter() {
            child.draw(c, b);
        }
    }

    /// Register animation with sprite
    pub fn run(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        use std::collections::hashmap::{ Vacant, Occupied };
        let animations = match self.running.entry(sprite_id) {
            Vacant(entry) => entry.set(Vec::new()),
            Occupied(entry) => entry.into_mut()
        };
        let state = State::new(animation.clone());
        animations.push((animation.clone(), state, false));
    }

    fn find(&self, sprite_id: Uuid, animation: &Behavior<Animation>) -> Option<uint> {
        let mut index = None;
        match self.running.find(&sprite_id) {
            Some(animations) => {
                for i in range(0, animations.len()) {
                    let (ref b, _, _) = animations[i];
                    if b == animation {
                        index = Some(i);
                        break;
                    }
                }
            },
            _ => {},
        }
        index
    }

    /// Pause a running animation of the sprite
    pub fn pause(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        let index = self.find(sprite_id, animation);
        if index.is_some() {
            println!("found");
            let i = index.unwrap();
            let animations = self.running.get_mut(&sprite_id);
            let (b, s, _) = animations.remove(i).unwrap();
            animations.push((b, s, true));
        }
    }

    /// Resume a paused animation of the sprite
    pub fn resume(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        let index = self.find(sprite_id, animation);
        if index.is_some() {
            println!("found");
            let i = index.unwrap();
            let animations = self.running.get_mut(&sprite_id);
            let (b, s, _) = animations.remove(i).unwrap();
            animations.push((b, s, false));
        }
    }

    /// Toggle an animation of the sprite
    pub fn toggle(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        let index = self.find(sprite_id, animation);
        if index.is_some() {
            let i = index.unwrap();
            let animations = self.running.get_mut(&sprite_id);
            let (b, s, paused) = animations.remove(i).unwrap();
            animations.push((b, s, !paused));
        }
    }

    /// Stop a running animation of the sprite
    pub fn stop(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        let index = self.find(sprite_id, animation);
        if index.is_some() {
            let i = index.unwrap();
            self.running.get_mut(&sprite_id).remove(i);
        }
    }

    /// Stop all running animations of the sprite
    pub fn stop_all(&mut self, sprite_id: Uuid) {
        self.running.remove(&sprite_id);
    }

    /// Get all the running animations in the scene
    pub fn running(&self) -> uint {
        let mut total = 0;
        for (_, animations) in self.running.iter() {
            total += animations.len();
        }
        total
    }

    /// Add sprite to scene
    pub fn add_child(&mut self, sprite: Sprite<I>) -> Uuid {
        let id = sprite.id();
        self.children.push(sprite);
        self.children_index.insert(id, self.children.len() - 1);
        id
    }

    fn stop_all_including_children(&mut self, sprite: &Sprite<I>) {
        self.stop_all(sprite.id());
        for child in sprite.children().iter() {
            self.stop_all_including_children(child);
        }
    }

    /// Remove the child by `id` from the scene's children or grandchild
    /// will stop all the animations run by this child
    pub fn remove_child(&mut self, id: Uuid) -> Option<Sprite<I>> {
        let removed = match self.children_index.pop(&id) {
            Some(i) => {
                let removed = self.children.remove(i).unwrap();
                // Removing a element of vector will alter the index,
                // update the mapping from uuid to index.
                for index in range(i, self.children.len()) {
                    let uuid = self.children[index].id();
                    self.children_index.insert(uuid, index);
                }
                Some(removed)
            },
            None => {
                for child in self.children.iter_mut() {
                    match child.remove_child(id) {
                        Some(c) => {
                            return Some(c);
                        }
                        _ => {}
                    }
                }

                None
            }
        };

        if removed.is_some() {
            self.stop_all_including_children(removed.as_ref().unwrap());
        }

        removed
    }

    /// Find the child by `id` from the scene's children or grandchild
    pub fn child(&self, id: Uuid) -> Option<&Sprite<I>> {
        match self.children_index.find(&id) {
            Some(i) => { Some(&self.children[*i]) },
            None => {
                for child in self.children.iter() {
                    match child.child(id) {
                        Some(c) => {
                            return Some(c);
                        }
                        _ => {}
                    }
                }

                None
            }
        }
    }

    /// Find the child by `id` from this sprite's children or grandchild, mutability
    pub fn child_mut(&mut self, id: Uuid) -> Option<&mut Sprite<I>> {
        match self.children_index.find(&id) {
            Some(i) => { Some(self.children.get_mut(*i)) },
            None => {
                for child in self.children.iter_mut() {
                    match child.child_mut(id) {
                        Some(c) => {
                            return Some(c);
                        }
                        _ => {}
                    }
                }

                None
            }
        }
    }
}
<commit_msg>Use GenericEvent<commit_after>
use std::collections::hashmap::HashMap;
use uuid::Uuid;

use graphics::*;

use event::{
    GenericEvent,
    Behavior,
    State,
    Running,
};

use Sprite;

use animation::{
    Animation,
    AnimationState,
};

/// A scene is used to manage sprite's life and run animation with sprite
pub struct Scene<I: ImageSize> {
    children: Vec<Sprite<I>>,
    children_index: HashMap<Uuid, uint>,
    running: HashMap<Uuid,
        Vec<(Behavior<Animation>, State<Animation, AnimationState>, bool)>>,
}

impl<I: ImageSize> Scene<I> {
    /// Create a new scene
    pub fn new() -> Scene<I> {
        Scene {
            children: Vec::new(),
            children_index: HashMap::new(),
            running: HashMap::new(),
        }
    }

    /// Update animation's state
    pub fn event<E: GenericEvent>(&mut self, e: &E) {
        // regenerate the animations and their states
        let running = self.running.clone();
        self.running.clear();

        for (id, animations) in running.into_iter() {
            let mut new_animations = Vec::new();

            for (b, mut a, paused) in animations.into_iter() {
                if paused {
                    new_animations.push((b, a, paused));
                    continue;
                }

                let sprite = self.child_mut(id).unwrap();
                let (status, _) = a.event(e, |_, dt, animation, s| {
                    let (state, status, remain) = {
                        let start_state;
                        let state = match *s {
                            None => { start_state = animation.to_state(sprite); &start_state },
                            Some(ref state) => state,
                        };
                        state.update(sprite, dt)
                    };
                    *s = state;
                    (status, remain)
                });

                match status {
                    // the behavior is still running, add it for next update
                    Running => {
                        new_animations.push((b, a, paused));
                    },
                    _ => {},
                }
            }

            if new_animations.len() > 0 {
                self.running.insert(id, new_animations);
            }
        }
    }

    /// Render this scene
    pub fn draw<B: BackEnd<I>>(&self, c: &Context, b: &mut B) {
        for child in self.children.iter() {
            child.draw(c, b);
        }
    }

    /// Register animation with sprite
    pub fn run(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        use std::collections::hashmap::{ Vacant, Occupied };
        let animations = match self.running.entry(sprite_id) {
            Vacant(entry) => entry.set(Vec::new()),
            Occupied(entry) => entry.into_mut()
        };
        let state = State::new(animation.clone());
        animations.push((animation.clone(), state, false));
    }

    fn find(&self, sprite_id: Uuid, animation: &Behavior<Animation>) -> Option<uint> {
        let mut index = None;
        match self.running.find(&sprite_id) {
            Some(animations) => {
                for i in range(0, animations.len()) {
                    let (ref b, _, _) = animations[i];
                    if b == animation {
                        index = Some(i);
                        break;
                    }
                }
            },
            _ => {},
        }
        index
    }

    /// Pause a running animation of the sprite
    pub fn pause(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        let index = self.find(sprite_id, animation);
        if index.is_some() {
            println!("found");
            let i = index.unwrap();
            let animations = self.running.get_mut(&sprite_id);
            let (b, s, _) = animations.remove(i).unwrap();
            animations.push((b, s, true));
        }
    }

    /// Resume a paused animation of the sprite
    pub fn resume(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        let index = self.find(sprite_id, animation);
        if index.is_some() {
            println!("found");
            let i = index.unwrap();
            let animations = self.running.get_mut(&sprite_id);
            let (b, s, _) = animations.remove(i).unwrap();
            animations.push((b, s, false));
        }
    }

    /// Toggle an animation of the sprite
    pub fn toggle(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        let index = self.find(sprite_id, animation);
        if index.is_some() {
            let i = index.unwrap();
            let animations = self.running.get_mut(&sprite_id);
            let (b, s, paused) = animations.remove(i).unwrap();
            animations.push((b, s, !paused));
        }
    }

    /// Stop a running animation of the sprite
    pub fn stop(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        let index = self.find(sprite_id, animation);
        if index.is_some() {
            let i = index.unwrap();
            self.running.get_mut(&sprite_id).remove(i);
        }
    }

    /// Stop all running animations of the sprite
    pub fn stop_all(&mut self, sprite_id: Uuid) {
        self.running.remove(&sprite_id);
    }

    /// Get all the running animations in the scene
    pub fn running(&self) -> uint {
        let mut total = 0;
        for (_, animations) in self.running.iter() {
            total += animations.len();
        }
        total
    }

    /// Add sprite to scene
    pub fn add_child(&mut self, sprite: Sprite<I>) -> Uuid {
        let id = sprite.id();
        self.children.push(sprite);
        self.children_index.insert(id, self.children.len() - 1);
        id
    }

    fn stop_all_including_children(&mut self, sprite: &Sprite<I>) {
        self.stop_all(sprite.id());
        for child in sprite.children().iter() {
            self.stop_all_including_children(child);
        }
    }

    /// Remove the child by `id` from the scene's children or grandchild
    /// will stop all the animations run by this child
    pub fn remove_child(&mut self, id: Uuid) -> Option<Sprite<I>> {
        let removed = match self.children_index.pop(&id) {
            Some(i) => {
                let removed = self.children.remove(i).unwrap();
                // Removing a element of vector will alter the index,
                // update the mapping from uuid to index.
                for index in range(i, self.children.len()) {
                    let uuid = self.children[index].id();
                    self.children_index.insert(uuid, index);
                }
                Some(removed)
            },
            None => {
                for child in self.children.iter_mut() {
                    match child.remove_child(id) {
                        Some(c) => {
                            return Some(c);
                        }
                        _ => {}
                    }
                }

                None
            }
        };

        if removed.is_some() {
            self.stop_all_including_children(removed.as_ref().unwrap());
        }

        removed
    }

    /// Find the child by `id` from the scene's children or grandchild
    pub fn child(&self, id: Uuid) -> Option<&Sprite<I>> {
        match self.children_index.find(&id) {
            Some(i) => { Some(&self.children[*i]) },
            None => {
                for child in self.children.iter() {
                    match child.child(id) {
                        Some(c) => {
                            return Some(c);
                        }
                        _ => {}
                    }
                }

                None
            }
        }
    }

    /// Find the child by `id` from this sprite's children or grandchild, mutability
    pub fn child_mut(&mut self, id: Uuid) -> Option<&mut Sprite<I>> {
        match self.children_index.find(&id) {
            Some(i) => { Some(self.children.get_mut(*i)) },
            None => {
                for child in self.children.iter_mut() {
                    match child.child_mut(id) {
                        Some(c) => {
                            return Some(c);
                        }
                        _ => {}
                    }
                }

                None
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::io::FilePermission;
use std::io::fs::{File, copy, mkdir, chmod};
use std::io::fs::PathExtensions;
use std::default::Default;
use std::collections::TreeMap;

use quire::parse_config;

use super::mount::{bind_mount, mount_ro_recursive, mount_tmpfs, mount_private};
use super::mount::{mount_pseudo};
use super::network::{get_host_ip, get_host_name};
use super::tree_config::TreeConfig;
use super::container_config::{ContainerConfig, Readonly, Persistent, Tmpfs};
use super::container_config::{Statedir};
use super::container_config::{parse_volume};
use super::child_config::ChildConfig;
use super::utils::temporary_change_root;

fn map_dir(dir: &Path, dirs: &TreeMap<String, String>) -> Option<Path> {
    assert!(dir.is_absolute());
    for (prefix, real_dir) in dirs.iter() {
        let dir_prefix = Path::new(prefix.as_slice());
        if dir_prefix.is_ancestor_of(dir) {
            match dir.path_relative_from(&dir_prefix) {
                Some(tail) => {
                    assert!(!tail.is_absolute());
                    return Some(Path::new(real_dir.as_slice()).join(tail));
                }
                None => continue,
            }
        }
    }
    return None;
}

pub fn setup_filesystem(global: &TreeConfig, local: &ContainerConfig,
    state_dir: &Path)
    -> Result<(), String>
{
    let root = Path::new("/");
    let mntdir = global.mount_dir.clone();
    assert!(mntdir.is_absolute());

    let mut volumes: Vec<(&String, &String)> = local.volumes.iter().collect();
    volumes.sort_by(|&(mp1, _), &(mp2, _)| mp1.len().cmp(&mp2.len()));

    for &(mp_str, volume_str) in volumes.iter() {
        let tmp_mp = Path::new(mp_str.as_slice());
        assert!(tmp_mp.is_absolute());  // should be checked earlier

        let dest = mntdir.join(tmp_mp.path_relative_from(&root).unwrap());
        match try_str!(parse_volume(volume_str.as_slice())) {
            Readonly(dir) => {
                let path = match map_dir(&dir, &global.readonly_paths).or_else(
                                 || map_dir(&dir, &global.writable_paths)) {
                    None => {
                        return Err(format!(concat!("Can't find volume for {},",
                            " probably missing entry in readonly-paths"),
                            dir.display()));
                    }
                    Some(path) => path,
                };
                try!(bind_mount(&path, &dest));
                try!(mount_ro_recursive(&dest));
            }
            Persistent(dir) => {
                let path = match map_dir(&dir, &global.writable_paths) {
                    None => {
                        return Err(format!(concat!("Can't find volume for {},",
                            " probably missing entry in writable-paths"),
                            dir.display()));
                    }
                    Some(path) => path,
                };
                try!(bind_mount(&path, &dest));
                try_str!(mount_private(&dest));
            }
            Tmpfs(opt) => {
                try!(mount_tmpfs(&dest, opt.as_slice()));
            }
            Statedir(dir) => {
                let relative_dir = dir.path_relative_from(&root).unwrap();
                try!(bind_mount(
                    &state_dir.join(relative_dir),
                    &dest));
                try_str!(mount_private(&dest));
            }
        }
    }
    let devdir = mntdir.join("dev");
    try!(bind_mount(&Path::new(global.devfs_dir.as_slice()), &devdir));
    try!(mount_ro_recursive(&devdir));
    try!(mount_pseudo(&mntdir.join("sys"), "sysfs", "", true));
    try!(mount_pseudo(&mntdir.join("proc"), "proc", "", false));

    return Ok(());
}

pub fn prepare_state_dir(dir: &Path, _global: &TreeConfig,
                         local: &ContainerConfig)
    -> Result<(), String>
{
    // TODO(tailhook) chown files
    if !dir.exists() {
        try_str!(mkdir(dir, FilePermission::from_bits_truncate(0o755)));
    }
    if local.resolv_conf.copy_from_host {
        try_str!(copy(&Path::new("/etc/resolv.conf"),
                      &dir.join("resolv.conf")));
    }
    if local.hosts_file.localhost || local.hosts_file.public_hostname {
        let fname = dir.join("hosts");
        let mut file = try_str!(File::create(&fname));
        if local.hosts_file.localhost {
            try_str!(file.write_str(
                "127.0.0.1 localhost.localdomain localhost\n"));
        }
        if local.hosts_file.public_hostname {
            try_str!(writeln!(file, "{} {}",
                try_str!(get_host_ip()),
                try_str!(get_host_name())));
        }
        try_str!(chmod(&fname, FilePermission::from_bits_truncate(0o644)));
    }
    return Ok(());
}

pub fn read_local_config(global_cfg: &TreeConfig, child_cfg: &ChildConfig)
    -> Result<ContainerConfig, String>
{
    let image_path = global_cfg.image_dir.join(&child_cfg.image);
    try!(bind_mount(&image_path, &global_cfg.mount_dir));
    try!(mount_ro_recursive(&global_cfg.mount_dir));
    return temporary_change_root(&global_cfg.mount_dir, || {
        parse_config(&child_cfg.config,
            &*ContainerConfig::validator(), Default::default())
    });
}
<commit_msg>Implement auto-mkdir for `rw` volumes<commit_after>use std::io::FilePermission;
use std::io::fs::{File, copy, mkdir, chmod, mkdir_recursive, chown};
use std::io::fs::PathExtensions;
use std::default::Default;
use std::collections::TreeMap;

use quire::parse_config;

use super::mount::{bind_mount, mount_ro_recursive, mount_tmpfs, mount_private};
use super::mount::{mount_pseudo};
use super::network::{get_host_ip, get_host_name};
use super::tree_config::TreeConfig;
use super::container_config::{ContainerConfig, Readonly, Persistent, Tmpfs};
use super::container_config::{Statedir};
use super::container_config::{parse_volume};
use super::child_config::ChildConfig;
use super::utils::temporary_change_root;

fn map_dir(dir: &Path, dirs: &TreeMap<String, String>) -> Option<Path> {
    assert!(dir.is_absolute());
    for (prefix, real_dir) in dirs.iter() {
        let dir_prefix = Path::new(prefix.as_slice());
        if dir_prefix.is_ancestor_of(dir) {
            match dir.path_relative_from(&dir_prefix) {
                Some(tail) => {
                    assert!(!tail.is_absolute());
                    return Some(Path::new(real_dir.as_slice()).join(tail));
                }
                None => continue,
            }
        }
    }
    return None;
}

pub fn setup_filesystem(global: &TreeConfig, local: &ContainerConfig,
    state_dir: &Path)
    -> Result<(), String>
{
    let root = Path::new("/");
    let mntdir = global.mount_dir.clone();
    assert!(mntdir.is_absolute());

    let mut volumes: Vec<(&String, &String)> = local.volumes.iter().collect();
    volumes.sort_by(|&(mp1, _), &(mp2, _)| mp1.len().cmp(&mp2.len()));

    for &(mp_str, volume_str) in volumes.iter() {
        let tmp_mp = Path::new(mp_str.as_slice());
        assert!(tmp_mp.is_absolute());  // should be checked earlier

        let dest = mntdir.join(tmp_mp.path_relative_from(&root).unwrap());
        match try_str!(parse_volume(volume_str.as_slice())) {
            Readonly(dir) => {
                let path = match map_dir(&dir, &global.readonly_paths).or_else(
                                 || map_dir(&dir, &global.writable_paths)) {
                    None => {
                        return Err(format!(concat!("Can't find volume for {},",
                            " probably missing entry in readonly-paths"),
                            dir.display()));
                    }
                    Some(path) => path,
                };
                try!(bind_mount(&path, &dest));
                try!(mount_ro_recursive(&dest));
            }
            Persistent(dir) => {
                let path = match map_dir(&dir, &global.writable_paths) {
                    None => {
                        return Err(format!(concat!("Can't find volume for {},",
                            " probably missing entry in writable-paths"),
                            dir.display()));
                    }
                    Some(path) => path,
                };
                // TODO(tailhook) make it parametrized
                if !path.exists() {
                    try_str!(mkdir_recursive(&path,
                        FilePermission::from_bits_truncate(0o755)));
                    try_str!(chown(&path, local.user_id as int, -1));
                }
                try!(bind_mount(&path, &dest));
                try_str!(mount_private(&dest));
            }
            Tmpfs(opt) => {
                try!(mount_tmpfs(&dest, opt.as_slice()));
            }
            Statedir(dir) => {
                let relative_dir = dir.path_relative_from(&root).unwrap();
                try!(bind_mount(
                    &state_dir.join(relative_dir),
                    &dest));
                try_str!(mount_private(&dest));
            }
        }
    }
    let devdir = mntdir.join("dev");
    try!(bind_mount(&Path::new(global.devfs_dir.as_slice()), &devdir));
    try!(mount_ro_recursive(&devdir));
    try!(mount_pseudo(&mntdir.join("sys"), "sysfs", "", true));
    try!(mount_pseudo(&mntdir.join("proc"), "proc", "", false));

    return Ok(());
}

pub fn prepare_state_dir(dir: &Path, _global: &TreeConfig,
                         local: &ContainerConfig)
    -> Result<(), String>
{
    // TODO(tailhook) chown files
    if !dir.exists() {
        try_str!(mkdir(dir, FilePermission::from_bits_truncate(0o755)));
    }
    if local.resolv_conf.copy_from_host {
        try_str!(copy(&Path::new("/etc/resolv.conf"),
                      &dir.join("resolv.conf")));
    }
    if local.hosts_file.localhost || local.hosts_file.public_hostname {
        let fname = dir.join("hosts");
        let mut file = try_str!(File::create(&fname));
        if local.hosts_file.localhost {
            try_str!(file.write_str(
                "127.0.0.1 localhost.localdomain localhost\n"));
        }
        if local.hosts_file.public_hostname {
            try_str!(writeln!(file, "{} {}",
                try_str!(get_host_ip()),
                try_str!(get_host_name())));
        }
        try_str!(chmod(&fname, FilePermission::from_bits_truncate(0o644)));
    }
    return Ok(());
}

pub fn read_local_config(global_cfg: &TreeConfig, child_cfg: &ChildConfig)
    -> Result<ContainerConfig, String>
{
    let image_path = global_cfg.image_dir.join(&child_cfg.image);
    try!(bind_mount(&image_path, &global_cfg.mount_dir));
    try!(mount_ro_recursive(&global_cfg.mount_dir));
    return temporary_change_root(&global_cfg.mount_dir, || {
        parse_config(&child_cfg.config,
            &*ContainerConfig::validator(), Default::default())
    });
}
<|endoftext|>