<commit_before>//! List projects
//!
//! https://docs.gitlab.com/ce/api/projects.html
//!
//! # List projects
//!
//! Get a list of projects for which the authenticated user is a member.
//!
//! ```text
//! GET /projects
//! ```
//!
//! Parameters:
//!
//! | Attribute | Type | Required | Description |
//! | --------- | ---- | -------- | ----------- |
//! | `archived` | boolean | no | Limit by archived status |
//! | `visibility` | string | no | Limit by visibility `public`, `internal`, or `private` |
//! | `order_by` | string | no | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at` |
//! | `sort` | string | no | Return projects sorted in `asc` or `desc` order. Default is `desc` |
//! | `search` | string | no | Return list of authorized projects matching the search criteria |
//! | `simple` | boolean | no | Return only the ID, URL, name, and path of each project |
//!

use serde_urlencoded;

use BuildQuery;
use Project;
use Projects;

pub mod all;
pub mod id_branches;
pub mod id_branch;
pub mod id_events;
pub mod id_hooks_id;
pub mod id_hooks;
pub mod id;
pub mod owned;
pub mod search;
pub mod starred;
pub mod visible;

use ::errors::*;

#[cfg(feature = "serde_derive")]
include!("serde_types.in.rs");

#[cfg(feature = "serde_codegen")]
include!(concat!(env!("OUT_DIR"), "/projects/serde_types.rs"));

#[derive(Debug, Clone)]
pub struct ProjectsLister<'a> {
    gl: &'a ::GitLab,
    internal: ProjectListerInternal,
}

impl<'a> ProjectsLister<'a> {
    pub fn new(gl: &'a ::GitLab) -> ProjectsLister {
        ProjectsLister {
            gl: gl,
            internal: ProjectListerInternal {
                archived: None,
                visibility: None,
                order_by: None,
                sort: None,
                search: None,
                simple: None,
            },
        }
    }

    pub fn all(self) -> all::ProjectsLister<'a> {
        // assert_eq!(self, ProjectsLister::new(self.gl));
        all::ProjectsLister::new(self.gl)
    }

    pub fn owned(self) -> owned::ProjectsLister<'a> {
        // assert_eq!(self, ProjectsLister::new(self.gl));
        owned::ProjectsLister::new(self.gl)
    }

    pub fn search(self, query: String) -> search::ProjectsLister<'a> {
        // assert_eq!(self, ProjectsLister::new(self.gl));
        search::ProjectsLister::new(self.gl, query)
    }

    pub fn id(self, id: ListingId) -> id::ProjectsLister<'a> {
        // assert_eq!(self, ProjectsLister::new(self.gl));
        id::ProjectsLister::new(self.gl, id)
    }

    pub fn archived(&'a mut self, archived: bool) -> &'a mut ProjectsLister {
        self.internal.archived = Some(archived);
        self
    }

    pub fn visibility(&'a mut self, visibility: ::ListingVisibility) -> &'a mut ProjectsLister {
        self.internal.visibility = Some(visibility);
        self
    }

    pub fn order_by(&'a mut self, order_by: ListingOrderBy) -> &'a mut ProjectsLister {
        self.internal.order_by = Some(order_by);
        self
    }

    pub fn sort(&'a mut self, sort: ::ListingSort) -> &'a mut ProjectsLister {
        self.internal.sort = Some(sort);
        self
    }

    pub fn search_pattern(&'a mut self, search: String) -> &'a mut ProjectsLister {
        self.internal.search = Some(search);
        self
    }

    pub fn simple(&'a mut self, simple: bool) -> &'a mut ProjectsLister {
        self.internal.simple = Some(simple);
        self
    }

    /// Commit the lister: Query GitLab and return a list of projects.
    pub fn list(&self) -> Result<Projects> {
        let query = self.build_query();
        debug!("query: {:?}", query);

        self.gl.get(&query).chain_err(|| format!("cannot get query {}", query))
    }
}

impl<'a> BuildQuery for ProjectsLister<'a> {
    fn build_query(&self) -> String {

        let encoded = serde_urlencoded::to_string(&self.internal).unwrap();
        let mut query = String::from("projects");
        if !encoded.is_empty() {
            query.push_str("?");
            query.push_str(&encoded);
        }

        query
    }
}

impl<'a> Project {
    /// Return a lister for the project's issues
    pub fn issues(&'a self, gl: &'a ::GitLab) -> ::issues::IssuesLister {
        ::issues::IssuesLister::new(gl)
    }

    /// Return a lister for the project's merge requests
    pub fn merge_requests(&'a self, gl: &'a ::GitLab) -> ::merge_requests::MergeRequestsLister {
        ::merge_requests::MergeRequestsLister::new(gl)
    }
}

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

    #[test]
    fn build_query_default() {
        let expected_string = "projects";

        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let projects_lister = gl.projects();
        let query = projects_lister.build_query();
        assert_eq!(query, expected_string);

        let query = gl.projects().build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_archived() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?archived=true";

        let mut projects_lister = gl.projects();
        let query = projects_lister.archived(true).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().archived(true).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?archived=false";

        let mut projects_lister = gl.projects();
        let query = projects_lister.archived(false).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().archived(false).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_visibility() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?visibility=public";
        let mut projects_lister = gl.projects();
        let query = projects_lister.visibility(::ListingVisibility::Public).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().visibility(::ListingVisibility::Public).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?visibility=internal";
        let mut projects_lister = gl.projects();
        let query = projects_lister.visibility(::ListingVisibility::Internal).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().visibility(::ListingVisibility::Internal).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?visibility=private";
        let mut projects_lister = gl.projects();
        let query = projects_lister.visibility(::ListingVisibility::Private).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().visibility(::ListingVisibility::Private).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_order_by() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?order_by=id";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::Id).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().order_by(::projects::ListingOrderBy::Id).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=name";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::Name).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().order_by(::projects::ListingOrderBy::Name).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=path";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::Path).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().order_by(::projects::ListingOrderBy::Path).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=created_at";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::CreatedAt).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().order_by(::projects::ListingOrderBy::CreatedAt).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=updated_at";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::UpdatedAt).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().order_by(::projects::ListingOrderBy::UpdatedAt).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=last_activity_at";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::LastActivityAt)
            .build_query();
        assert_eq!(query, expected_string);
        let query =
            gl.projects().order_by(::projects::ListingOrderBy::LastActivityAt).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_sort() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?sort=asc";
        let mut projects_lister = gl.projects();
        let query = projects_lister.sort(::ListingSort::Asc).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().sort(::ListingSort::Asc).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?sort=desc";
        let mut projects_lister = gl.projects();
        let query = projects_lister.sort(::ListingSort::Desc).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().sort(::ListingSort::Desc).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_search() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?search=SearchPattern";
        let mut projects_lister = gl.projects();
        let query = projects_lister.search_pattern(String::from("SearchPattern")).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().search_pattern(String::from("SearchPattern")).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_simple() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?simple=true";
        let mut projects_lister = gl.projects();
        let query = projects_lister.simple(true).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().simple(true).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?simple=false";
        let mut projects_lister = gl.projects();
        let query = projects_lister.simple(false).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().simple(false).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn groups_build_query_multiple() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?archived=true&simple=true";
        let mut projects_lister = gl.projects();
        let query = projects_lister.archived(true).simple(true).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().archived(true).simple(true).build_query();
        assert_eq!(query, expected_string);
    }
}
<commit_msg>Bug fix: `Project::issues()` should create a `issues::project::IssuesLister`<commit_after>//! List projects
//!
//! https://docs.gitlab.com/ce/api/projects.html
//!
//! # List projects
//!
//! Get a list of projects for which the authenticated user is a member.
//!
//! ```text
//! GET /projects
//! ```
//!
//! Parameters:
//!
//! | Attribute | Type | Required | Description |
//! | --------- | ---- | -------- | ----------- |
//! | `archived` | boolean | no | Limit by archived status |
//! | `visibility` | string | no | Limit by visibility `public`, `internal`, or `private` |
//! | `order_by` | string | no | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at` |
//! | `sort` | string | no | Return projects sorted in `asc` or `desc` order. Default is `desc` |
//! | `search` | string | no | Return list of authorized projects matching the search criteria |
//! | `simple` | boolean | no | Return only the ID, URL, name, and path of each project |
//!

use serde_urlencoded;

use BuildQuery;
use Project;
use Projects;

pub mod all;
pub mod id_branches;
pub mod id_branch;
pub mod id_events;
pub mod id_hooks_id;
pub mod id_hooks;
pub mod id;
pub mod owned;
pub mod search;
pub mod starred;
pub mod visible;

use ::errors::*;

#[cfg(feature = "serde_derive")]
include!("serde_types.in.rs");

#[cfg(feature = "serde_codegen")]
include!(concat!(env!("OUT_DIR"), "/projects/serde_types.rs"));

#[derive(Debug, Clone)]
pub struct ProjectsLister<'a> {
    gl: &'a ::GitLab,
    internal: ProjectListerInternal,
}

impl<'a> ProjectsLister<'a> {
    pub fn new(gl: &'a ::GitLab) -> ProjectsLister {
        ProjectsLister {
            gl: gl,
            internal: ProjectListerInternal {
                archived: None,
                visibility: None,
                order_by: None,
                sort: None,
                search: None,
                simple: None,
            },
        }
    }

    pub fn all(self) -> all::ProjectsLister<'a> {
        // assert_eq!(self, ProjectsLister::new(self.gl));
        all::ProjectsLister::new(self.gl)
    }

    pub fn owned(self) -> owned::ProjectsLister<'a> {
        // assert_eq!(self, ProjectsLister::new(self.gl));
        owned::ProjectsLister::new(self.gl)
    }

    pub fn search(self, query: String) -> search::ProjectsLister<'a> {
        // assert_eq!(self, ProjectsLister::new(self.gl));
        search::ProjectsLister::new(self.gl, query)
    }

    pub fn id(self, id: ListingId) -> id::ProjectsLister<'a> {
        // assert_eq!(self, ProjectsLister::new(self.gl));
        id::ProjectsLister::new(self.gl, id)
    }

    pub fn archived(&'a mut self, archived: bool) -> &'a mut ProjectsLister {
        self.internal.archived = Some(archived);
        self
    }

    pub fn visibility(&'a mut self, visibility: ::ListingVisibility) -> &'a mut ProjectsLister {
        self.internal.visibility = Some(visibility);
        self
    }

    pub fn order_by(&'a mut self, order_by: ListingOrderBy) -> &'a mut ProjectsLister {
        self.internal.order_by = Some(order_by);
        self
    }

    pub fn sort(&'a mut self, sort: ::ListingSort) -> &'a mut ProjectsLister {
        self.internal.sort = Some(sort);
        self
    }

    pub fn search_pattern(&'a mut self, search: String) -> &'a mut ProjectsLister {
        self.internal.search = Some(search);
        self
    }

    pub fn simple(&'a mut self, simple: bool) -> &'a mut ProjectsLister {
        self.internal.simple = Some(simple);
        self
    }

    /// Commit the lister: Query GitLab and return a list of projects.
    pub fn list(&self) -> Result<Projects> {
        let query = self.build_query();
        debug!("query: {:?}", query);

        self.gl.get(&query).chain_err(|| format!("cannot get query {}", query))
    }
}

impl<'a> BuildQuery for ProjectsLister<'a> {
    fn build_query(&self) -> String {

        let encoded = serde_urlencoded::to_string(&self.internal).unwrap();
        let mut query = String::from("projects");
        if !encoded.is_empty() {
            query.push_str("?");
            query.push_str(&encoded);
        }

        query
    }
}

impl<'a> Project {
    /// Return a lister for the project's issues
    pub fn issues(&'a self, gl: &'a ::GitLab) -> ::issues::project::IssuesLister {
        ::issues::project::IssuesLister::new(gl, self.id)
    }

    /// Return a lister for the project's merge requests
    pub fn merge_requests(&'a self, gl: &'a ::GitLab) -> ::merge_requests::MergeRequestsLister {
        ::merge_requests::MergeRequestsLister::new(gl)
    }
}

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

    #[test]
    fn build_query_default() {
        let expected_string = "projects";

        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let projects_lister = gl.projects();
        let query = projects_lister.build_query();
        assert_eq!(query, expected_string);

        let query = gl.projects().build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_archived() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?archived=true";

        let mut projects_lister = gl.projects();
        let query = projects_lister.archived(true).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().archived(true).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?archived=false";

        let mut projects_lister = gl.projects();
        let query = projects_lister.archived(false).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().archived(false).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_visibility() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?visibility=public";
        let mut projects_lister = gl.projects();
        let query = projects_lister.visibility(::ListingVisibility::Public).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().visibility(::ListingVisibility::Public).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?visibility=internal";
        let mut projects_lister = gl.projects();
        let query = projects_lister.visibility(::ListingVisibility::Internal).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().visibility(::ListingVisibility::Internal).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?visibility=private";
        let mut projects_lister = gl.projects();
        let query = projects_lister.visibility(::ListingVisibility::Private).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().visibility(::ListingVisibility::Private).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_order_by() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?order_by=id";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::Id).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().order_by(::projects::ListingOrderBy::Id).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=name";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::Name).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().order_by(::projects::ListingOrderBy::Name).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=path";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::Path).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().order_by(::projects::ListingOrderBy::Path).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=created_at";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::CreatedAt).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().order_by(::projects::ListingOrderBy::CreatedAt).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=updated_at";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::UpdatedAt).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().order_by(::projects::ListingOrderBy::UpdatedAt).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=last_activity_at";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::LastActivityAt)
            .build_query();
        assert_eq!(query, expected_string);
        let query =
            gl.projects().order_by(::projects::ListingOrderBy::LastActivityAt).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_sort() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?sort=asc";
        let mut projects_lister = gl.projects();
        let query = projects_lister.sort(::ListingSort::Asc).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().sort(::ListingSort::Asc).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?sort=desc";
        let mut projects_lister = gl.projects();
        let query = projects_lister.sort(::ListingSort::Desc).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().sort(::ListingSort::Desc).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_search() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?search=SearchPattern";
        let mut projects_lister = gl.projects();
        let query = projects_lister.search_pattern(String::from("SearchPattern")).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().search_pattern(String::from("SearchPattern")).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_simple() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?simple=true";
        let mut projects_lister = gl.projects();
        let query = projects_lister.simple(true).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().simple(true).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?simple=false";
        let mut projects_lister = gl.projects();
        let query = projects_lister.simple(false).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().simple(false).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn groups_build_query_multiple() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?archived=true&simple=true";
        let mut projects_lister = gl.projects();
        let query = projects_lister.archived(true).simple(true).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().archived(true).simple(true).build_query();
        assert_eq!(query, expected_string);
    }
}
<|endoftext|>


<commit_before>//! A definition of the game Tic-Tac-Toe using the library, for use in tests.
//!
//! For example, playing a correctly-implemented strategy against itself should
//! always result in a draw; and playing such a strategy against one that picks
//! moves randomly should always result in a win or draw.

use interface;
use std::default::Default;
use std::fmt::{Display, Formatter, Result};
use std::convert::From;

#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
pub enum Square {
    Empty,
    X,
    O,
}

impl Default for Square {
  fn default() -> Square { Square::Empty }
}

impl Display for Square {
  fn fmt(&self, f: &mut Formatter) -> Result {
    write!(f, "{}", match *self {
        Square::Empty => ' ',
        Square::X => 'X',
        Square::O => 'O',
    })
  }
}

impl From<interface::Player> for Square {
    fn from(p: interface::Player) -> Square {
        match p {
            interface::Player::Computer => Square::X,
            interface::Player::Opponent => Square::O,
        }
    }
}

impl From<Square> for interface::Player {
    fn from(s: Square) -> interface::Player {
        match s {
            Square::X => interface::Player::Computer,
            Square::O => interface::Player::Opponent,
            _ => panic!("From::from(Square::Empty))"),
        }
    }
}

#[derive(Clone, Default, PartialEq, Eq)]
pub struct Board {
    squares: [Square; 9]
}

impl Display for Board {
  fn fmt(&self, f: &mut Formatter) -> Result {
    try!(writeln!(f, "{} | {} | {}", self.squares[0], self.squares[1], self.squares[2]));
    try!(writeln!(f, "{} | {} | {}", self.squares[3], self.squares[4], self.squares[5]));
    try!(writeln!(f, "{} | {} | {}", self.squares[6], self.squares[7], self.squares[8]));
    Ok(())
  }
}

pub struct Game;

impl interface::Game for Game {
    type S = Board;
    type M = Place;

    fn generate_moves(b: &Board, p: interface::Player, ms: &mut [Option<Place>])
        -> usize {
        let mut j = 0;
        for i in 0..b.squares.len() {
            if b.squares[i] == Square::Empty {
                ms[j] = Some(Place { i: i as u8, s: From::from(p) });
                j += 1;
            }
        }
        ms[j] = None;
        j
    }

    fn get_winner(b: &Board) -> Option<interface::Winner> {
        // horizontal wins
        if b.squares[0] != Square::Empty && b.squares[0] == b.squares[1] && b.squares[1] == b.squares[2] {
            return Some(interface::Winner::Competitor(From::from(b.squares[0])));
        }
        if b.squares[3] != Square::Empty && b.squares[3] == b.squares[4] && b.squares[4] == b.squares[5] {
            return Some(interface::Winner::Competitor(From::from(b.squares[3])));
        }
        if b.squares[6] != Square::Empty && b.squares[6] == b.squares[7] && b.squares[7] == b.squares[8] {
            return Some(interface::Winner::Competitor(From::from(b.squares[6])));
        }
        // vertical wins
        if b.squares[0] != Square::Empty && b.squares[0] == b.squares[3] && b.squares[3] == b.squares[6] {
            return Some(interface::Winner::Competitor(From::from(b.squares[0])));
        }
        if b.squares[1] != Square::Empty && b.squares[1] == b.squares[4] && b.squares[4] == b.squares[7] {
            return Some(interface::Winner::Competitor(From::from(b.squares[1])));
        }
        if b.squares[2] != Square::Empty && b.squares[2] == b.squares[5] && b.squares[5] == b.squares[8] {
            return Some(interface::Winner::Competitor(From::from(b.squares[2])));
        }
        // diagonal wins
        if b.squares[0] != Square::Empty && b.squares[0] == b.squares[4] && b.squares[4] == b.squares[8] {
            return Some(interface::Winner::Competitor(From::from(b.squares[0])));
        }
        if b.squares[2] != Square::Empty && b.squares[2] == b.squares[4] && b.squares[4] == b.squares[6] {
            return Some(interface::Winner::Competitor(From::from(b.squares[2])));
        }
        // draws
        if b.squares.iter().all(|s| *s != Square::Empty) {
            Some(interface::Winner::Draw)
        } else {
            // non-terminal state
            None
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Place { i: u8, s: Square }

impl Display for Place {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}@{}", self.s, self.i)
    }
}

impl interface::Move for Place {
    type G = Game;
    fn apply(&self, b: &mut Board) {
        b.squares[self.i as usize] = self.s;
    }
    fn undo(&self, b: &mut Board) {
        b.squares[self.i as usize] = Square::Empty;
    }
}

pub struct Evaluator;

impl interface::Evaluator for Evaluator {
    type G = Game;
    // adapted from http://www.cs.olemiss.edu/~dwilkins/CSCI531/tic.c
    fn evaluate(b: &Board, mw: Option<interface::Winner>) -> interface::Evaluation {
        match mw {
            Some(interface::Winner::Competitor(wp)) => match wp {
                interface::Player::Computer => return interface::Evaluation::Best,
                interface::Player::Opponent => return interface::Evaluation::Worst,
            },
            _ => {},
        }
        let mut score = 0;

        // 3rd: check for doubles
        for i in 0..3 {
            let line = i * 3;
            if b.squares[line + 0] == b.squares[line + 1] {
                if b.squares[line + 0] == Square::X {
                    score += 5;
                } else if b.squares[line + 0] == Square::O {
                    score -= 5;
                }
            }
            if b.squares[line + 1] == b.squares[line + 2] {
                if b.squares[line + 1] == Square::X {
                    score += 5;
                } else if b.squares[line + 1] == Square::O {
                    score += 5;
                }
            }
            if b.squares[i] == b.squares[3 + i] {
                if b.squares[i] == Square::X {
                    score += 5;
                } else if b.squares[i] == Square::O {
                    score -= 5;
                }
            }
            if b.squares[3 + i] == b.squares[6 + i] {
                if b.squares[3 + i] == Square::X {
                    score += 5;
                } else if b.squares[3 + i] == Square::O {
                    score -= 5;
                }
            }
        }
        // 2nd: check for the middle square
        if b.squares[4] == Square::X {
            score += 5;
        }
        if b.squares[4] == Square::O {
            score -= 5;
        }
        interface::Evaluation::Score(score)
    }
}
<commit_msg>Implement `Default` for `ttt::Board` manually so that the library builds with the stable Rust compiler.<commit_after>//! A definition of the game Tic-Tac-Toe using the library, for use in tests.
//!
//! For example, playing a correctly-implemented strategy against itself should
//! always result in a draw; and playing such a strategy against one that picks
//! moves randomly should always result in a win or draw.

use interface;
use std::default::Default;
use std::fmt::{Display, Formatter, Result};
use std::convert::From;

#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
pub enum Square {
    Empty,
    X,
    O,
}

impl Default for Square {
  fn default() -> Square { Square::Empty }
}

impl Display for Square {
  fn fmt(&self, f: &mut Formatter) -> Result {
    write!(f, "{}", match *self {
        Square::Empty => ' ',
        Square::X => 'X',
        Square::O => 'O',
    })
  }
}

impl From<interface::Player> for Square {
    fn from(p: interface::Player) -> Square {
        match p {
            interface::Player::Computer => Square::X,
            interface::Player::Opponent => Square::O,
        }
    }
}

impl From<Square> for interface::Player {
    fn from(s: Square) -> interface::Player {
        match s {
            Square::X => interface::Player::Computer,
            Square::O => interface::Player::Opponent,
            _ => panic!("From::from(Square::Empty))"),
        }
    }
}

#[derive(Clone, PartialEq, Eq)]
pub struct Board {
    squares: [Square; 9]
}

impl Default for Board {
    fn default() -> Board {
        Board {
            squares: [Square::default(); 9]
        }
    }
}

impl Display for Board {
  fn fmt(&self, f: &mut Formatter) -> Result {
    try!(writeln!(f, "{} | {} | {}", self.squares[0], self.squares[1], self.squares[2]));
    try!(writeln!(f, "{} | {} | {}", self.squares[3], self.squares[4], self.squares[5]));
    try!(writeln!(f, "{} | {} | {}", self.squares[6], self.squares[7], self.squares[8]));
    Ok(())
  }
}

pub struct Game;

impl interface::Game for Game {
    type S = Board;
    type M = Place;

    fn generate_moves(b: &Board, p: interface::Player, ms: &mut [Option<Place>])
        -> usize {
        let mut j = 0;
        for i in 0..b.squares.len() {
            if b.squares[i] == Square::Empty {
                ms[j] = Some(Place { i: i as u8, s: From::from(p) });
                j += 1;
            }
        }
        ms[j] = None;
        j
    }

    fn get_winner(b: &Board) -> Option<interface::Winner> {
        // horizontal wins
        if b.squares[0] != Square::Empty && b.squares[0] == b.squares[1] && b.squares[1] == b.squares[2] {
            return Some(interface::Winner::Competitor(From::from(b.squares[0])));
        }
        if b.squares[3] != Square::Empty && b.squares[3] == b.squares[4] && b.squares[4] == b.squares[5] {
            return Some(interface::Winner::Competitor(From::from(b.squares[3])));
        }
        if b.squares[6] != Square::Empty && b.squares[6] == b.squares[7] && b.squares[7] == b.squares[8] {
            return Some(interface::Winner::Competitor(From::from(b.squares[6])));
        }
        // vertical wins
        if b.squares[0] != Square::Empty && b.squares[0] == b.squares[3] && b.squares[3] == b.squares[6] {
            return Some(interface::Winner::Competitor(From::from(b.squares[0])));
        }
        if b.squares[1] != Square::Empty && b.squares[1] == b.squares[4] && b.squares[4] == b.squares[7] {
            return Some(interface::Winner::Competitor(From::from(b.squares[1])));
        }
        if b.squares[2] != Square::Empty && b.squares[2] == b.squares[5] && b.squares[5] == b.squares[8] {
            return Some(interface::Winner::Competitor(From::from(b.squares[2])));
        }
        // diagonal wins
        if b.squares[0] != Square::Empty && b.squares[0] == b.squares[4] && b.squares[4] == b.squares[8] {
            return Some(interface::Winner::Competitor(From::from(b.squares[0])));
        }
        if b.squares[2] != Square::Empty && b.squares[2] == b.squares[4] && b.squares[4] == b.squares[6] {
            return Some(interface::Winner::Competitor(From::from(b.squares[2])));
        }
        // draws
        if b.squares.iter().all(|s| *s != Square::Empty) {
            Some(interface::Winner::Draw)
        } else {
            // non-terminal state
            None
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Place { i: u8, s: Square }

impl Display for Place {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}@{}", self.s, self.i)
    }
}

impl interface::Move for Place {
    type G = Game;
    fn apply(&self, b: &mut Board) {
        b.squares[self.i as usize] = self.s;
    }
    fn undo(&self, b: &mut Board) {
        b.squares[self.i as usize] = Square::Empty;
    }
}

pub struct Evaluator;

impl interface::Evaluator for Evaluator {
    type G = Game;
    // adapted from http://www.cs.olemiss.edu/~dwilkins/CSCI531/tic.c
    fn evaluate(b: &Board, mw: Option<interface::Winner>) -> interface::Evaluation {
        match mw {
            Some(interface::Winner::Competitor(wp)) => match wp {
                interface::Player::Computer => return interface::Evaluation::Best,
                interface::Player::Opponent => return interface::Evaluation::Worst,
            },
            _ => {},
        }
        let mut score = 0;

        // 3rd: check for doubles
        for i in 0..3 {
            let line = i * 3;
            if b.squares[line + 0] == b.squares[line + 1] {
                if b.squares[line + 0] == Square::X {
                    score += 5;
                } else if b.squares[line + 0] == Square::O {
                    score -= 5;
                }
            }
            if b.squares[line + 1] == b.squares[line + 2] {
                if b.squares[line + 1] == Square::X {
                    score += 5;
                } else if b.squares[line + 1] == Square::O {
                    score += 5;
                }
            }
            if b.squares[i] == b.squares[3 + i] {
                if b.squares[i] == Square::X {
                    score += 5;
                } else if b.squares[i] == Square::O {
                    score -= 5;
                }
            }
            if b.squares[3 + i] == b.squares[6 + i] {
                if b.squares[3 + i] == Square::X {
                    score += 5;
                } else if b.squares[3 + i] == Square::O {
                    score -= 5;
                }
            }
        }
        // 2nd: check for the middle square
        if b.squares[4] == Square::X {
            score += 5;
        }
        if b.squares[4] == Square::O {
            score -= 5;
        }
        interface::Evaluation::Score(score)
    }
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::fs::{File, OpenOptions};
use std::process::{Command, Stdio};
use std::os::unix::AsRawFd;
use libc::{c_ushort, c_int, c_ulong};
use std::str;
use std::path::Path;

pub struct TTY {
    file: File,
    dimensions: (usize, usize),
    original_state: String
}

pub trait IO {
    fn write(&mut self, line: &str);
    fn read(&mut self) -> Option<String>;
    fn last(&self) -> &str;
    fn lines(&self) -> Vec<String>;
    fn dimensions(&self) -> (usize, usize);
    fn reset(&self);
}

impl IO for TTY {
    fn write(&mut self, line: &str) {
        let it = format!("{}", line);
        self.file.write(it.as_bytes()).unwrap();
    }

    fn read(&mut self) -> Option<String> {
        let mut buffer = [0] ;
        let res = match self.file.read(&mut buffer) {
            Ok(c) if  c > 0 => {
                str::from_utf8(&buffer).ok().map(|x| x.to_string())
            },
            _ => None,
        };
        res
    }

    fn last(&self) -> &str {
        "fail"
    }

    fn lines(&self) -> Vec<String> {
        let mut lines: Vec<String> = Vec::new();
        lines.push("fail".to_string());
        lines
    }

    fn dimensions(&self) -> (usize, usize) {
        self.dimensions
    }

    fn reset(&self) {
        TTY::stty(&[self.original_state.as_slice()]);
    }
}

impl TTY {
    pub fn new() -> TTY {
        let path = Path::new("/dev/tty");
        let file = OpenOptions::new().read(true).write(true).open(&path).unwrap();
        let dimension = TTY::get_window_size(&file);
        let orig_state = TTY::previous_state();

        TTY::no_echo_no_escaping();

        TTY {
            original_state: orig_state,
            dimensions: dimension,
            file: file,
        }
    }

    fn get_window_size(path: &File) -> (usize, usize) {
        extern {
            fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int;
        }
        #[cfg(any(target_os = "macos", target_os = "freebsd"))]
        const TIOCGWINSZ: c_ulong = 0x40087468;

        #[cfg(any(target_os = "linux", target_os = "android"))]
        const TIOCGWINSZ: c_ulong = 0x00005413;

        #[repr(C)]
        struct TermSize {
            rows: c_ushort,
            cols: c_ushort,
            x: c_ushort,
            y: c_ushort,
        }

        let size = TermSize { rows: 0, cols: 0, x: 0, y: 0 };
        if unsafe { ioctl(path.as_raw_fd(), TIOCGWINSZ, &size) } == 0 {
            (size.cols as usize, size.rows as usize)
        } else {
            panic!("Could not read winsize from /dev/tty")
        }
    }

    fn stty(args: &[&str]) -> Option<String> {
        let output = Command::new("stty").args(args).stdin(Stdio::capture()).output().unwrap();
        String::from_utf8(output.stdout).ok()
    }

    fn no_echo_no_escaping() {
        TTY::stty(&["-echo", "-icanon"]);
    }

    fn previous_state() -> String {
        TTY::stty(&["-g"]).unwrap_or("".to_string())
    }
}
<commit_msg>Revert "Use new path and remove no longer needed file param"<commit_after>use std::io::prelude::*;
use std::fs::{File, OpenOptions};
use std::process::{Command, Stdio};
use std::os::unix::AsRawFd;
use libc::{c_ushort, c_int, c_ulong};
use std::str;

pub struct TTY {
    file: File,
    dimensions: (usize, usize),
    original_state: String
}

pub trait IO {
    fn write(&mut self, line: &str);
    fn read(&mut self) -> Option<String>;
    fn last(&self) -> &str;
    fn lines(&self) -> Vec<String>;
    fn dimensions(&self) -> (usize, usize);
    fn reset(&self);
}

impl IO for TTY {
    fn write(&mut self, line: &str) {
        let it = format!("{}", line);
        self.file.write(it.as_bytes()).unwrap();
    }

    fn read(&mut self) -> Option<String> {
        let mut buffer = [0] ;
        let res = match self.file.read(&mut buffer) {
            Ok(c) if  c > 0 => {
                str::from_utf8(&buffer).ok().map(|x| x.to_string())
            },
            _ => None,
        };
        res
    }

    fn last(&self) -> &str {
        "fail"
    }

    fn lines(&self) -> Vec<String> {
        let mut lines: Vec<String> = Vec::new();
        lines.push("fail".to_string());
        lines
    }

    fn dimensions(&self) -> (usize, usize) {
        self.dimensions
    }

    fn reset(&self) {
        TTY::stty(&self.file, &[self.original_state.as_slice()]);
    }
}

impl TTY {
    pub fn new() -> TTY {
        let path = Path::new("/dev/tty");
        let file = OpenOptions::new().read(true).write(true).open(&path).unwrap();
        let dimension = TTY::get_window_size(&file);
        let orig_state = TTY::previous_state(&file);

        TTY::no_echo_no_escaping(&file);

        TTY {
            original_state: orig_state,
            dimensions: dimension,
            file: file,
        }
    }

    fn get_window_size(path: &File) -> (usize, usize) {
        extern {
            fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int;
        }
        #[cfg(any(target_os = "macos", target_os = "freebsd"))]
        const TIOCGWINSZ: c_ulong = 0x40087468;

        #[cfg(any(target_os = "linux", target_os = "android"))]
        const TIOCGWINSZ: c_ulong = 0x00005413;

        #[repr(C)]
        struct TermSize {
            rows: c_ushort,
            cols: c_ushort,
            x: c_ushort,
            y: c_ushort,
        }

        let size = TermSize { rows: 0, cols: 0, x: 0, y: 0 };
        if unsafe { ioctl(path.as_raw_fd(), TIOCGWINSZ, &size) } == 0 {
            (size.cols as usize, size.rows as usize)
        } else {
            panic!("Could not read winsize from /dev/tty")
        }
    }

    fn stty(file: &File, args: &[&str]) -> Option<String> {
        let output = Command::new("stty").args(args).stdin(Stdio::capture()).output().unwrap();
        String::from_utf8(output.stdout).ok()
    }

    fn no_echo_no_escaping(file: &File) {
        TTY::stty(file, &["-echo", "-icanon"]);
    }

    fn previous_state(file: &File) -> String {
        TTY::stty(file, &["-g"]).unwrap_or("".to_string())
    }
}
<|endoftext|>


<commit_before>use nalgebra::Point2;
use num::Zero;
use std::collections::HashSet;
use std::ops::Deref;

use BoolExt;
use event::{ElementState, Event, MouseButton, React};
use super::state::{CompositeState, Element, Input, InputState, InputDifference, InputTransition,
                   Snapshot, State};

impl Element for MouseButton {
    type State = ElementState;
}

#[derive(Clone, Copy)]
pub struct MousePosition;

impl Element for MousePosition {
    type State = Point2<i32>;
}

#[derive(Clone, Copy)]
pub struct MouseProximity;

impl Element for MouseProximity {
    type State = bool;
}

pub struct Mouse {
    live: MouseState,
    snapshot: MouseState,
}

impl Mouse {
    pub fn new() -> Self {
        Mouse::default()
    }
}

impl Default for Mouse {
    fn default() -> Self {
        Mouse {
            live: MouseState::new(),
            snapshot: MouseState::new(),
        }
    }
}

impl Deref for Mouse {
    type Target = MouseState;

    fn deref(&self) -> &Self::Target {
        &self.live
    }
}

impl Input for Mouse {
    type State = MouseState;

    fn live(&self) -> &Self::State {
        &self.live
    }

    fn snapshot(&self) -> &Self::State {
        &self.snapshot
    }
}

impl InputDifference<MousePosition> for Mouse {
    type Difference = Option<
        (
            MousePosition,
            <<MousePosition as Element>::State as State>::Difference,
        ),
    >;

    // This is distinct from `InputTransition::transition`. That function
    // indicates whether or not a change has occurred and yields the current
    // state. This function instead yields a *difference*, for which the type
    // representing the change in state can be entirely different than the type
    // of the state itself. For mouse position, `transition` yields a point and
    // `difference` yields a vector.
    fn difference(&self) -> Self::Difference {
        let difference = self.live.state(MousePosition) - self.snapshot.state(MousePosition);
        (!difference.is_zero()).into_some((MousePosition, difference))
    }
}

impl InputDifference<MouseProximity> for Mouse {
    type Difference = Option<
        (
            MouseProximity,
            <<MouseProximity as Element>::State as State>::Difference,
        ),
    >;

    fn difference(&self) -> Self::Difference {
        self.transition(MouseProximity)
            .map(|state| (MouseProximity, state))
    }
}

impl React for Mouse {
    fn react(&mut self, event: &Event) {
        match *event {
            Event::MouseEntered => {
                self.live.proximity = true;
            }
            Event::MouseInput(ElementState::Pressed, button) => {
                self.live.buttons.insert(button);
            }
            Event::MouseInput(ElementState::Released, button) => {
                self.live.buttons.remove(&button);
            }
            Event::MouseLeft => {
                self.live.proximity = false;
            }
            Event::MouseMoved(x, y) => {
                self.live.position = Point2::new(x, y);
            }
            _ => {}
        }
    }
}

impl Snapshot for Mouse {
    fn snapshot(&mut self) {
        self.snapshot = self.live.clone();
    }
}

#[derive(Clone)]
pub struct MouseState {
    buttons: HashSet<MouseButton>,
    position: Point2<i32>,
    proximity: bool,
}

impl MouseState {
    fn new() -> Self {
        MouseState {
            buttons: HashSet::new(),
            position: Point2::origin(),
            proximity: false,
        }
    }
}

impl CompositeState<MouseButton> for MouseState {
    type Composite = HashSet<MouseButton>;

    fn composite(&self) -> &Self::Composite {
        &self.buttons
    }
}

impl InputState<MousePosition> for MouseState {
    fn state(&self, _: MousePosition) -> <MousePosition as Element>::State {
        self.position
    }
}

impl InputState<MouseProximity> for MouseState {
    fn state(&self, _: MouseProximity) -> <MouseProximity as Element>::State {
        self.proximity
    }
}
<commit_msg>Add sanity tests to `input::mouse` module.<commit_after>use nalgebra::Point2;
use num::Zero;
use std::collections::HashSet;
use std::ops::Deref;

use BoolExt;
use event::{ElementState, Event, MouseButton, React};
use super::state::{CompositeState, Element, Input, InputState, InputDifference, InputTransition,
                   Snapshot, State};

impl Element for MouseButton {
    type State = ElementState;
}

#[derive(Clone, Copy, Debug)]
pub struct MousePosition;

impl Element for MousePosition {
    type State = Point2<i32>;
}

#[derive(Clone, Copy, Debug)]
pub struct MouseProximity;

impl Element for MouseProximity {
    type State = bool;
}

pub struct Mouse {
    live: MouseState,
    snapshot: MouseState,
}

impl Mouse {
    pub fn new() -> Self {
        Mouse::default()
    }
}

impl Default for Mouse {
    fn default() -> Self {
        Mouse {
            live: MouseState::new(),
            snapshot: MouseState::new(),
        }
    }
}

impl Deref for Mouse {
    type Target = MouseState;

    fn deref(&self) -> &Self::Target {
        &self.live
    }
}

impl Input for Mouse {
    type State = MouseState;

    fn live(&self) -> &Self::State {
        &self.live
    }

    fn snapshot(&self) -> &Self::State {
        &self.snapshot
    }
}

impl InputDifference<MousePosition> for Mouse {
    type Difference = Option<
        (
            MousePosition,
            <<MousePosition as Element>::State as State>::Difference,
        ),
    >;

    // This is distinct from `InputTransition::transition`. That function
    // indicates whether or not a change has occurred and yields the current
    // state. This function instead yields a *difference*, for which the type
    // representing the change in state can be entirely different than the type
    // of the state itself. For mouse position, `transition` yields a point and
    // `difference` yields a vector.
    fn difference(&self) -> Self::Difference {
        let difference = self.live.state(MousePosition) - self.snapshot.state(MousePosition);
        (!difference.is_zero()).into_some((MousePosition, difference))
    }
}

impl InputDifference<MouseProximity> for Mouse {
    type Difference = Option<
        (
            MouseProximity,
            <<MouseProximity as Element>::State as State>::Difference,
        ),
    >;

    fn difference(&self) -> Self::Difference {
        self.transition(MouseProximity)
            .map(|state| (MouseProximity, state))
    }
}

impl React for Mouse {
    fn react(&mut self, event: &Event) {
        match *event {
            Event::MouseEntered => {
                self.live.proximity = true;
            }
            Event::MouseInput(ElementState::Pressed, button) => {
                self.live.buttons.insert(button);
            }
            Event::MouseInput(ElementState::Released, button) => {
                self.live.buttons.remove(&button);
            }
            Event::MouseLeft => {
                self.live.proximity = false;
            }
            Event::MouseMoved(x, y) => {
                self.live.position = Point2::new(x, y);
            }
            _ => {}
        }
    }
}

impl Snapshot for Mouse {
    fn snapshot(&mut self) {
        self.snapshot = self.live.clone();
    }
}

#[derive(Clone)]
pub struct MouseState {
    buttons: HashSet<MouseButton>,
    position: Point2<i32>,
    proximity: bool,
}

impl MouseState {
    fn new() -> Self {
        MouseState {
            buttons: HashSet::new(),
            position: Point2::origin(),
            proximity: false,
        }
    }
}

impl CompositeState<MouseButton> for MouseState {
    type Composite = HashSet<MouseButton>;

    fn composite(&self) -> &Self::Composite {
        &self.buttons
    }
}

impl InputState<MousePosition> for MouseState {
    fn state(&self, _: MousePosition) -> <MousePosition as Element>::State {
        self.position
    }
}

impl InputState<MouseProximity> for MouseState {
    fn state(&self, _: MouseProximity) -> <MouseProximity as Element>::State {
        self.proximity
    }
}

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

    use event::{Event, React};
    use super::super::*;

    #[test]
    fn position_difference_some() {
        let mut mouse = Mouse::new();
        mouse.react(&Event::MouseMoved(1, 0));
        mouse.snapshot();
        mouse.react(&Event::MouseMoved(1, 1)); // Move 1 LU along the Y axis.

        assert_eq!(
            Vector2::<i32>::new(0, 1),
            <Mouse as InputDifference<MousePosition>>::difference(&mouse)
                .unwrap()
                .1
        );
    }

    #[test]
    fn position_difference_none() {
        let mut mouse = Mouse::new();
        mouse.react(&Event::MouseMoved(1, 0));
        mouse.snapshot();

        assert!(<Mouse as InputDifference<MousePosition>>::difference(&mouse).is_none());
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate assert_cli;

#[test]
fn invalid_manifest() {
    assert_cli!("target/debug/cargo-list",
                &["list", "--manifest-path=tests/fixtures/manifest-invalid/Cargo.toml.sample"] =>
                Error 1, r#"failed to parse datetime for key `invalid-section.key`"#)
        .unwrap();
}
<commit_msg>Fix invalid manifest test<commit_after>#[macro_use]
extern crate assert_cli;

#[test]
fn invalid_manifest() {
    assert_cli!("target/debug/cargo-add",
                &["add", "foo", "--manifest-path=tests/fixtures/manifest-invalid/Cargo.toml.sample"] =>
                Error 1, "Command failed due to unhandled error: failed to parse datetime for key `invalid-section.key`")
        .unwrap();
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::hash_set::HashSet;
use std::mem;
use std::rc::Rc;

use alloc::AllocBox;
use gc_error::{GcError, Result};
use js_types::js_var::{JsPtrEnum, JsType, JsVar};
use js_types::binding::Binding;
use js_types::allocator::Allocator;

// Tunable GC parameter. Probably should not be a constant, but good enough for now.
const GC_THRESHOLD: usize = 64;

/// A logical scope in the AST. Represents any scoped block of Javascript code.
/// roots: A set of all root references into the heap
/// parent: An optional parent scope, e.g. the caller of this function scope,
///         or the function that owns an `if` statement
/// heap: A shared reference to the heap allocator.
/// stack: The stack of the current scope, containing all variables allocated
///        by this scope.
pub struct Scope {
    roots: HashSet<Binding>,
    pub parent: Option<Box<Scope>>,
    heap: Rc<RefCell<AllocBox>>,
    stack: HashMap<Binding, JsVar>,
}

impl Scope {
    /// Create a new, parentless scope node.
    pub fn new(heap: &Rc<RefCell<AllocBox>>) -> Scope {
        Scope {
            roots: HashSet::new(),
            parent: None,
            heap: heap.clone(),
            stack: HashMap::new(),
        }
    }

    /// Create a scope as a child of another scope. Clones all of bindings of
    /// root references from the parent.
    pub fn as_child(parent: Scope, heap: &Rc<RefCell<AllocBox>>) -> Scope {
        Scope {
            roots: parent.roots.clone(),
            parent: Some(Box::new(parent)),
            heap: heap.clone(),
            stack: HashMap::new(),
        }
    }

    /// Sets the parent of a scope, and clones and unions its root bindings.
    pub fn set_parent(&mut self, parent: Scope) {
        self.roots = self.roots.union(&parent.roots).cloned().collect();
        self.parent = Some(Box::new(parent));
    }

    /// Push a new JsVar onto the stack, and maybe allocate a pointer in the heap.
    pub fn push(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<()> {
        let res = match &var.t {
            &JsType::JsPtr =>
                if let Some(ptr) = ptr {
                    // Creating a new pointer creates a new root
                    self.roots.insert(var.binding.clone());
                    self.heap.borrow_mut().alloc(var.binding.clone(), ptr)
                } else {
                    return Err(GcError::PtrError);
                },
            _ => Ok(()),
        };
        self.stack.insert(var.binding.clone(), var);
        res
    }

    /// Take ownership of a variable (usually from another scope).
    pub fn own(&mut self, var: JsVar) {
        self.stack.insert(var.binding.clone(), var);
    }

    /// Return an optional copy of a variable and an optional pointer into the heap.
    pub fn get_var_copy(&self, bnd: &Binding) -> (Option<JsVar>, Option<JsPtrEnum>) {
        if let Some(var) = self.stack.get(bnd) {
            match var.t {
                JsType::JsPtr => {
                    if let Some(alloc) = self.heap.borrow().find_id(bnd) {
                        (Some(var.clone()), Some(alloc.borrow().clone()))
                    } else {
                        // This case should be impossible unless you have an
                        // invalid ptr, which should also be impossible.
                        (None, None)
                    }
                },
                _ => (Some(var.clone()), None),
            }
        } else if let Some(ref parent) = self.parent {
            // FIXME? This is slow.
            parent.get_var_copy(bnd)
        } else { (None, None) }
    }

    /// Try to update a variable that's been allocated.
    pub fn update_var(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<()> {
        match var.t {
            JsType::JsPtr =>
                if let Some(ptr) = ptr {
                    // A new root was potentially created
                    self.roots.insert(var.binding.clone());
                    self.heap.borrow_mut().update_ptr(&var.binding, ptr)
                } else {
                    Err(GcError::PtrError)
                },
            _ => {
                if let Entry::Occupied(mut view) = self.stack.entry(var.binding.clone()) {
                    // A root was potentially removed
                    self.roots.remove(&var.binding);
                    *view.get_mut() = var;
                    return Ok(());
                }
                // Hack to skirt mutable borrow of self lasting longer than it should
                if let Entry::Vacant(_) = self.stack.entry(var.binding.clone()) {
                    // TODO Need to call `push` on the root scope?
                    // Push into this scope and just give to parent when done?
                    return self.push(var, ptr);
                }
                unreachable!();
            },
        }
    }

    /// Called when a scope exits. Transfers the stack of this scope to its parent,
    /// and returns the parent scope, which may be `None`.
    pub fn transfer_stack(&mut self, gc_yield: bool) -> Option<Box<Scope>> {
        if gc_yield {
            // The interpreter says we can GC now
            self.heap.borrow_mut().mark_roots(&self.roots);
            self.heap.borrow_mut().mark_ptrs();
            self.heap.borrow_mut().sweep_ptrs();
            // Pop all of the roots we just deleted
            for bnd in self.roots.iter() {
                if let None = self.heap.borrow().find_id(bnd) {
                    self.stack.remove(bnd);
                }
            }
        }
        if let Some(ref mut parent) = self.parent {
            for (_, var) in self.stack.drain() {
                match var.t {
                    JsType::JsPtr => {
                        // Mangle each binding before giving it to the parent
                        // scope. This avoids binding collisions, and helps
                        // identify to a human observer which bindings are
                        // not from the current scope.
                        let mut mangled_var = var.clone();
                        mangled_var.binding = Binding::mangle(var.binding);
                        parent.own(mangled_var);
                    }
                    _ => (),
                }
            }
            parent.roots = parent.roots.union(&self.roots).cloned().collect();
        }
        mem::replace(&mut self.parent, None)
    }
}

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

    use js_types::js_var::{JsPtrEnum, JsKey, JsKeyEnum};
    use js_types::binding::Binding;
    use js_types::js_str::JsStrStruct;
    use test_utils;

    #[test]
    fn test_new_scope() {
        let heap = test_utils::make_alloc_box();
        let test_scope = Scope::new(&heap);
        assert!(test_scope.parent.is_none());
    }

    #[test]
    fn test_as_child_scope() {
        let heap = test_utils::make_alloc_box();
        let parent_scope = Scope::new(&heap);
        let test_scope = Scope::as_child(parent_scope, &heap);
        assert!(test_scope.parent.is_some());
    }

    #[test]
    fn test_set_parent() {
        let heap = test_utils::make_alloc_box();
        let parent_scope = Scope::new(&heap);
        let mut test_scope = Scope::new(&heap);
        assert!(test_scope.parent.is_none());
        test_scope.set_parent(parent_scope);
        assert!(test_scope.parent.is_some());
    }

    #[test]
    fn test_get_var_copy() {
        let heap = test_utils::make_alloc_box();
        let mut test_scope = Scope::new(&heap);
        let (x, x_ptr, x_bnd) = test_utils::make_str("x");
        test_scope.push(x, Some(x_ptr)).unwrap();
        let bad_bnd = Binding::anon();

        let (var_copy, ptr_copy) = test_scope.get_var_copy(&x_bnd);
        assert!(var_copy.is_some());
        assert!(ptr_copy.is_some());

        let (bad_copy, ptr_copy) = test_scope.get_var_copy(&bad_bnd);
        assert!(bad_copy.is_none());
        assert!(ptr_copy.is_none());
    }

    #[test]
    fn test_get_var_copy_from_parent_scope() {
        let heap = test_utils::make_alloc_box();
        let mut parent_scope = Scope::new(&heap);
        let (x, x_ptr, x_bnd) = test_utils::make_str("x");
        parent_scope.push(x, Some(x_ptr)).unwrap();

        let child_scope = Scope::as_child(parent_scope, &heap);

        let (var_copy, ptr_copy) = child_scope.get_var_copy(&x_bnd);
        assert!(var_copy.is_some());
        assert!(ptr_copy.is_some());
    }

    #[test]
    fn test_update_var() {
        let heap = test_utils::make_alloc_box();
        let mut test_scope = Scope::new(&heap);
        let (x, x_ptr, x_bnd) = test_utils::make_str("x");
        assert!(test_scope.push(x, Some(x_ptr)).is_ok());
        let (update, _) = test_scope.get_var_copy(&x_bnd);
        let update_ptr = Some(JsPtrEnum::JsStr(JsStrStruct::new("test")));
        assert!(test_scope.update_var(update.unwrap(), update_ptr).is_ok());

        let (update, update_ptr) = test_scope.get_var_copy(&x_bnd);
        match update_ptr.unwrap() {
            JsPtrEnum::JsStr(JsStrStruct{text: ref s}) => assert_eq!(s, "test"),
            _ => panic!("Updated var was not equal to expected!")
        }
        assert_eq!(update.unwrap().binding, x_bnd);
    }

    #[test]
    fn test_transfer_stack() {
        let heap = test_utils::make_alloc_box();
        let mut parent_scope = Scope::new(&heap);
        {
            let mut test_scope = Scope::as_child(parent_scope, &heap);
            test_scope.push(test_utils::make_num(0.), None).unwrap();
            test_scope.push(test_utils::make_num(1.), None).unwrap();
            test_scope.push(test_utils::make_num(2.), None).unwrap();
            let kvs = vec![(JsKey::new(JsKeyEnum::JsBool(true)),
                            test_utils::make_num(1.), None)];
            let (var, ptr, _) = test_utils::make_obj(kvs, heap.clone());
            test_scope.push(var, Some(ptr)).unwrap();
            parent_scope = *test_scope.transfer_stack(false).unwrap();
        }
        assert_eq!(parent_scope.stack.len(), 1);
    }

    #[test]
    fn test_transfer_stack_with_yield() {
        let heap = test_utils::make_alloc_box();
        // Make a scope
        let mut parent_scope = Scope::new(&heap);
        {
            // Push a child scope
            let mut test_scope = Scope::as_child(parent_scope, &heap);
            // Allocate some non-root variables (numbers)
            test_scope.push(test_utils::make_num(0.), None).unwrap();
            test_scope.push(test_utils::make_num(1.), None).unwrap();
            test_scope.push(test_utils::make_num(2.), None).unwrap();

            // Make a string to put into an object
            // (so it's heap-allocated and we can lose its ref from the object)
            let (var, ptr, _) = test_utils::make_str("test");

            // Create an obj of { true: 1.0, false: heap("test") }
            let kvs = vec![(JsKey::new(JsKeyEnum::JsBool(true)),
                            test_utils::make_num(1.), None),
                           (JsKey::new(JsKeyEnum::JsBool(false)),
                            var, Some(ptr))];
            let key_bnd = kvs[1].0.binding.clone();
            let (var, ptr, bnd) = test_utils::make_obj(kvs, heap.clone());

            // Push the obj into the current scope
            test_scope.push(var, Some(ptr)).unwrap();

            // Replace the string in the object with something else so it's no longer live
            let copy = test_scope.get_var_copy(&bnd);
            let (var_cp, mut ptr_cp) = (copy.0.unwrap(), copy.1.unwrap());
            let key = JsKey { binding: key_bnd, k: JsKeyEnum::JsBool(false) };
            match ptr_cp {
                JsPtrEnum::JsObj(ref mut obj) => { obj.dict.insert(key, test_utils::make_num(-1.)); }
                _ => unreachable!()
            }
            test_scope.update_var(var_cp, Some(ptr_cp)).unwrap();

            // Kill the current scope & give its refs to the parent,
            // allowing the GC to kick in beforehand.
            parent_scope = *test_scope.transfer_stack(true).unwrap();
        }
        // The object we created above should still exist
        assert_eq!(parent_scope.stack.len(), 1);
        assert_eq!(heap.borrow().len(), 1);
    }

}
<commit_msg>Add extra error cases to update_ptr & push for Scope<commit_after>use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::hash_set::HashSet;
use std::mem;
use std::rc::Rc;

use alloc::AllocBox;
use gc_error::{GcError, Result};
use js_types::js_var::{JsPtrEnum, JsType, JsVar};
use js_types::binding::Binding;
use js_types::allocator::Allocator;

// Tunable GC parameter. Probably should not be a constant, but good enough for now.
const GC_THRESHOLD: usize = 64;

/// A logical scope in the AST. Represents any scoped block of Javascript code.
/// roots: A set of all root references into the heap
/// parent: An optional parent scope, e.g. the caller of this function scope,
///         or the function that owns an `if` statement
/// heap: A shared reference to the heap allocator.
/// stack: The stack of the current scope, containing all variables allocated
///        by this scope.
pub struct Scope {
    roots: HashSet<Binding>,
    pub parent: Option<Box<Scope>>,
    heap: Rc<RefCell<AllocBox>>,
    stack: HashMap<Binding, JsVar>,
}

impl Scope {
    /// Create a new, parentless scope node.
    pub fn new(heap: &Rc<RefCell<AllocBox>>) -> Scope {
        Scope {
            roots: HashSet::new(),
            parent: None,
            heap: heap.clone(),
            stack: HashMap::new(),
        }
    }

    /// Create a scope as a child of another scope. Clones all of bindings of
    /// root references from the parent.
    pub fn as_child(parent: Scope, heap: &Rc<RefCell<AllocBox>>) -> Scope {
        Scope {
            roots: parent.roots.clone(),
            parent: Some(Box::new(parent)),
            heap: heap.clone(),
            stack: HashMap::new(),
        }
    }

    /// Sets the parent of a scope, and clones and unions its root bindings.
    pub fn set_parent(&mut self, parent: Scope) {
        self.roots = self.roots.union(&parent.roots).cloned().collect();
        self.parent = Some(Box::new(parent));
    }

    /// Push a new JsVar onto the stack, and maybe allocate a pointer in the heap.
    pub fn push(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<()> {
        let res = match &var.t {
            &JsType::JsPtr =>
                if let Some(ptr) = ptr {
                    // Creating a new pointer creates a new root
                    self.roots.insert(var.binding.clone());
                    self.heap.borrow_mut().alloc(var.binding.clone(), ptr)
                } else {
                    return Err(GcError::PtrError);
                },
            _ => if let Some(_) = ptr { Err(GcError::PtrError) } else { Ok(()) },
        };
        self.stack.insert(var.binding.clone(), var);
        res
    }

    /// Take ownership of a variable (usually from another scope).
    pub fn own(&mut self, var: JsVar) {
        self.stack.insert(var.binding.clone(), var);
    }

    /// Return an optional copy of a variable and an optional pointer into the heap.
    pub fn get_var_copy(&self, bnd: &Binding) -> (Option<JsVar>, Option<JsPtrEnum>) {
        if let Some(var) = self.stack.get(bnd) {
            match var.t {
                JsType::JsPtr => {
                    if let Some(alloc) = self.heap.borrow().find_id(bnd) {
                        (Some(var.clone()), Some(alloc.borrow().clone()))
                    } else {
                        // This case should be impossible unless you have an
                        // invalid ptr, which should also be impossible.
                        (None, None)
                    }
                },
                _ => (Some(var.clone()), None),
            }
        } else if let Some(ref parent) = self.parent {
            // FIXME? This is slow.
            parent.get_var_copy(bnd)
        } else { (None, None) }
    }

    /// Try to update a variable that's been allocated.
    pub fn update_var(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<()> {
        match var.t {
            JsType::JsPtr =>
                if let Some(ptr) = ptr {
                    // A new root was potentially created
                    self.roots.insert(var.binding.clone());
                    self.heap.borrow_mut().update_ptr(&var.binding, ptr)
                } else {
                    Err(GcError::PtrError)
                },
            _ => {
                if let Some(_) = ptr { return Err(GcError::PtrError); }
                if let Entry::Occupied(mut view) = self.stack.entry(var.binding.clone()) {
                    // A root was potentially removed
                    self.roots.remove(&var.binding);
                    *view.get_mut() = var;
                    return Ok(());
                }
                // Hack to skirt mutable borrow of self lasting longer than it should
                if let Entry::Vacant(_) = self.stack.entry(var.binding.clone()) {
                    // TODO Need to call `push` on the root scope?
                    // Push into this scope and just give to parent when done?
                    return self.push(var, ptr);
                }
                unreachable!();
            },
        }
    }

    /// Called when a scope exits. Transfers the stack of this scope to its parent,
    /// and returns the parent scope, which may be `None`.
    pub fn transfer_stack(&mut self, gc_yield: bool) -> Option<Box<Scope>> {
        if gc_yield {
            // The interpreter says we can GC now
            self.heap.borrow_mut().mark_roots(&self.roots);
            self.heap.borrow_mut().mark_ptrs();
            self.heap.borrow_mut().sweep_ptrs();
            // Pop all of the roots we just deleted
            for bnd in self.roots.iter() {
                if let None = self.heap.borrow().find_id(bnd) {
                    self.stack.remove(bnd);
                }
            }
        }
        if let Some(ref mut parent) = self.parent {
            for (_, var) in self.stack.drain() {
                match var.t {
                    JsType::JsPtr => {
                        // Mangle each binding before giving it to the parent
                        // scope. This avoids binding collisions, and helps
                        // identify to a human observer which bindings are
                        // not from the current scope.
                        let mut mangled_var = var.clone();
                        mangled_var.binding = Binding::mangle(var.binding);
                        parent.own(mangled_var);
                    }
                    _ => (),
                }
            }
            parent.roots = parent.roots.union(&self.roots).cloned().collect();
        }
        mem::replace(&mut self.parent, None)
    }
}

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

    use js_types::js_var::{JsPtrEnum, JsKey, JsKeyEnum};
    use js_types::binding::Binding;
    use js_types::js_str::JsStrStruct;
    use test_utils;

    #[test]
    fn test_new_scope() {
        let heap = test_utils::make_alloc_box();
        let test_scope = Scope::new(&heap);
        assert!(test_scope.parent.is_none());
    }

    #[test]
    fn test_as_child_scope() {
        let heap = test_utils::make_alloc_box();
        let parent_scope = Scope::new(&heap);
        let test_scope = Scope::as_child(parent_scope, &heap);
        assert!(test_scope.parent.is_some());
    }

    #[test]
    fn test_set_parent() {
        let heap = test_utils::make_alloc_box();
        let parent_scope = Scope::new(&heap);
        let mut test_scope = Scope::new(&heap);
        assert!(test_scope.parent.is_none());
        test_scope.set_parent(parent_scope);
        assert!(test_scope.parent.is_some());
    }

    #[test]
    fn test_get_var_copy() {
        let heap = test_utils::make_alloc_box();
        let mut test_scope = Scope::new(&heap);
        let (x, x_ptr, x_bnd) = test_utils::make_str("x");
        test_scope.push(x, Some(x_ptr)).unwrap();
        let bad_bnd = Binding::anon();

        let (var_copy, ptr_copy) = test_scope.get_var_copy(&x_bnd);
        assert!(var_copy.is_some());
        assert!(ptr_copy.is_some());

        let (bad_copy, ptr_copy) = test_scope.get_var_copy(&bad_bnd);
        assert!(bad_copy.is_none());
        assert!(ptr_copy.is_none());
    }

    #[test]
    fn test_get_var_copy_from_parent_scope() {
        let heap = test_utils::make_alloc_box();
        let mut parent_scope = Scope::new(&heap);
        let (x, x_ptr, x_bnd) = test_utils::make_str("x");
        parent_scope.push(x, Some(x_ptr)).unwrap();

        let child_scope = Scope::as_child(parent_scope, &heap);

        let (var_copy, ptr_copy) = child_scope.get_var_copy(&x_bnd);
        assert!(var_copy.is_some());
        assert!(ptr_copy.is_some());
    }

    #[test]
    fn test_update_var() {
        let heap = test_utils::make_alloc_box();
        let mut test_scope = Scope::new(&heap);
        let (x, x_ptr, x_bnd) = test_utils::make_str("x");
        assert!(test_scope.push(x, Some(x_ptr)).is_ok());
        let (update, _) = test_scope.get_var_copy(&x_bnd);
        let update_ptr = Some(JsPtrEnum::JsStr(JsStrStruct::new("test")));
        assert!(test_scope.update_var(update.unwrap(), update_ptr).is_ok());

        let (update, update_ptr) = test_scope.get_var_copy(&x_bnd);
        match update_ptr.unwrap() {
            JsPtrEnum::JsStr(JsStrStruct{text: ref s}) => assert_eq!(s, "test"),
            _ => panic!("Updated var was not equal to expected!")
        }
        assert_eq!(update.unwrap().binding, x_bnd);
    }

    #[test]
    fn test_transfer_stack() {
        let heap = test_utils::make_alloc_box();
        let mut parent_scope = Scope::new(&heap);
        {
            let mut test_scope = Scope::as_child(parent_scope, &heap);
            test_scope.push(test_utils::make_num(0.), None).unwrap();
            test_scope.push(test_utils::make_num(1.), None).unwrap();
            test_scope.push(test_utils::make_num(2.), None).unwrap();
            let kvs = vec![(JsKey::new(JsKeyEnum::JsBool(true)),
                            test_utils::make_num(1.), None)];
            let (var, ptr, _) = test_utils::make_obj(kvs, heap.clone());
            test_scope.push(var, Some(ptr)).unwrap();
            parent_scope = *test_scope.transfer_stack(false).unwrap();
        }
        assert_eq!(parent_scope.stack.len(), 1);
    }

    #[test]
    fn test_transfer_stack_with_yield() {
        let heap = test_utils::make_alloc_box();
        // Make a scope
        let mut parent_scope = Scope::new(&heap);
        {
            // Push a child scope
            let mut test_scope = Scope::as_child(parent_scope, &heap);
            // Allocate some non-root variables (numbers)
            test_scope.push(test_utils::make_num(0.), None).unwrap();
            test_scope.push(test_utils::make_num(1.), None).unwrap();
            test_scope.push(test_utils::make_num(2.), None).unwrap();

            // Make a string to put into an object
            // (so it's heap-allocated and we can lose its ref from the object)
            let (var, ptr, _) = test_utils::make_str("test");

            // Create an obj of { true: 1.0, false: heap("test") }
            let kvs = vec![(JsKey::new(JsKeyEnum::JsBool(true)),
                            test_utils::make_num(1.), None),
                           (JsKey::new(JsKeyEnum::JsBool(false)),
                            var, Some(ptr))];
            let key_bnd = kvs[1].0.binding.clone();
            let (var, ptr, bnd) = test_utils::make_obj(kvs, heap.clone());

            // Push the obj into the current scope
            test_scope.push(var, Some(ptr)).unwrap();

            // Replace the string in the object with something else so it's no longer live
            let copy = test_scope.get_var_copy(&bnd);
            let (var_cp, mut ptr_cp) = (copy.0.unwrap(), copy.1.unwrap());
            let key = JsKey { binding: key_bnd, k: JsKeyEnum::JsBool(false) };
            match ptr_cp {
                JsPtrEnum::JsObj(ref mut obj) => { obj.dict.insert(key, test_utils::make_num(-1.)); }
                _ => unreachable!()
            }
            test_scope.update_var(var_cp, Some(ptr_cp)).unwrap();

            // Kill the current scope & give its refs to the parent,
            // allowing the GC to kick in beforehand.
            parent_scope = *test_scope.transfer_stack(true).unwrap();
        }
        // The object we created above should still exist
        assert_eq!(parent_scope.stack.len(), 1);
        assert_eq!(heap.borrow().len(), 1);
    }

}
<|endoftext|>


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

use git2;
use regex::Regex;

use prelude::*;
use api::{Repo, Ref};

#[derive(Debug)]
pub struct CommitSpec {
    pub repo: String,
    pub path: Option<PathBuf>,
    pub rev: Option<String>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct VcsUrl {
    pub provider: &'static str,
    pub id: String,
}

impl CommitSpec {
    pub fn parse(s: &str) -> Result<CommitSpec> {
        lazy_static! {
            static ref SPEC_RE: Regex = Regex::new(
                r"^([^@#]+)(?:#([^@]+))?(?:@(.+))?$").unwrap();
        }
        if let Some(caps) = SPEC_RE.captures(s) {
            Ok(CommitSpec {
                repo: caps[1].to_string(),
                path: caps.get(2).map(|x| PathBuf::from(x.as_str())),
                rev: caps.get(3).map(|x| x.as_str().to_string()),
            })
        } else {
            Err(Error::from(format!("Could not parse commit spec '{}'", s)))
        }
    }
}

fn strip_git_suffix(s: &str) -> &str {
    if s.ends_with(".git") {
        &s[0..s.len() - 4]
    } else {
        s
    }
}

impl VcsUrl {
    pub fn parse(url: &str) -> VcsUrl {
        lazy_static! {
            static ref GITHUB_URL_RE: Regex = Regex::new(
                r"^(?:ssh|https?)://(?:[^@]+@)?github.com/([^/]+)/([^/]+)").unwrap();
            static ref GITHUB_SSH_RE: Regex = Regex::new(
                r"^(?:[^@]+@)?github.com:([^/]+)/([^/]+)").unwrap();
        }
        if let Some(caps) = GITHUB_URL_RE.captures(url) {
            VcsUrl {
                provider: "github",
                id: format!("{}/{}", &caps[1], strip_git_suffix(&caps[2])),
            }
        } else if let Some(caps) = GITHUB_SSH_RE.captures(url) {
            VcsUrl {
                provider: "github",
                id: format!("{}/{}", &caps[1], strip_git_suffix(&caps[2])),
            }
        } else {
            VcsUrl {
                provider: "generic",
                id: url.into(),
            }
        }
    }
}

fn is_matching_url(a: &str, b: &str) -> bool {
    VcsUrl::parse(a) == VcsUrl::parse(b)
}

fn find_reference_url(repo: &str, repos: &[Repo]) -> Result<String> {
    for configured_repo in repos {
        if configured_repo.name != repo {
            continue;
        }
        if &configured_repo.provider.id != "github" &&
           &configured_repo.provider.id != "git" {
            return Err(Error::from("For non git repositories \
                                   explicit revisions are required"));
        }

        return Ok(configured_repo.url.clone())
    }

    Err(Error::from(format!("Could not find matching repository for {}", repo)))
}

fn find_matching_head(spec: &CommitSpec, repos: &[Repo], disable_discovery: bool)
    -> Result<Option<String>>
{
    let (repo, discovery) = if let Some(ref path) = spec.path {
        (git2::Repository::open(path)?, false)
    } else {
        (git2::Repository::open_from_env()?, !disable_discovery)
    };

    let reference_url = find_reference_url(&spec.repo, repos)?;

    // direct reference in root repository found.  If we are in discovery
    // mode we want to also check for matching URLs.
    if_chain! {
        if let Ok(remote) = repo.find_remote("origin");
        if let Some(url) = remote.url();
        if !discovery || is_matching_url(url, &reference_url);
        then {
            let head = repo.revparse_single("HEAD")?;
            return Ok(Some(head.id().to_string()));
        }
    }

    // in discovery mode we want to find that repo in associated submodules.
    for submodule in repo.submodules()? {
        if_chain! {
            if let Some(submodule_url) = submodule.url();
            if is_matching_url(submodule_url, &reference_url);
            if let Some(head_oid) = submodule.head_id();
            then {
                return Ok(Some(head_oid.to_string()));
            }
        }
    }

    Ok(None)
}

pub fn find_head() -> Result<String>
{
    let repo = git2::Repository::open_from_env()?;
    let head = repo.revparse_single("HEAD")?;
    Ok(head.id().to_string())
}

/// Given commit specs and repos this returns a list of head commits
/// from it.
pub fn find_heads(specs: Option<Vec<CommitSpec>>, repos: Vec<Repo>)
    -> Result<Vec<Ref>>
{
    let mut rv = vec![];

    // if commit specs were explicitly provided find head commits with
    // limited amounts of magic.
    if let Some(specs) = specs {
        for spec in &specs {
            let head = if let Some(ref rev) = spec.rev {
                rev.clone()
            } else if let Some(head) = find_matching_head(
                &spec, &repos[..], specs.len() == 1)? {
                head
            } else {
                return Err(Error::from(format!(
                    "Could not find HEAD commit for '{}'", &spec.repo)));
            };
            rv.push(Ref {
                repo: spec.repo.clone(),
                rev: head,
            });
        }

    // otherwise apply all the magic available
    } else {
        for repo in &repos {
            if let Some(head) = find_matching_head(
                &CommitSpec {
                    repo: repo.name.to_string(),
                    path: None,
                    rev: None,
                }, &repos[..], false)? {
                rv.push(Ref {
                    repo: repo.name.to_string(),
                    rev: head,
                });
            }
        }
    }

    Ok(rv)
}

#[test]
fn test_url_parsing() {
    assert_eq!(VcsUrl::parse("http://github.com/mitsuhiko/flask"), VcsUrl {
        provider: "github",
        id: "mitsuhiko/flask".into(),
    });
    assert_eq!(VcsUrl::parse("git@github.com:mitsuhiko/flask.git"), VcsUrl {
        provider: "github",
        id: "mitsuhiko/flask".into(),
    });
}

#[test]
fn test_url_normalization() {
    assert!(is_matching_url("http://github.com/mitsuhiko/flask",
                            "git@github.com:mitsuhiko/flask.git"));
}
<commit_msg>Added resolve support for commit setting and a better error message. Refs #63<commit_after>use std::fmt;
use std::path::PathBuf;

use git2;
use regex::Regex;

use prelude::*;
use api::{Repo, Ref};

pub enum GitReference<'a> {
    Commit(git2::Oid),
    Symbolic(&'a str),
}

impl<'a> fmt::Display for GitReference<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GitReference::Commit(ref c) => write!(f, "{}", c),
            GitReference::Symbolic(ref s) => write!(f, "{}", s),
        }
    }
}

#[derive(Debug)]
pub struct CommitSpec {
    pub repo: String,
    pub path: Option<PathBuf>,
    pub rev: Option<String>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct VcsUrl {
    pub provider: &'static str,
    pub id: String,
}

impl CommitSpec {
    pub fn parse(s: &str) -> Result<CommitSpec> {
        lazy_static! {
            static ref SPEC_RE: Regex = Regex::new(
                r"^([^@#]+)(?:#([^@]+))?(?:@(.+))?$").unwrap();
        }
        if let Some(caps) = SPEC_RE.captures(s) {
            Ok(CommitSpec {
                repo: caps[1].to_string(),
                path: caps.get(2).map(|x| PathBuf::from(x.as_str())),
                rev: caps.get(3).map(|x| x.as_str().to_string()),
            })
        } else {
            Err(Error::from(format!("Could not parse commit spec '{}'", s)))
        }
    }

    pub fn reference<'a>(&'a self) -> GitReference<'a> {
        let r = self.rev.as_ref().map(|x| x.as_str()).unwrap_or("HEAD");
        if let Ok(oid) = git2::Oid::from_str(r) {
            GitReference::Commit(oid)
        } else {
            GitReference::Symbolic(r)
        }
    }
}

fn strip_git_suffix(s: &str) -> &str {
    if s.ends_with(".git") {
        &s[0..s.len() - 4]
    } else {
        s
    }
}

impl VcsUrl {
    pub fn parse(url: &str) -> VcsUrl {
        lazy_static! {
            static ref GITHUB_URL_RE: Regex = Regex::new(
                r"^(?:ssh|https?)://(?:[^@]+@)?github.com/([^/]+)/([^/]+)").unwrap();
            static ref GITHUB_SSH_RE: Regex = Regex::new(
                r"^(?:[^@]+@)?github.com:([^/]+)/([^/]+)").unwrap();
        }
        if let Some(caps) = GITHUB_URL_RE.captures(url) {
            VcsUrl {
                provider: "github",
                id: format!("{}/{}", &caps[1], strip_git_suffix(&caps[2])),
            }
        } else if let Some(caps) = GITHUB_SSH_RE.captures(url) {
            VcsUrl {
                provider: "github",
                id: format!("{}/{}", &caps[1], strip_git_suffix(&caps[2])),
            }
        } else {
            VcsUrl {
                provider: "generic",
                id: url.into(),
            }
        }
    }
}

fn is_matching_url(a: &str, b: &str) -> bool {
    VcsUrl::parse(a) == VcsUrl::parse(b)
}

fn find_reference_url(repo: &str, repos: &[Repo]) -> Result<String> {
    for configured_repo in repos {
        if configured_repo.name != repo {
            continue;
        }
        if &configured_repo.provider.id != "github" &&
           &configured_repo.provider.id != "git" {
            return Err(Error::from("For non git repositories \
                                   explicit revisions are required"));
        }

        return Ok(configured_repo.url.clone())
    }

    Err(Error::from(format!("Could not find matching repository for {}", repo)))
}

fn find_matching_rev(spec: &CommitSpec, repos: &[Repo], disable_discovery: bool)
    -> Result<Option<String>>
{
    let r = match spec.reference() {
        GitReference::Commit(commit) => {
            return Ok(Some(commit.to_string()));
        }
        GitReference::Symbolic(r) => r,
    };

    let (repo, discovery) = if let Some(ref path) = spec.path {
        (git2::Repository::open(path)?, false)
    } else {
        (git2::Repository::open_from_env()?, !disable_discovery)
    };

    let reference_url = find_reference_url(&spec.repo, repos)?;

    // direct reference in root repository found.  If we are in discovery
    // mode we want to also check for matching URLs.
    if_chain! {
        if let Ok(remote) = repo.find_remote("origin");
        if let Some(url) = remote.url();
        if !discovery || is_matching_url(url, &reference_url);
        then {
            let head = repo.revparse_single(r)?;
            return Ok(Some(head.id().to_string()));
        }
    }

    // in discovery mode we want to find that repo in associated submodules.
    for submodule in repo.submodules()? {
        if_chain! {
            if let Some(submodule_url) = submodule.url();
            if is_matching_url(submodule_url, &reference_url);
            then {
                // heads on submodules is easier so let's start with that
                // because that does not require the submodule to be
                // checked out.
                if_chain! {
                    if r == "HEAD";
                    if let Some(head_oid) = submodule.head_id();
                    then {
                        return Ok(Some(head_oid.to_string()));
                    }
                }

                // otherwise we need to open the submodule which requires
                // it to be checked out.
                if_chain! {
                    if let Ok(subrepo) = submodule.open();
                    then {
                        let head = subrepo.revparse_single(r)?;
                        return Ok(Some(head.id().to_string()));
                    }
                }
            }
        }
    }

    Ok(None)
}

pub fn find_head() -> Result<String> {
    let repo = git2::Repository::open_from_env()?;
    let head = repo.revparse_single("HEAD")?;
    Ok(head.id().to_string())
}

/// Given commit specs and repos this returns a list of head commits
/// from it.
pub fn find_heads(specs: Option<Vec<CommitSpec>>, repos: Vec<Repo>)
    -> Result<Vec<Ref>>
{
    let mut rv = vec![];

    // if commit specs were explicitly provided find head commits with
    // limited amounts of magic.
    if let Some(specs) = specs {
        for spec in &specs {
            let rev = if let Some(rev) = find_matching_rev(
                &spec, &repos[..], specs.len() == 1)? {
                rev
            } else {
                return Err(Error::from(format!(
                    "Could not find commit '{}' for '{}'. If you do not have local \
                     checkouts of the repositories in question referencing tags or \
                     other references will not work and you need to refer to \
                     revisions explicitly.",
                    spec.reference(), &spec.repo)));
            };
            rv.push(Ref {
                repo: spec.repo.clone(),
                rev: rev,
            });
        }

    // otherwise apply all the magic available
    } else {
        for repo in &repos {
            if let Some(head) = find_matching_rev(
                &CommitSpec {
                    repo: repo.name.to_string(),
                    path: None,
                    rev: Some("HEAD".into()),
                }, &repos[..], false)? {
                rv.push(Ref {
                    repo: repo.name.to_string(),
                    rev: head,
                });
            }
        }
    }

    Ok(rv)
}

#[test]
fn test_url_parsing() {
    assert_eq!(VcsUrl::parse("http://github.com/mitsuhiko/flask"), VcsUrl {
        provider: "github",
        id: "mitsuhiko/flask".into(),
    });
    assert_eq!(VcsUrl::parse("git@github.com:mitsuhiko/flask.git"), VcsUrl {
        provider: "github",
        id: "mitsuhiko/flask".into(),
    });
}

#[test]
fn test_url_normalization() {
    assert!(is_matching_url("http://github.com/mitsuhiko/flask",
                            "git@github.com:mitsuhiko/flask.git"));
}
<|endoftext|>