<commit_before>use diesel::prelude::*;
use diesel::pg::PgConnection;
use pg::rows::Row;

use app::App;
use http;
use schema::*;
use util::{CargoResult, human};
use {Model, User, Crate};

#[derive(Insertable, Associations, Identifiable)]
#[belongs_to(Crate)]
#[belongs_to(User, foreign_key = "owner_id")]
#[belongs_to(Team, foreign_key = "owner_id")]
#[table_name = "crate_owners"]
#[primary_key(crate_id, owner_id, owner_kind)]
pub struct CrateOwner {
    pub crate_id: i32,
    pub owner_id: i32,
    pub created_by: i32,
    pub owner_kind: i32,
}

#[repr(u32)]
pub enum OwnerKind {
    User = 0,
    Team = 1,
}

/// Unifies the notion of a User or a Team.
pub enum Owner {
    User(User),
    Team(Team),
}

/// For now, just a Github Team. Can be upgraded to other teams
/// later if desirable.
#[derive(Queryable, Identifiable, RustcEncodable, RustcDecodable)]
pub struct Team {
    /// Unique table id
    pub id: i32,
    /// "github:org:team"
    /// An opaque unique ID, that was at one point parsed out to query Github.
    /// We only query membership with github using the github_id, though.
    /// This is the only name we should ever talk to Cargo about.
    pub login: String,
    /// We're assuming these are stable
    pub github_id: i32,
    /// Sugary goodness
    pub name: Option<String>,
    pub avatar: Option<String>,
}

#[derive(RustcEncodable)]
pub struct EncodableTeam {
    pub id: i32,
    pub login: String,
    pub name: Option<String>,
    pub avatar: Option<String>,
    pub url: Option<String>,
}

#[derive(RustcEncodable, RustcDecodable)]
pub struct EncodableOwner {
    pub id: i32,
    pub login: String,
    pub kind: String,
    pub email: Option<String>,
    pub url: Option<String>,
    pub name: Option<String>,
    pub avatar: Option<String>,
}

/// Access rights to the crate (publishing and ownership management)
/// NOTE: The order of these variants matters!
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub enum Rights {
    None,
    Publish,
    Full,
}

#[derive(Insertable, AsChangeset)]
#[table_name = "teams"]
pub struct NewTeam<'a> {
    pub login: &'a str,
    pub github_id: i32,
    pub name: Option<String>,
    pub avatar: Option<String>,
}

impl<'a> NewTeam<'a> {
    pub fn new(
        login: &'a str,
        github_id: i32,
        name: Option<String>,
        avatar: Option<String>,
    ) -> Self {
        NewTeam {
            login: login,
            github_id: github_id,
            name: name,
            avatar: avatar,
        }
    }

    pub fn create_or_update(&self, conn: &PgConnection) -> CargoResult<Team> {
        use diesel::insert;
        use diesel::pg::upsert::*;

        insert(&self.on_conflict(teams::github_id, do_update().set(self)))
            .into(teams::table)
            .get_result(conn)
            .map_err(Into::into)
    }
}

impl Team {
    /// Tries to create the Team in the DB (assumes a `:` has already been found).
    pub fn create(
        app: &App,
        conn: &PgConnection,
        login: &str,
        req_user: &User,
    ) -> CargoResult<Self> {
        // must look like system:xxxxxxx
        let mut chunks = login.split(':');
        match chunks.next().unwrap() {
            // github:rust-lang:owners
            "github" => {
                // Ok to unwrap since we know one ":" is contained
                let org = chunks.next().unwrap();
                let team = chunks.next().ok_or_else(|| {
                    human(
                        "missing github team argument; \
                            format is github:org:team",
                    )
                })?;
                Team::create_github_team(app, conn, login, org, team, req_user)
            }
            _ => {
                Err(human(
                    "unknown organization handler, \
                            only 'github:org:team' is supported",
                ))
            }
        }
    }

    /// Tries to create a Github Team from scratch. Assumes `org` and `team` are
    /// correctly parsed out of the full `name`. `name` is passed as a
    /// convenience to avoid rebuilding it.
    pub fn create_github_team(
        app: &App,
        conn: &PgConnection,
        login: &str,
        org_name: &str,
        team_name: &str,
        req_user: &User,
    ) -> CargoResult<Self> {
        // GET orgs/:org/teams
        // check that `team` is the `slug` in results, and grab its data

        // "sanitization"
        fn whitelist(c: &char) -> bool {
            match *c {
                'a'...'z' | 'A'...'Z' | '0'...'9' | '-' | '_' => false,
                _ => true,
            }
        }

        if let Some(c) = org_name.chars().find(whitelist) {
            return Err(human(&format_args!(
                "organization cannot contain special \
                                        characters like {}",
                c
            )));
        }

        #[derive(RustcDecodable)]
        struct GithubTeam {
            slug: String, // the name we want to find
            id: i32, // unique GH id (needed for membership queries)
            name: Option<String>, // Pretty name
        }

        // FIXME: we just set per_page=100 and don't bother chasing pagination
        // links. A hundred teams should be enough for any org, right?
        let url = format!("/orgs/{}/teams?per_page=100", org_name);
        let token = http::token(req_user.gh_access_token.clone());
        let (handle, data) = http::github(app, &url, &token)?;
        let teams: Vec<GithubTeam> = http::parse_github_response(handle, &data)?;

        let team = teams
            .into_iter()
            .find(|team| team.slug == team_name)
            .ok_or_else(|| {
                human(&format_args!(
                    "could not find the github team {}/{}",
                    org_name,
                    team_name
                ))
            })?;

        if !team_with_gh_id_contains_user(app, team.id, req_user)? {
            return Err(human("only members of a team can add it as an owner"));
        }

        #[derive(RustcDecodable)]
        struct Org {
            avatar_url: Option<String>,
        }

        let url = format!("/orgs/{}", org_name);
        let (handle, resp) = http::github(app, &url, &token)?;
        let org: Org = http::parse_github_response(handle, &resp)?;

        NewTeam::new(login, team.id, team.name, org.avatar_url).create_or_update(&conn)
    }

    /// Phones home to Github to ask if this User is a member of the given team.
    /// Note that we're assuming that the given user is the one interested in
    /// the answer. If this is not the case, then we could accidentally leak
    /// private membership information here.
    pub fn contains_user(&self, app: &App, user: &User) -> CargoResult<bool> {
        team_with_gh_id_contains_user(app, self.github_id, user)
    }

    pub fn encodable(self) -> EncodableTeam {
        let Team {
            id,
            name,
            login,
            avatar,
            ..
        } = self;
        let org_name = Team::get_org(&login);
        let team_name = Team::get_team(&login);
        let url = format!("https://github.com/orgs/{}/teams/{}", org_name, team_name);

        EncodableTeam {
            id: id,
            login: login,
            name: name,
            avatar: avatar,
            url: Some(url),
        }
    }

    fn get_org(login: &str) -> String {
        let login_string = login.to_string();
        let org: Vec<&str> = login_string.split(':').collect();
        org[1].to_string()
    }

    fn get_team(login: &str) -> String {
        let login_string = login.to_string();
        let org: Vec<&str> = login_string.split(':').collect();
        org[2].to_string()
    }
}

fn team_with_gh_id_contains_user(app: &App, github_id: i32, user: &User) -> CargoResult<bool> {
    // GET teams/:team_id/memberships/:user_name
    // check that "state": "active"

    #[derive(RustcDecodable)]
    struct Membership {
        state: String,
    }

    let url = format!("/teams/{}/memberships/{}", &github_id, &user.gh_login);
    let token = http::token(user.gh_access_token.clone());
    let (mut handle, resp) = http::github(app, &url, &token)?;

    // Officially how `false` is returned
    if handle.response_code().unwrap() == 404 {
        return Ok(false);
    }

    let membership: Membership = http::parse_github_response(handle, &resp)?;

    // There is also `state: pending` for which we could possibly give
    // some feedback, but it's not obvious how that should work.
    Ok(membership.state == "active")
}

impl Model for Team {
    fn from_row(row: &Row) -> Self {
        Team {
            id: row.get("id"),
            name: row.get("name"),
            github_id: row.get("github_id"),
            login: row.get("login"),
            avatar: row.get("avatar"),
        }
    }

    fn table_name(_: Option<Self>) -> &'static str {
        "teams"
    }
}

impl Owner {
    /// Finds the owner by name, failing out if it doesn't exist.
    /// May be a user's GH login, or a full team name. This is case
    /// sensitive.
    pub fn find_by_login(conn: &PgConnection, name: &str) -> CargoResult<Owner> {
        if name.contains(':') {
            teams::table
                .filter(teams::login.eq(name))
                .first(conn)
                .map(Owner::Team)
                .map_err(|_| {
                    human(&format_args!("could not find team with name {}", name))
                })
        } else {
            users::table
                .filter(users::gh_login.eq(name))
                .first(conn)
                .map(Owner::User)
                .map_err(|_| {
                    human(&format_args!("could not find user with login `{}`", name))
                })
        }
    }

    pub fn kind(&self) -> i32 {
        match *self {
            Owner::User(_) => OwnerKind::User as i32,
            Owner::Team(_) => OwnerKind::Team as i32,
        }
    }

    pub fn login(&self) -> &str {
        match *self {
            Owner::User(ref user) => &user.gh_login,
            Owner::Team(ref team) => &team.login,
        }
    }

    pub fn id(&self) -> i32 {
        match *self {
            Owner::User(ref user) => user.id,
            Owner::Team(ref team) => team.id,
        }
    }

    pub fn encodable(self) -> EncodableOwner {
        match self {
            Owner::User(User {
                            id,
                            email,
                            name,
                            gh_login,
                            gh_avatar,
                            ..
                        }) => {
                let url = format!("https://github.com/{}", gh_login);
                EncodableOwner {
                    id: id,
                    login: gh_login,
                    email: email,
                    avatar: gh_avatar,
                    url: Some(url),
                    name: name,
                    kind: String::from("user"),
                }
            }
            Owner::Team(Team {
                            id,
                            name,
                            login,
                            avatar,
                            ..
                        }) => {
                let url = {
                    let mut parts = login.split(':');
                    parts.next(); // discard github
                    format!(
                        "https://github.com/orgs/{}/teams/{}",
                        parts.next().expect("org failed"),
                        parts.next().expect("team failed")
                    )
                };
                EncodableOwner {
                    id: id,
                    login: login,
                    email: None,
                    url: Some(url),
                    avatar: avatar,
                    name: name,
                    kind: String::from("team"),
                }
            }
        }
    }
}

/// Given this set of owners, determines the strongest rights the
/// given user has.
///
/// Shortcircuits on `Full` because you can't beat it. In practice we'll always
/// see `[user, user, user, ..., team, team, team]`, so we could shortcircuit on
/// `Publish` as well, but this is a non-obvious invariant so we don't bother.
/// Sweet free optimization if teams are proving burdensome to check.
/// More than one team isn't really expected, though.
pub fn rights(app: &App, owners: &[Owner], user: &User) -> CargoResult<Rights> {
    let mut best = Rights::None;
    for owner in owners {
        match *owner {
            Owner::User(ref other_user) => {
                if other_user.id == user.id {
                    return Ok(Rights::Full);
                }
            }
            Owner::Team(ref team) => {
                if team.contains_user(app, user)? {
                    best = Rights::Publish;
                }
            }
        }
    }
    Ok(best)
}
<commit_msg>combine get_org and get_team into one function that gets the github url<commit_after>use diesel::prelude::*;
use diesel::pg::PgConnection;
use pg::rows::Row;

use app::App;
use http;
use schema::*;
use util::{CargoResult, human};
use {Model, User, Crate};

#[derive(Insertable, Associations, Identifiable)]
#[belongs_to(Crate)]
#[belongs_to(User, foreign_key = "owner_id")]
#[belongs_to(Team, foreign_key = "owner_id")]
#[table_name = "crate_owners"]
#[primary_key(crate_id, owner_id, owner_kind)]
pub struct CrateOwner {
    pub crate_id: i32,
    pub owner_id: i32,
    pub created_by: i32,
    pub owner_kind: i32,
}

#[repr(u32)]
pub enum OwnerKind {
    User = 0,
    Team = 1,
}

/// Unifies the notion of a User or a Team.
pub enum Owner {
    User(User),
    Team(Team),
}

/// For now, just a Github Team. Can be upgraded to other teams
/// later if desirable.
#[derive(Queryable, Identifiable, RustcEncodable, RustcDecodable)]
pub struct Team {
    /// Unique table id
    pub id: i32,
    /// "github:org:team"
    /// An opaque unique ID, that was at one point parsed out to query Github.
    /// We only query membership with github using the github_id, though.
    /// This is the only name we should ever talk to Cargo about.
    pub login: String,
    /// We're assuming these are stable
    pub github_id: i32,
    /// Sugary goodness
    pub name: Option<String>,
    pub avatar: Option<String>,
}

#[derive(RustcEncodable)]
pub struct EncodableTeam {
    pub id: i32,
    pub login: String,
    pub name: Option<String>,
    pub avatar: Option<String>,
    pub url: Option<String>,
}

#[derive(RustcEncodable, RustcDecodable)]
pub struct EncodableOwner {
    pub id: i32,
    pub login: String,
    pub kind: String,
    pub email: Option<String>,
    pub url: Option<String>,
    pub name: Option<String>,
    pub avatar: Option<String>,
}

/// Access rights to the crate (publishing and ownership management)
/// NOTE: The order of these variants matters!
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub enum Rights {
    None,
    Publish,
    Full,
}

#[derive(Insertable, AsChangeset)]
#[table_name = "teams"]
pub struct NewTeam<'a> {
    pub login: &'a str,
    pub github_id: i32,
    pub name: Option<String>,
    pub avatar: Option<String>,
}

impl<'a> NewTeam<'a> {
    pub fn new(
        login: &'a str,
        github_id: i32,
        name: Option<String>,
        avatar: Option<String>,
    ) -> Self {
        NewTeam {
            login: login,
            github_id: github_id,
            name: name,
            avatar: avatar,
        }
    }

    pub fn create_or_update(&self, conn: &PgConnection) -> CargoResult<Team> {
        use diesel::insert;
        use diesel::pg::upsert::*;

        insert(&self.on_conflict(teams::github_id, do_update().set(self)))
            .into(teams::table)
            .get_result(conn)
            .map_err(Into::into)
    }
}

impl Team {
    /// Tries to create the Team in the DB (assumes a `:` has already been found).
    pub fn create(
        app: &App,
        conn: &PgConnection,
        login: &str,
        req_user: &User,
    ) -> CargoResult<Self> {
        // must look like system:xxxxxxx
        let mut chunks = login.split(':');
        match chunks.next().unwrap() {
            // github:rust-lang:owners
            "github" => {
                // Ok to unwrap since we know one ":" is contained
                let org = chunks.next().unwrap();
                let team = chunks.next().ok_or_else(|| {
                    human(
                        "missing github team argument; \
                            format is github:org:team",
                    )
                })?;
                Team::create_github_team(app, conn, login, org, team, req_user)
            }
            _ => {
                Err(human(
                    "unknown organization handler, \
                            only 'github:org:team' is supported",
                ))
            }
        }
    }

    /// Tries to create a Github Team from scratch. Assumes `org` and `team` are
    /// correctly parsed out of the full `name`. `name` is passed as a
    /// convenience to avoid rebuilding it.
    pub fn create_github_team(
        app: &App,
        conn: &PgConnection,
        login: &str,
        org_name: &str,
        team_name: &str,
        req_user: &User,
    ) -> CargoResult<Self> {
        // GET orgs/:org/teams
        // check that `team` is the `slug` in results, and grab its data

        // "sanitization"
        fn whitelist(c: &char) -> bool {
            match *c {
                'a'...'z' | 'A'...'Z' | '0'...'9' | '-' | '_' => false,
                _ => true,
            }
        }

        if let Some(c) = org_name.chars().find(whitelist) {
            return Err(human(&format_args!(
                "organization cannot contain special \
                                        characters like {}",
                c
            )));
        }

        #[derive(RustcDecodable)]
        struct GithubTeam {
            slug: String, // the name we want to find
            id: i32, // unique GH id (needed for membership queries)
            name: Option<String>, // Pretty name
        }

        // FIXME: we just set per_page=100 and don't bother chasing pagination
        // links. A hundred teams should be enough for any org, right?
        let url = format!("/orgs/{}/teams?per_page=100", org_name);
        let token = http::token(req_user.gh_access_token.clone());
        let (handle, data) = http::github(app, &url, &token)?;
        let teams: Vec<GithubTeam> = http::parse_github_response(handle, &data)?;

        let team = teams
            .into_iter()
            .find(|team| team.slug == team_name)
            .ok_or_else(|| {
                human(&format_args!(
                    "could not find the github team {}/{}",
                    org_name,
                    team_name
                ))
            })?;

        if !team_with_gh_id_contains_user(app, team.id, req_user)? {
            return Err(human("only members of a team can add it as an owner"));
        }

        #[derive(RustcDecodable)]
        struct Org {
            avatar_url: Option<String>,
        }

        let url = format!("/orgs/{}", org_name);
        let (handle, resp) = http::github(app, &url, &token)?;
        let org: Org = http::parse_github_response(handle, &resp)?;

        NewTeam::new(login, team.id, team.name, org.avatar_url).create_or_update(&conn)
    }

    /// Phones home to Github to ask if this User is a member of the given team.
    /// Note that we're assuming that the given user is the one interested in
    /// the answer. If this is not the case, then we could accidentally leak
    /// private membership information here.
    pub fn contains_user(&self, app: &App, user: &User) -> CargoResult<bool> {
        team_with_gh_id_contains_user(app, self.github_id, user)
    }

    pub fn encodable(self) -> EncodableTeam {
        let Team {
            id,
            name,
            login,
            avatar,
            ..
        } = self;
        let url = Team::github_url(&login);

        EncodableTeam {
            id: id,
            login: login,
            name: name,
            avatar: avatar,
            url: Some(url),
        }
    }

    fn github_url(login: &str) -> String {
        let mut login_pieces = login.split(':');
        login_pieces.next();

        format!(
            "https://github.com/orgs/{}/teams/{}",
            login_pieces.next().expect("org failed"),
            login_pieces.next().expect("team failed")
        )
    }
}

fn team_with_gh_id_contains_user(app: &App, github_id: i32, user: &User) -> CargoResult<bool> {
    // GET teams/:team_id/memberships/:user_name
    // check that "state": "active"

    #[derive(RustcDecodable)]
    struct Membership {
        state: String,
    }

    let url = format!("/teams/{}/memberships/{}", &github_id, &user.gh_login);
    let token = http::token(user.gh_access_token.clone());
    let (mut handle, resp) = http::github(app, &url, &token)?;

    // Officially how `false` is returned
    if handle.response_code().unwrap() == 404 {
        return Ok(false);
    }

    let membership: Membership = http::parse_github_response(handle, &resp)?;

    // There is also `state: pending` for which we could possibly give
    // some feedback, but it's not obvious how that should work.
    Ok(membership.state == "active")
}

impl Model for Team {
    fn from_row(row: &Row) -> Self {
        Team {
            id: row.get("id"),
            name: row.get("name"),
            github_id: row.get("github_id"),
            login: row.get("login"),
            avatar: row.get("avatar"),
        }
    }

    fn table_name(_: Option<Self>) -> &'static str {
        "teams"
    }
}

impl Owner {
    /// Finds the owner by name, failing out if it doesn't exist.
    /// May be a user's GH login, or a full team name. This is case
    /// sensitive.
    pub fn find_by_login(conn: &PgConnection, name: &str) -> CargoResult<Owner> {
        if name.contains(':') {
            teams::table
                .filter(teams::login.eq(name))
                .first(conn)
                .map(Owner::Team)
                .map_err(|_| {
                    human(&format_args!("could not find team with name {}", name))
                })
        } else {
            users::table
                .filter(users::gh_login.eq(name))
                .first(conn)
                .map(Owner::User)
                .map_err(|_| {
                    human(&format_args!("could not find user with login `{}`", name))
                })
        }
    }

    pub fn kind(&self) -> i32 {
        match *self {
            Owner::User(_) => OwnerKind::User as i32,
            Owner::Team(_) => OwnerKind::Team as i32,
        }
    }

    pub fn login(&self) -> &str {
        match *self {
            Owner::User(ref user) => &user.gh_login,
            Owner::Team(ref team) => &team.login,
        }
    }

    pub fn id(&self) -> i32 {
        match *self {
            Owner::User(ref user) => user.id,
            Owner::Team(ref team) => team.id,
        }
    }

    pub fn encodable(self) -> EncodableOwner {
        match self {
            Owner::User(User {
                            id,
                            email,
                            name,
                            gh_login,
                            gh_avatar,
                            ..
                        }) => {
                let url = format!("https://github.com/{}", gh_login);
                EncodableOwner {
                    id: id,
                    login: gh_login,
                    email: email,
                    avatar: gh_avatar,
                    url: Some(url),
                    name: name,
                    kind: String::from("user"),
                }
            }
            Owner::Team(Team {
                            id,
                            name,
                            login,
                            avatar,
                            ..
                        }) => {
                let url = Team::github_url(&login);
                EncodableOwner {
                    id: id,
                    login: login,
                    email: None,
                    url: Some(url),
                    avatar: avatar,
                    name: name,
                    kind: String::from("team"),
                }
            }
        }
    }
}

/// Given this set of owners, determines the strongest rights the
/// given user has.
///
/// Shortcircuits on `Full` because you can't beat it. In practice we'll always
/// see `[user, user, user, ..., team, team, team]`, so we could shortcircuit on
/// `Publish` as well, but this is a non-obvious invariant so we don't bother.
/// Sweet free optimization if teams are proving burdensome to check.
/// More than one team isn't really expected, though.
pub fn rights(app: &App, owners: &[Owner], user: &User) -> CargoResult<Rights> {
    let mut best = Rights::None;
    for owner in owners {
        match *owner {
            Owner::User(ref other_user) => {
                if other_user.id == user.id {
                    return Ok(Rights::Full);
                }
            }
            Owner::Team(ref team) => {
                if team.contains_user(app, user)? {
                    best = Rights::Publish;
                }
            }
        }
    }
    Ok(best)
}
<|endoftext|>


<commit_before>use character::CharacterDrawable;
use crossbeam_channel as channel;
use game::constants::{CHARACTER_X_SPEED, CHARACTER_Y_SPEED};
use graphics::{camera::CameraInputState, can_move_to_tile, DeltaTime, orientation::Orientation};
use shaders::Position;
use specs;
use specs::prelude::{Read, ReadStorage, WriteStorage};

#[derive(Clone, Debug)]
pub struct CharacterInputState {
  pub movement: Position,
  pub orientation: Orientation,
  pub is_colliding: bool,
  pub is_shooting: bool,
}

impl CharacterInputState {
  pub fn new() -> CharacterInputState {
    CharacterInputState {
      movement: Position::new(0.0, 0.0),
      orientation: Orientation::Still,
      is_colliding: false,
      is_shooting: false,
    }
  }

  pub fn update(&mut self, camera: &mut CameraInputState, css: &CharacterControlSystem) {
    if css.y_move.is_none() && css.x_move.is_none() {
        self.orientation = Orientation::Still;
    } else if css.x_move.is_none() {
      if let Some(y) = css.y_move {
        let vert_move = self.movement + Position::new(0.0, y);
        if !self.is_colliding || can_move_to_tile(vert_move) {
          self.movement = vert_move;
          camera.movement = camera.movement - Position::new(0.0, y);
          self.orientation = match y {
            y if y < 0.0 => Orientation::Up,
            y if y > 0.0 => Orientation::Down,
            _ => Orientation::Still,
          };
        }
      }
    } else if let Some(x) = css.x_move {
      let horizontal_move  = self.movement + Position::new(x, 0.0);
      if let Some(y) = css.y_move {
        let diag_move = self.movement + Position::new(x, y);
        if !self.is_colliding || can_move_to_tile(diag_move) {
          self.movement = self.movement + Position::new(x / 1.5, y / 1.5);
          camera.movement = camera.movement + Position::new(x / 1.5, 0.0) - Position::new(0.0, y / 1.5);

          self.orientation = match (x, y) {
            (x, y) if x > 0.0 && y > 0.0 => Orientation::DownLeft,
            (x, y) if x > 0.0 && y < 0.0 => Orientation::UpLeft,
            (x, y) if x < 0.0 && y > 0.0 => Orientation::DownRight,
            (x, y) if x < 0.0 && y < 0.0 => Orientation::UpRight,
            _ => Orientation::Still,
          };
        }
      } else if css.y_move.is_none() && !self.is_colliding || can_move_to_tile(horizontal_move) {
        self.movement = self.movement + Position::new(x, 0.0);
        camera.movement = camera.movement + Position::new(x, 0.0);
        self.orientation = match x {
          x if x < 0.0 => Orientation::Right,
          x if x > 0.0 => Orientation::Left,
          _ => Orientation::Still,
        };
      }
    }
    self.is_shooting = css.is_ctrl_pressed;
  }
}

impl Default for CharacterInputState {
  fn default() -> Self {
    CharacterInputState::new()
  }
}

impl specs::prelude::Component for CharacterInputState {
  type Storage = specs::storage::DenseVecStorage<CharacterInputState>;
}

#[derive(Debug)]
pub enum CharacterControl {
  Left,
  Right,
  Up,
  Down,
  XMoveStop,
  YMoveStop,
  CtrlPressed,
  CtrlReleased,
}

#[derive(Debug)]
pub struct CharacterControlSystem {
  queue: channel::Receiver<CharacterControl>,
  x_move: Option<f32>,
  y_move: Option<f32>,
  cool_down: f64,
  is_ctrl_pressed: bool,
}

impl CharacterControlSystem {
  pub fn new() -> (CharacterControlSystem, channel::Sender<CharacterControl>) {
    let (tx, rx) = channel::unbounded();
    (CharacterControlSystem {
      queue: rx,
      x_move: None,
      y_move: None,
      cool_down: 1.0,
      is_ctrl_pressed: false,
    }, tx)
  }
}

impl<'a> specs::prelude::System<'a> for CharacterControlSystem {
  type SystemData = (WriteStorage<'a, CharacterInputState>,
                     ReadStorage<'a, CharacterDrawable>,
                     WriteStorage<'a, CameraInputState>,
                     Read<'a, DeltaTime>);

  fn run(&mut self, (mut character_input, character, mut camera_input, d): Self::SystemData) {
    use specs::join::Join;
    use graphics::orientation::Stance;
    let delta = d.0;

    if self.cool_down == 0.0 {
      self.cool_down += 0.1;
    } else {
      self.cool_down = (self.cool_down - delta).max(0.0);
      while let Some(control) = self.queue.try_recv() {
        match control {
          CharacterControl::Up => self.y_move = Some(-CHARACTER_Y_SPEED),
          CharacterControl::Down => self.y_move = Some(CHARACTER_Y_SPEED),
          CharacterControl::YMoveStop => self.y_move = None,
          CharacterControl::Right => self.x_move = Some(-CHARACTER_X_SPEED),
          CharacterControl::Left => self.x_move = Some(CHARACTER_X_SPEED),
          CharacterControl::XMoveStop => self.x_move = None,
          CharacterControl::CtrlPressed => self.is_ctrl_pressed = true,
          CharacterControl::CtrlReleased => self.is_ctrl_pressed = false,
        }
      }

      for (ci, c, camera) in (&mut character_input, &character, &mut camera_input).join() {
        if c.stance != Stance::NormalDeath {
          ci.update(camera, self);
        }
      }
    }
  }
}
<commit_msg>Refactor character movement code<commit_after>use character::CharacterDrawable;
use crossbeam_channel as channel;
use game::constants::{CHARACTER_X_SPEED, CHARACTER_Y_SPEED};
use graphics::{camera::CameraInputState, can_move_to_tile, DeltaTime, orientation::Orientation};
use shaders::Position;
use specs;
use specs::prelude::{Read, ReadStorage, WriteStorage};

#[derive(Clone, Debug)]
pub struct CharacterInputState {
  pub movement: Position,
  pub orientation: Orientation,
  pub is_colliding: bool,
  pub is_shooting: bool,
}

impl CharacterInputState {
  pub fn new() -> CharacterInputState {
    CharacterInputState {
      movement: Position::new(0.0, 0.0),
      orientation: Orientation::Still,
      is_colliding: false,
      is_shooting: false,
    }
  }

  pub fn update(&mut self, camera: &mut CameraInputState, css: &CharacterControlSystem) {
    if css.y_move.is_none() && css.x_move.is_none() {
        self.orientation = Orientation::Still;
    } else if css.x_move.is_none() {
      if let Some(y) = css.y_move {
        let vertical_movement = self.movement + Position::new(0.0, y);
        if !self.is_colliding || can_move_to_tile(vertical_movement) {
          self.movement = vertical_movement;
          camera.movement = camera.movement - Position::new(0.0, y);
          self.orientation = match y {
            y if y < 0.0 => Orientation::Up,
            y if y > 0.0 => Orientation::Down,
            _ => Orientation::Still,
          };
        }
      }
    } else if let Some(x) = css.x_move {
      let horizontal_move  = self.movement + Position::new(x, 0.0);
      if let Some(y) = css.y_move {
        let horizontal_movement = Position::new(x / 1.5, 0.0);
        let vertical_movement = Position::new(0.0, y / 1.5);
        if !self.is_colliding || can_move_to_tile(self.movement + horizontal_movement + vertical_movement) {
          self.movement = self.movement + horizontal_movement + vertical_movement;
          camera.movement = camera.movement + horizontal_movement - vertical_movement;

          self.orientation = match (x, y) {
            (x, y) if x > 0.0 && y > 0.0 => Orientation::DownLeft,
            (x, y) if x > 0.0 && y < 0.0 => Orientation::UpLeft,
            (x, y) if x < 0.0 && y > 0.0 => Orientation::DownRight,
            (x, y) if x < 0.0 && y < 0.0 => Orientation::UpRight,
            _ => Orientation::Still,
          };
        }
      } else if css.y_move.is_none() && !self.is_colliding || can_move_to_tile(horizontal_move) {
        let horizontal_movement = Position::new(x, 0.0);
        self.movement = self.movement + horizontal_movement;
        camera.movement = camera.movement + horizontal_movement;
        self.orientation = match x {
          x if x < 0.0 => Orientation::Right,
          x if x > 0.0 => Orientation::Left,
          _ => Orientation::Still,
        };
      }
    }
    self.is_shooting = css.is_ctrl_pressed;
  }
}

impl Default for CharacterInputState {
  fn default() -> Self {
    CharacterInputState::new()
  }
}

impl specs::prelude::Component for CharacterInputState {
  type Storage = specs::storage::DenseVecStorage<CharacterInputState>;
}

#[derive(Debug)]
pub enum CharacterControl {
  Left,
  Right,
  Up,
  Down,
  XMoveStop,
  YMoveStop,
  CtrlPressed,
  CtrlReleased,
}

#[derive(Debug)]
pub struct CharacterControlSystem {
  queue: channel::Receiver<CharacterControl>,
  x_move: Option<f32>,
  y_move: Option<f32>,
  cool_down: f64,
  is_ctrl_pressed: bool,
}

impl CharacterControlSystem {
  pub fn new() -> (CharacterControlSystem, channel::Sender<CharacterControl>) {
    let (tx, rx) = channel::unbounded();
    (CharacterControlSystem {
      queue: rx,
      x_move: None,
      y_move: None,
      cool_down: 1.0,
      is_ctrl_pressed: false,
    }, tx)
  }
}

impl<'a> specs::prelude::System<'a> for CharacterControlSystem {
  type SystemData = (WriteStorage<'a, CharacterInputState>,
                     ReadStorage<'a, CharacterDrawable>,
                     WriteStorage<'a, CameraInputState>,
                     Read<'a, DeltaTime>);

  fn run(&mut self, (mut character_input, character, mut camera_input, d): Self::SystemData) {
    use specs::join::Join;
    use graphics::orientation::Stance;
    let delta = d.0;

    if self.cool_down == 0.0 {
      self.cool_down += 0.1;
    } else {
      self.cool_down = (self.cool_down - delta).max(0.0);
      while let Some(control) = self.queue.try_recv() {
        match control {
          CharacterControl::Up => self.y_move = Some(-CHARACTER_Y_SPEED),
          CharacterControl::Down => self.y_move = Some(CHARACTER_Y_SPEED),
          CharacterControl::YMoveStop => self.y_move = None,
          CharacterControl::Right => self.x_move = Some(-CHARACTER_X_SPEED),
          CharacterControl::Left => self.x_move = Some(CHARACTER_X_SPEED),
          CharacterControl::XMoveStop => self.x_move = None,
          CharacterControl::CtrlPressed => self.is_ctrl_pressed = true,
          CharacterControl::CtrlReleased => self.is_ctrl_pressed = false,
        }
      }

      for (ci, c, camera) in (&mut character_input, &character, &mut camera_input).join() {
        if c.stance != Stance::NormalDeath {
          ci.update(camera, self);
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>use crate::iter::{self, Iter, IterImpl};
use crate::{Define, Error, Export, ExportArgs, FakeCallSite, Input, Macro, Visibility};
use proc_macro::Delimiter::{Brace, Bracket, Parenthesis};
use proc_macro::{Delimiter, Ident, Span, TokenStream, TokenTree};

pub(crate) fn parse_input(tokens: Iter) -> Result<Input, Error> {
    let attrs = parse_attributes(tokens)?;
    let vis = parse_visibility(tokens)?;
    let kw = parse_ident(tokens)?;
    if kw.to_string() == "use" {
        parse_export(attrs, vis, tokens).map(Input::Export)
    } else if kw.to_string() == "fn" {
        parse_define(attrs, vis, kw.span(), tokens).map(Input::Define)
    } else {
        Err(Error::new(
            kw.span(),
            "unexpected input to #[proc_macro_hack]",
        ))
    }
}

fn parse_export(attrs: TokenStream, vis: Visibility, tokens: Iter) -> Result<Export, Error> {
    let _ = parse_punct(tokens, ':');
    let _ = parse_punct(tokens, ':');
    let from = parse_ident(tokens)?;
    parse_punct(tokens, ':')?;
    parse_punct(tokens, ':')?;

    let mut macros = Vec::new();
    match tokens.peek() {
        Some(TokenTree::Group(group)) if group.delimiter() == Brace => {
            let ref mut content = iter::new(group.stream());
            loop {
                macros.push(parse_macro(content)?);
                if content.peek().is_none() {
                    break;
                }
                parse_punct(content, ',')?;
                if content.peek().is_none() {
                    break;
                }
            }
            tokens.next().unwrap();
        }
        _ => macros.push(parse_macro(tokens)?),
    }

    parse_punct(tokens, ';')?;
    Ok(Export {
        attrs,
        vis,
        from,
        macros,
    })
}

fn parse_punct(tokens: Iter, ch: char) -> Result<(), Error> {
    match tokens.peek() {
        Some(TokenTree::Punct(punct)) if punct.as_char() == ch => {
            tokens.next().unwrap();
            Ok(())
        }
        tt => Err(Error::new(
            tt.map_or_else(Span::call_site, TokenTree::span),
            format!("expected `{}`", ch),
        )),
    }
}

fn parse_define(
    attrs: TokenStream,
    vis: Visibility,
    fn_token: Span,
    tokens: Iter,
) -> Result<Define, Error> {
    if vis.is_none() {
        return Err(Error::new(
            fn_token,
            "functions tagged with `#[proc_macro_hack]` must be `pub`",
        ));
    }
    let name = parse_ident(tokens)?;
    let body = tokens.collect();
    Ok(Define { attrs, name, body })
}

fn parse_macro(tokens: Iter) -> Result<Macro, Error> {
    let name = parse_ident(tokens)?;
    let export_as = match tokens.peek() {
        Some(TokenTree::Ident(ident)) if ident.to_string() == "as" => {
            tokens.next().unwrap();
            parse_ident(tokens)?
        }
        _ => name.clone(),
    };
    Ok(Macro { name, export_as })
}

fn parse_ident(tokens: Iter) -> Result<Ident, Error> {
    match tokens.next() {
        Some(TokenTree::Ident(ident)) => Ok(ident),
        tt => Err(Error::new(
            tt.as_ref().map_or_else(Span::call_site, TokenTree::span),
            "expected identifier",
        )),
    }
}

fn parse_keyword(tokens: Iter, kw: &'static str) -> Result<(), Error> {
    match &tokens.next() {
        Some(TokenTree::Ident(ident)) if ident.to_string() == kw => Ok(()),
        tt => Err(Error::new(
            tt.as_ref().map_or_else(Span::call_site, TokenTree::span),
            format!("expected `{}`", kw),
        )),
    }
}

fn parse_int(tokens: Iter) -> Result<u16, Span> {
    match tokens.next() {
        Some(TokenTree::Literal(lit)) => lit.to_string().parse().map_err(|_| lit.span()),
        Some(tt) => Err(tt.span()),
        None => Err(Span::call_site()),
    }
}

fn parse_group(tokens: Iter, delimiter: Delimiter) -> Result<IterImpl, Error> {
    match &tokens.next() {
        Some(TokenTree::Group(group)) if group.delimiter() == delimiter => {
            Ok(iter::new(group.stream()))
        }
        tt => Err(Error::new(
            tt.as_ref().map_or_else(Span::call_site, TokenTree::span),
            "expected delimiter",
        )),
    }
}

fn parse_visibility(tokens: Iter) -> Result<Visibility, Error> {
    if let Some(TokenTree::Ident(ident)) = tokens.peek() {
        if ident.to_string() == "pub" {
            return Ok(Some(tokens.next().unwrap().span()));
        }
    }
    Ok(None)
}

fn parse_attributes(tokens: Iter) -> Result<TokenStream, Error> {
    let mut attrs = TokenStream::new();
    while let Some(TokenTree::Punct(punct)) = tokens.peek() {
        if punct.as_char() != '#' {
            break;
        }
        let span = punct.span();
        attrs.extend(tokens.next());
        match tokens.peek() {
            Some(TokenTree::Group(group)) if group.delimiter() == Bracket => {
                attrs.extend(tokens.next());
            }
            _ => return Err(Error::new(span, "unexpected input")),
        }
    }
    Ok(attrs)
}

pub(crate) fn parse_export_args(tokens: Iter) -> Result<ExportArgs, Error> {
    let mut args = ExportArgs {
        support_nested: false,
        internal_macro_calls: 0,
        fake_call_site: false,
    };

    while let Some(tt) = tokens.next() {
        match &tt {
            TokenTree::Ident(ident) if ident.to_string() == "support_nested" => {
                args.support_nested = true;
            }
            TokenTree::Ident(ident) if ident.to_string() == "internal_macro_calls" => {
                parse_punct(tokens, '=')?;
                let calls = parse_int(tokens).map_err(|span| {
                    Error::new(span, "expected integer value for internal_macro_calls")
                })?;
                args.internal_macro_calls = calls;
            }
            TokenTree::Ident(ident) if ident.to_string() == "fake_call_site" => {
                args.fake_call_site = true;
            }
            _ => {
                return Err(Error::new(
                    tt.span(),
                    "expected one of: `support_nested`, `internal_macro_calls`, `fake_call_site`",
                ))
            }
        }
        if tokens.peek().is_none() {
            break;
        }
        parse_punct(tokens, ',')?;
    }

    Ok(args)
}

pub(crate) fn parse_define_args(tokens: Iter) -> Result<(), Error> {
    if tokens.peek().is_none() {
        Ok(())
    } else {
        Err(Error::new(Span::call_site(), "unexpected input"))
    }
}

pub(crate) fn parse_enum_hack(tokens: Iter) -> Result<TokenStream, Error> {
    parse_keyword(tokens, "enum")?;
    parse_ident(tokens)?;

    let ref mut braces = parse_group(tokens, Brace)?;
    parse_ident(braces)?;
    parse_punct(braces, '=')?;

    let ref mut parens = parse_group(braces, Parenthesis)?;
    parse_ident(parens)?;
    parse_punct(parens, '!')?;

    let ref mut inner = parse_group(parens, Brace)?;
    let token_stream = inner.collect();

    parse_punct(parens, ',')?;
    let _ = parens.next();
    parse_punct(braces, '.')?;
    let _ = braces.next();
    parse_punct(braces, ',')?;

    Ok(token_stream)
}

pub(crate) fn parse_fake_call_site(tokens: Iter) -> Result<FakeCallSite, Error> {
    parse_punct(tokens, '#')?;
    let ref mut attr = parse_group(tokens, Bracket)?;
    parse_keyword(attr, "derive")?;
    let ref mut path = parse_group(attr, Parenthesis)?;
    Ok(FakeCallSite {
        derive: parse_ident(path)?,
        rest: tokens.collect(),
    })
}
<commit_msg>Format with rustfmt 2.0.0-rc.2<commit_after>use crate::iter::{self, Iter, IterImpl};
use crate::{Define, Error, Export, ExportArgs, FakeCallSite, Input, Macro, Visibility};
use proc_macro::Delimiter::{Brace, Bracket, Parenthesis};
use proc_macro::{Delimiter, Ident, Span, TokenStream, TokenTree};

pub(crate) fn parse_input(tokens: Iter) -> Result<Input, Error> {
    let attrs = parse_attributes(tokens)?;
    let vis = parse_visibility(tokens)?;
    let kw = parse_ident(tokens)?;
    if kw.to_string() == "use" {
        parse_export(attrs, vis, tokens).map(Input::Export)
    } else if kw.to_string() == "fn" {
        parse_define(attrs, vis, kw.span(), tokens).map(Input::Define)
    } else {
        Err(Error::new(
            kw.span(),
            "unexpected input to #[proc_macro_hack]",
        ))
    }
}

fn parse_export(attrs: TokenStream, vis: Visibility, tokens: Iter) -> Result<Export, Error> {
    let _ = parse_punct(tokens, ':');
    let _ = parse_punct(tokens, ':');
    let from = parse_ident(tokens)?;
    parse_punct(tokens, ':')?;
    parse_punct(tokens, ':')?;

    let mut macros = Vec::new();
    match tokens.peek() {
        Some(TokenTree::Group(group)) if group.delimiter() == Brace => {
            let ref mut content = iter::new(group.stream());
            loop {
                macros.push(parse_macro(content)?);
                if content.peek().is_none() {
                    break;
                }
                parse_punct(content, ',')?;
                if content.peek().is_none() {
                    break;
                }
            }
            tokens.next().unwrap();
        }
        _ => macros.push(parse_macro(tokens)?),
    }

    parse_punct(tokens, ';')?;
    Ok(Export {
        attrs,
        vis,
        from,
        macros,
    })
}

fn parse_punct(tokens: Iter, ch: char) -> Result<(), Error> {
    match tokens.peek() {
        Some(TokenTree::Punct(punct)) if punct.as_char() == ch => {
            tokens.next().unwrap();
            Ok(())
        }
        tt => Err(Error::new(
            tt.map_or_else(Span::call_site, TokenTree::span),
            format!("expected `{}`", ch),
        )),
    }
}

fn parse_define(
    attrs: TokenStream,
    vis: Visibility,
    fn_token: Span,
    tokens: Iter,
) -> Result<Define, Error> {
    if vis.is_none() {
        return Err(Error::new(
            fn_token,
            "functions tagged with `#[proc_macro_hack]` must be `pub`",
        ));
    }
    let name = parse_ident(tokens)?;
    let body = tokens.collect();
    Ok(Define { attrs, name, body })
}

fn parse_macro(tokens: Iter) -> Result<Macro, Error> {
    let name = parse_ident(tokens)?;
    let export_as = match tokens.peek() {
        Some(TokenTree::Ident(ident)) if ident.to_string() == "as" => {
            tokens.next().unwrap();
            parse_ident(tokens)?
        }
        _ => name.clone(),
    };
    Ok(Macro { name, export_as })
}

fn parse_ident(tokens: Iter) -> Result<Ident, Error> {
    match tokens.next() {
        Some(TokenTree::Ident(ident)) => Ok(ident),
        tt => Err(Error::new(
            tt.as_ref().map_or_else(Span::call_site, TokenTree::span),
            "expected identifier",
        )),
    }
}

fn parse_keyword(tokens: Iter, kw: &'static str) -> Result<(), Error> {
    match &tokens.next() {
        Some(TokenTree::Ident(ident)) if ident.to_string() == kw => Ok(()),
        tt => Err(Error::new(
            tt.as_ref().map_or_else(Span::call_site, TokenTree::span),
            format!("expected `{}`", kw),
        )),
    }
}

fn parse_int(tokens: Iter) -> Result<u16, Span> {
    match tokens.next() {
        Some(TokenTree::Literal(lit)) => lit.to_string().parse().map_err(|_| lit.span()),
        Some(tt) => Err(tt.span()),
        None => Err(Span::call_site()),
    }
}

fn parse_group(tokens: Iter, delimiter: Delimiter) -> Result<IterImpl, Error> {
    match &tokens.next() {
        Some(TokenTree::Group(group)) if group.delimiter() == delimiter => {
            Ok(iter::new(group.stream()))
        }
        tt => Err(Error::new(
            tt.as_ref().map_or_else(Span::call_site, TokenTree::span),
            "expected delimiter",
        )),
    }
}

fn parse_visibility(tokens: Iter) -> Result<Visibility, Error> {
    if let Some(TokenTree::Ident(ident)) = tokens.peek() {
        if ident.to_string() == "pub" {
            return Ok(Some(tokens.next().unwrap().span()));
        }
    }
    Ok(None)
}

fn parse_attributes(tokens: Iter) -> Result<TokenStream, Error> {
    let mut attrs = TokenStream::new();
    while let Some(TokenTree::Punct(punct)) = tokens.peek() {
        if punct.as_char() != '#' {
            break;
        }
        let span = punct.span();
        attrs.extend(tokens.next());
        match tokens.peek() {
            Some(TokenTree::Group(group)) if group.delimiter() == Bracket => {
                attrs.extend(tokens.next());
            }
            _ => return Err(Error::new(span, "unexpected input")),
        }
    }
    Ok(attrs)
}

pub(crate) fn parse_export_args(tokens: Iter) -> Result<ExportArgs, Error> {
    let mut args = ExportArgs {
        support_nested: false,
        internal_macro_calls: 0,
        fake_call_site: false,
    };

    while let Some(tt) = tokens.next() {
        match &tt {
            TokenTree::Ident(ident) if ident.to_string() == "support_nested" => {
                args.support_nested = true;
            }
            TokenTree::Ident(ident) if ident.to_string() == "internal_macro_calls" => {
                parse_punct(tokens, '=')?;
                let calls = parse_int(tokens).map_err(|span| {
                    Error::new(span, "expected integer value for internal_macro_calls")
                })?;
                args.internal_macro_calls = calls;
            }
            TokenTree::Ident(ident) if ident.to_string() == "fake_call_site" => {
                args.fake_call_site = true;
            }
            _ => {
                return Err(Error::new(
                    tt.span(),
                    "expected one of: `support_nested`, `internal_macro_calls`, `fake_call_site`",
                ));
            }
        }
        if tokens.peek().is_none() {
            break;
        }
        parse_punct(tokens, ',')?;
    }

    Ok(args)
}

pub(crate) fn parse_define_args(tokens: Iter) -> Result<(), Error> {
    if tokens.peek().is_none() {
        Ok(())
    } else {
        Err(Error::new(Span::call_site(), "unexpected input"))
    }
}

pub(crate) fn parse_enum_hack(tokens: Iter) -> Result<TokenStream, Error> {
    parse_keyword(tokens, "enum")?;
    parse_ident(tokens)?;

    let ref mut braces = parse_group(tokens, Brace)?;
    parse_ident(braces)?;
    parse_punct(braces, '=')?;

    let ref mut parens = parse_group(braces, Parenthesis)?;
    parse_ident(parens)?;
    parse_punct(parens, '!')?;

    let ref mut inner = parse_group(parens, Brace)?;
    let token_stream = inner.collect();

    parse_punct(parens, ',')?;
    let _ = parens.next();
    parse_punct(braces, '.')?;
    let _ = braces.next();
    parse_punct(braces, ',')?;

    Ok(token_stream)
}

pub(crate) fn parse_fake_call_site(tokens: Iter) -> Result<FakeCallSite, Error> {
    parse_punct(tokens, '#')?;
    let ref mut attr = parse_group(tokens, Bracket)?;
    parse_keyword(attr, "derive")?;
    let ref mut path = parse_group(attr, Parenthesis)?;
    Ok(FakeCallSite {
        derive: parse_ident(path)?,
        rest: tokens.collect(),
    })
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! Scene infrastructure to be used with Gfx phases.

extern crate "gfx_phase" as phase;
extern crate gfx;
extern crate cgmath;

use std::fmt::Debug;
use std::marker::PhantomData;

/// Scene drawing error.
#[derive(Debug)]
pub enum Error {
    /// Error in creating a batch.
    Batch(gfx::batch::Error),
    /// Error in sending a batch for drawing.
    Flush(phase::FlushError),
}

/// Abstract information about the view. Supposed to containt at least
/// Model-View-Projection transform for the shader.
pub trait ViewInfo<S, T: cgmath::Transform3<S>>: phase::ToDepth<Depth = S> {
    /// Construct a new information block.
    fn new(mvp: cgmath::Matrix4<S>, view: T, model: T) -> Self;
}

/// Abstract scene that can be drawn into something.
pub trait AbstractScene<R: gfx::Resources> {
    /// A type of the view information.
    type ViewInfo;
    /// A type of the entity.
    type Entity;
    /// A type of the camera.
    type Camera;

    /// Draw the contents of the scene with a specific phase into a renderer,
    /// using a given camera and a frame.
    fn draw<C: gfx::CommandBuffer<R>, H: phase::AbstractPhase<R, C, Self::Entity, Self::ViewInfo> + ?Sized>(
            &mut self, &mut H, &Self::Camera, &gfx::Frame<R>, &mut gfx::Renderer<R, C>) -> Result<(), Error>;
}

/// A class that manages spatial relations between objects.
pub trait World {
    /// Type of the scalar used in all associated mathematical constructs.
    type Scalar: cgmath::BaseFloat + 'static;
    /// Type of the transform that every node performs relative to the parent.
    type Transform: cgmath::Transform3<Self::Scalar> + Clone;
    /// Pointer to a node, associated with an entity, camera, or something else.
    type NodePtr;
    /// Pointer to a skeleton, associated with an enttity.
    type SkeletonPtr;
    /// Get the transformation of a specific node pointer.
    fn get_transform(&self, &Self::NodePtr) -> Self::Transform;
}

/// A simple struct representing an object with a given material, mesh, bound,
/// and spatial relation to other stuff in the world.
pub struct Entity<R: gfx::Resources, M, W: World, B> {
    /// Name of the entity.
    pub name: String,
    /// Assotiated material of the entity.
    pub material: M,
    /// Mesh.
    pub mesh: gfx::Mesh<R>,
    /// Mesh slice.
    pub slice: gfx::Slice<R>,
    /// Node pointer into the world.
    pub node: W::NodePtr,
    /// Skeleton pointer.
    pub skeleton: Option<W::SkeletonPtr>,
    /// Associated spatial bound of the entity.
    pub bound: B,
}

impl<R: gfx::Resources, M: phase::Material, W: World, B> phase::Entity<R, M> for Entity<R, M, W, B> {
    fn get_material(&self) -> &M {
        &self.material
    }
    fn get_mesh(&self) -> (&gfx::Mesh<R>, &gfx::Slice<R>) {
        (&self.mesh, &self.slice)
    }
}

/// A simple camera with generic projection and spatial relation.
pub struct Camera<P, N> {
    /// Name of the camera.
    pub name: String,
    /// Generic projection.
    pub projection: P,
    /// Generic spatial node.
    pub node: N,
}

/// A generic `draw()` routine that takes a phase and some entities, and draws them
/// into a given frame. It does frustum culling and `ViewInfo` construction.
/// It can be used as a helper for user-side scenes.
pub fn draw_entities<'a,
    R: gfx::Resources,
    C: gfx::CommandBuffer<R>,
    M: phase::Material + 'a,
    W: World + 'a,
    B: cgmath::Bound<W::Scalar> + Debug + 'a,
    H: phase::AbstractPhase<R, C, Entity<R, M, W, B>, V> + ?Sized,
    P: cgmath::Projection<W::Scalar>,
    V: ViewInfo<W::Scalar, W::Transform>,
    I: Iterator<Item = &'a mut Entity<R, M, W, B>>,
>
(   entities: I, phase: &mut H, world: &W, camera: &Camera<P, W::NodePtr>,
    cull_frustum: bool, frame: &gfx::Frame<R>,
    context: &mut gfx::batch::Context<R>, renderer: &mut gfx::Renderer<R, C>)
    -> Result<(), Error>
where
    R: 'a,
    R::Buffer: 'a,
    R::ArrayBuffer: 'a,
    R::Shader: 'a,
    R::Program: 'a,
    R::FrameBuffer: 'a,
    R::Surface: 'a,
    R::Texture: 'a,
    R::Sampler: 'a,
    W::Transform: 'a,
    W::NodePtr: 'a,
    W::SkeletonPtr: 'a,
{
    use cgmath::{Matrix, ToMatrix4, Transform};
    let cam_inverse = world.get_transform(&camera.node)
                           .invert().unwrap();
    let projection = camera.projection.to_matrix4()
                           .mul_m(&cam_inverse.to_matrix4());
    for entity in entities {
        if !phase.test(entity) {
            continue
        }
        let model = world.get_transform(&entity.node);
        let view = cam_inverse.concat(&model);
        let mvp = projection.mul_m(&model.to_matrix4());
        if cull_frustum && entity.bound.relate_clip_space(&mvp) == cgmath::Relation::Out {
            continue
        }
        let view_info = ViewInfo::new(mvp, view, model.clone());
        match phase.enqueue(entity, view_info, context) {
            Ok(()) => (),
            Err(e) => return Err(Error::Batch(e)),
        }
    }
    phase.flush(frame, context, renderer)
         .map_err(|e| Error::Flush(e))
}

/// An example scene type.
pub struct Scene<R: gfx::Resources, M, W: World, B, P, V> {
    /// A list of entities in the scene.
    pub entities: Vec<Entity<R, M, W, B>>,
    /// A list of cameras. It's not really useful, but `P` needs to be
    /// constrained in order to be able to implement `AbstractScene`.
    pub cameras: Vec<Camera<P, W::NodePtr>>,
    /// A flag controlling the frustum culling.
    pub cull_frustum: bool,
    /// Spatial world.
    pub world: W,
    context: gfx::batch::Context<R>,
    _view_dummy: PhantomData<V>,
}

impl<R: gfx::Resources, M, W: World, B, P, V> Scene<R, M, W, B, P, V> {
    /// Create a new empty scene.
    pub fn new(world: W) -> Scene<R, M, W, B, P, V> {
        Scene {
            entities: Vec::new(),
            cameras: Vec::new(),
            cull_frustum: true,
            world: world,
            context: gfx::batch::Context::new(),
            _view_dummy: PhantomData,
        }
    }
}

impl<
    R: gfx::Resources,
    M: phase::Material,
    W: World,
    B: cgmath::Bound<W::Scalar> + Debug,
    P: cgmath::Projection<W::Scalar>,
    V: ViewInfo<W::Scalar, W::Transform>,
> AbstractScene<R> for Scene<R, M, W, B, P, V> {
    type ViewInfo = V;
    type Entity = Entity<R, M, W, B>;
    type Camera = Camera<P, W::NodePtr>;

    fn draw<C: gfx::CommandBuffer<R>, H: phase::AbstractPhase<R, C, Entity<R, M, W, B>, V> + ?Sized>(
            &mut self, phase: &mut H, camera: &Camera<P, W::NodePtr>,
            frame: &gfx::Frame<R>, renderer: &mut gfx::Renderer<R, C>)
            -> Result<(), Error> {
        draw_entities(self.entities.iter_mut(), phase, &self.world, camera,
                      self.cull_frustum, frame, &mut self.context, renderer)
    }
}

/// Wrapper around a scene that carries a list of phases as well as the
/// `Renderer`, allowing to isolate a command buffer completely.
pub struct PhaseHarness<D: gfx::Device, C: AbstractScene<D::Resources>> {
    /// Wrapped scene.
    pub scene: C,
    /// Optional clear data.
    pub clear: Option<gfx::ClearData>,
    /// List of phases as trait objects.
    pub phases: Vec<Box<phase::AbstractPhase<D::Resources, D::CommandBuffer, C::Entity, C::ViewInfo>>>,
    /// Gfx renderer to draw into.
    pub renderer: gfx::Renderer<D::Resources, D::CommandBuffer>,
}

impl<D: gfx::Device, C: AbstractScene<D::Resources>> PhaseHarness<D, C> {
    /// Create a new empty phase harness.
    pub fn new(scene: C, renderer: gfx::Renderer<D::Resources, D::CommandBuffer>)
               -> PhaseHarness<D, C> {
        PhaseHarness {
            scene: scene,
            clear: None,
            phases: Vec::new(),
            renderer: renderer,
        }
    }

    /// Draw the scene into a given frame, using all the phases.
    pub fn draw(&mut self, camera: &C::Camera, frame: &gfx::Frame<D::Resources>)
                -> Result<gfx::SubmitInfo<D>, Error> {
        use std::ops::DerefMut;
        self.renderer.reset();
        match self.clear {
            Some(data) => self.renderer.clear(data, gfx::COLOR | gfx::DEPTH | gfx::STENCIL, frame),
            None => (),
        }
        for phase in self.phases.iter_mut() {
            match self.scene.draw(phase.deref_mut(), camera, frame, &mut self.renderer) {
                Ok(_) => (),
                Err(e) => return Err(e),
            }
        }
        Ok(self.renderer.as_buffer())
    }
}

/// A simple perspective camera based on the `World` trait.
pub type PerspectiveCam<W: World> = Camera<
    cgmath::PerspectiveFov<W::Scalar, cgmath::Rad<W::Scalar>>,
    W::NodePtr
>;
<commit_msg>Deriving Clone for Camera<commit_after>#![deny(missing_docs)]

//! Scene infrastructure to be used with Gfx phases.

extern crate "gfx_phase" as phase;
extern crate gfx;
extern crate cgmath;

use std::fmt::Debug;
use std::marker::PhantomData;

/// Scene drawing error.
#[derive(Debug)]
pub enum Error {
    /// Error in creating a batch.
    Batch(gfx::batch::Error),
    /// Error in sending a batch for drawing.
    Flush(phase::FlushError),
}

/// Abstract information about the view. Supposed to containt at least
/// Model-View-Projection transform for the shader.
pub trait ViewInfo<S, T: cgmath::Transform3<S>>: phase::ToDepth<Depth = S> {
    /// Construct a new information block.
    fn new(mvp: cgmath::Matrix4<S>, view: T, model: T) -> Self;
}

/// Abstract scene that can be drawn into something.
pub trait AbstractScene<R: gfx::Resources> {
    /// A type of the view information.
    type ViewInfo;
    /// A type of the entity.
    type Entity;
    /// A type of the camera.
    type Camera;

    /// Draw the contents of the scene with a specific phase into a renderer,
    /// using a given camera and a frame.
    fn draw<C: gfx::CommandBuffer<R>, H: phase::AbstractPhase<R, C, Self::Entity, Self::ViewInfo> + ?Sized>(
            &mut self, &mut H, &Self::Camera, &gfx::Frame<R>, &mut gfx::Renderer<R, C>) -> Result<(), Error>;
}

/// A class that manages spatial relations between objects.
pub trait World {
    /// Type of the scalar used in all associated mathematical constructs.
    type Scalar: cgmath::BaseFloat + 'static;
    /// Type of the transform that every node performs relative to the parent.
    type Transform: cgmath::Transform3<Self::Scalar> + Clone;
    /// Pointer to a node, associated with an entity, camera, or something else.
    type NodePtr;
    /// Pointer to a skeleton, associated with an enttity.
    type SkeletonPtr;
    /// Get the transformation of a specific node pointer.
    fn get_transform(&self, &Self::NodePtr) -> Self::Transform;
}

/// A simple struct representing an object with a given material, mesh, bound,
/// and spatial relation to other stuff in the world.
pub struct Entity<R: gfx::Resources, M, W: World, B> {
    /// Name of the entity.
    pub name: String,
    /// Assotiated material of the entity.
    pub material: M,
    /// Mesh.
    pub mesh: gfx::Mesh<R>,
    /// Mesh slice.
    pub slice: gfx::Slice<R>,
    /// Node pointer into the world.
    pub node: W::NodePtr,
    /// Skeleton pointer.
    pub skeleton: Option<W::SkeletonPtr>,
    /// Associated spatial bound of the entity.
    pub bound: B,
}

impl<R: gfx::Resources, M: phase::Material, W: World, B> phase::Entity<R, M> for Entity<R, M, W, B> {
    fn get_material(&self) -> &M {
        &self.material
    }
    fn get_mesh(&self) -> (&gfx::Mesh<R>, &gfx::Slice<R>) {
        (&self.mesh, &self.slice)
    }
}

/// A simple camera with generic projection and spatial relation.
#[derive(Clone, Debug)]
pub struct Camera<P, N> {
    /// Name of the camera.
    pub name: String,
    /// Generic projection.
    pub projection: P,
    /// Generic spatial node.
    pub node: N,
}

/// A generic `draw()` routine that takes a phase and some entities, and draws them
/// into a given frame. It does frustum culling and `ViewInfo` construction.
/// It can be used as a helper for user-side scenes.
pub fn draw_entities<'a,
    R: gfx::Resources,
    C: gfx::CommandBuffer<R>,
    M: phase::Material + 'a,
    W: World + 'a,
    B: cgmath::Bound<W::Scalar> + Debug + 'a,
    H: phase::AbstractPhase<R, C, Entity<R, M, W, B>, V> + ?Sized,
    P: cgmath::Projection<W::Scalar>,
    V: ViewInfo<W::Scalar, W::Transform>,
    I: Iterator<Item = &'a mut Entity<R, M, W, B>>,
>
(   entities: I, phase: &mut H, world: &W, camera: &Camera<P, W::NodePtr>,
    cull_frustum: bool, frame: &gfx::Frame<R>,
    context: &mut gfx::batch::Context<R>, renderer: &mut gfx::Renderer<R, C>)
    -> Result<(), Error>
where
    R: 'a,
    R::Buffer: 'a,
    R::ArrayBuffer: 'a,
    R::Shader: 'a,
    R::Program: 'a,
    R::FrameBuffer: 'a,
    R::Surface: 'a,
    R::Texture: 'a,
    R::Sampler: 'a,
    W::Transform: 'a,
    W::NodePtr: 'a,
    W::SkeletonPtr: 'a,
{
    use cgmath::{Matrix, ToMatrix4, Transform};
    let cam_inverse = world.get_transform(&camera.node)
                           .invert().unwrap();
    let projection = camera.projection.to_matrix4()
                           .mul_m(&cam_inverse.to_matrix4());
    for entity in entities {
        if !phase.test(entity) {
            continue
        }
        let model = world.get_transform(&entity.node);
        let view = cam_inverse.concat(&model);
        let mvp = projection.mul_m(&model.to_matrix4());
        if cull_frustum && entity.bound.relate_clip_space(&mvp) == cgmath::Relation::Out {
            continue
        }
        let view_info = ViewInfo::new(mvp, view, model.clone());
        match phase.enqueue(entity, view_info, context) {
            Ok(()) => (),
            Err(e) => return Err(Error::Batch(e)),
        }
    }
    phase.flush(frame, context, renderer)
         .map_err(|e| Error::Flush(e))
}

/// An example scene type.
pub struct Scene<R: gfx::Resources, M, W: World, B, P, V> {
    /// A list of entities in the scene.
    pub entities: Vec<Entity<R, M, W, B>>,
    /// A list of cameras. It's not really useful, but `P` needs to be
    /// constrained in order to be able to implement `AbstractScene`.
    pub cameras: Vec<Camera<P, W::NodePtr>>,
    /// A flag controlling the frustum culling.
    pub cull_frustum: bool,
    /// Spatial world.
    pub world: W,
    context: gfx::batch::Context<R>,
    _view_dummy: PhantomData<V>,
}

impl<R: gfx::Resources, M, W: World, B, P, V> Scene<R, M, W, B, P, V> {
    /// Create a new empty scene.
    pub fn new(world: W) -> Scene<R, M, W, B, P, V> {
        Scene {
            entities: Vec::new(),
            cameras: Vec::new(),
            cull_frustum: true,
            world: world,
            context: gfx::batch::Context::new(),
            _view_dummy: PhantomData,
        }
    }
}

impl<
    R: gfx::Resources,
    M: phase::Material,
    W: World,
    B: cgmath::Bound<W::Scalar> + Debug,
    P: cgmath::Projection<W::Scalar>,
    V: ViewInfo<W::Scalar, W::Transform>,
> AbstractScene<R> for Scene<R, M, W, B, P, V> {
    type ViewInfo = V;
    type Entity = Entity<R, M, W, B>;
    type Camera = Camera<P, W::NodePtr>;

    fn draw<C: gfx::CommandBuffer<R>, H: phase::AbstractPhase<R, C, Entity<R, M, W, B>, V> + ?Sized>(
            &mut self, phase: &mut H, camera: &Camera<P, W::NodePtr>,
            frame: &gfx::Frame<R>, renderer: &mut gfx::Renderer<R, C>)
            -> Result<(), Error> {
        draw_entities(self.entities.iter_mut(), phase, &self.world, camera,
                      self.cull_frustum, frame, &mut self.context, renderer)
    }
}

/// Wrapper around a scene that carries a list of phases as well as the
/// `Renderer`, allowing to isolate a command buffer completely.
pub struct PhaseHarness<D: gfx::Device, C: AbstractScene<D::Resources>> {
    /// Wrapped scene.
    pub scene: C,
    /// Optional clear data.
    pub clear: Option<gfx::ClearData>,
    /// List of phases as trait objects.
    pub phases: Vec<Box<phase::AbstractPhase<D::Resources, D::CommandBuffer, C::Entity, C::ViewInfo>>>,
    /// Gfx renderer to draw into.
    pub renderer: gfx::Renderer<D::Resources, D::CommandBuffer>,
}

impl<D: gfx::Device, C: AbstractScene<D::Resources>> PhaseHarness<D, C> {
    /// Create a new empty phase harness.
    pub fn new(scene: C, renderer: gfx::Renderer<D::Resources, D::CommandBuffer>)
               -> PhaseHarness<D, C> {
        PhaseHarness {
            scene: scene,
            clear: None,
            phases: Vec::new(),
            renderer: renderer,
        }
    }

    /// Draw the scene into a given frame, using all the phases.
    pub fn draw(&mut self, camera: &C::Camera, frame: &gfx::Frame<D::Resources>)
                -> Result<gfx::SubmitInfo<D>, Error> {
        use std::ops::DerefMut;
        self.renderer.reset();
        match self.clear {
            Some(data) => self.renderer.clear(data, gfx::COLOR | gfx::DEPTH | gfx::STENCIL, frame),
            None => (),
        }
        for phase in self.phases.iter_mut() {
            match self.scene.draw(phase.deref_mut(), camera, frame, &mut self.renderer) {
                Ok(_) => (),
                Err(e) => return Err(e),
            }
        }
        Ok(self.renderer.as_buffer())
    }
}

/// A simple perspective camera based on the `World` trait.
pub type PerspectiveCam<W: World> = Camera<
    cgmath::PerspectiveFov<W::Scalar, cgmath::Rad<W::Scalar>>,
    W::NodePtr
>;
<|endoftext|>


<commit_before>//! Scheduling game play.

use state::Player;
use state::{Action, State};

use std::sync::mpsc::Sender;

use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::mem::replace;

/// A `Scheduler` collects actions from all players, and then broadcasts the
/// full list once everyone has submitted their moves for that turn.
///
/// When a player submits their moves, they provide a `Sender` on which
/// `Scheduler` should send the full move list once it is available.
pub struct Scheduler {
    // The number of the last turn we broadcast out.
    turn: usize,

    // The number of players that have actually joined.
    joined: usize,

    // A scheduler actually maintains its own copy of the game state, for
    // generating checksums to send to clients.
    state: State,

    // A vector recording submitted actions and reply channels; the `i`'th
    // element is for `Player(i)`. Once this has actions for every joined player,
    // we apply all the actions to our state in a given order, compute the new
    // state's checksum, and then transmit the collected moves to all the
    // players.
    pending_actions: Vec<Option<(PlayerActions, Sender<CollectedActions>)>>
}

impl Scheduler {
    pub fn new(initial_state: State) -> Scheduler {
        let num_players = initial_state.map.player_colors.len();
        let mut pending_actions = Vec::new();
        for _ in 0..num_players {
            pending_actions.push(None)
        }
        Scheduler { turn: 0, joined: 0, state: initial_state, pending_actions }
    }

    // Add another player to the game. Return its number, or `None` if there is
    // no room for more players.
    pub fn player_join(&mut self) -> Option<usize> {
        if self.joined >= self.pending_actions.len() {
            None
        } else {
            self.joined += 1;
            Some(self.joined - 1)
        }
    }

    // Submit `actions` to be carried out as soon as possible. Request
    // that a collected list of all players' actions for the current turn
    // be sent to `reply_to`.
    pub fn submit_actions(&mut self,
                          actions: PlayerActions,
                          reply_to: Sender<CollectedActions>) {
        assert_eq!(actions.turn, self.turn);
        assert!(self.pending_actions[actions.player.0].is_none());
        let player = actions.player.0;
        self.pending_actions[player] = Some((actions, reply_to));

        // Have all the players that have joined finally submitted an action?
        if self.pending_actions.iter().take(self.joined).all(|o| o.is_some()) {
            // Grab the list of pending actions and reset it for the next turn.
            let pendings = replace(&mut self.pending_actions, vec![]);

            // Collect all the actions into a single vector,
            // collect all the reply-to's in another vector,
            // and apply all the actions to our state.
            let mut collected_reply_tos = Vec::new();
            let mut collected_actions = Vec::new();

            for player in pendings {
                let (player_actions, reply_to) = player.unwrap();
                for action in player_actions.actions {
                    self.state.take_action(&action);
                    collected_actions.push(action);
                }
                collected_reply_tos.push(reply_to);
            }

            // Compute a checksum for the resulting state.
            let mut hasher = DefaultHasher::new();
            self.state.hash(&mut hasher);
            let state_checksum = hasher.finish();

            // We are now in the new turn.
            self.turn += 1;

            let collected = CollectedActions {
                turn: self.turn,
                actions: collected_actions,
                state_checksum
            };

            // Broadcast out the new state of the world to all players.
            for reply_to in collected_reply_tos {
                reply_to.send(collected.clone())
                    .expect("sending collected moves failed");
            }
        }
    }
}

/// A set of actions submitted by a single player on a single turn.
#[derive(Clone, Debug)]
pub struct PlayerActions {
    // The player submitting these actions.
    player: Player,

    // The turn number they believe they're on.
    turn: usize,

    // The actions they wish to submit.
    actions: Vec<Action>,
}

/// A collection of all actions submitted by all players.
#[derive(Clone, Debug)]
pub struct CollectedActions {
    // The turn these moves produce when applied.
    turn: usize,

    // The actions to apply to the prior state.
    actions: Vec<Action>,

    // The hash value of the State that should result, as a checksum.
    state_checksum: u64
}
<commit_msg>Abstract out how scheduler notifies participants.<commit_after>//! Scheduling game play.

use state::Player;
use state::{Action, State};

use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::mem::replace;

/// A `Scheduler` collects actions from all players, and then broadcasts the
/// full list once everyone has submitted their moves for that turn.
///
/// When a player submits their moves, they provide a `Sender` on which
/// `Scheduler` should send the full move list once it is available.
pub struct Scheduler {
    // The number of the last turn we broadcast out.
    turn: usize,

    // The number of players that have actually joined.
    joined: usize,

    // A scheduler actually maintains its own copy of the game state, for
    // generating checksums to send to clients.
    state: State,

    // A vector recording submitted actions and reply channels; the `i`'th
    // element is for `Player(i)`. Once this has actions for every joined player,
    // we apply all the actions to our state in a given order, compute the new
    // state's checksum, and then transmit the collected moves to all the
    // players.
    pending_actions: Vec<Option<(PlayerActions, Box<Notifier>)>>
}

/// Something that can notify a player of a turn's actions when they have been
/// collected.
trait Notifier {
    fn notify(&self, turn: CollectedActions);
}

impl Scheduler {
    pub fn new(initial_state: State) -> Scheduler {
        let num_players = initial_state.map.player_colors.len();
        let mut pending_actions = Vec::new();
        for _ in 0..num_players {
            pending_actions.push(None)
        }
        Scheduler { turn: 0, joined: 0, state: initial_state, pending_actions }
    }

    // Add another player to the game. Return its number, or `None` if there is
    // no room for more players.
    pub fn player_join(&mut self) -> Option<usize> {
        if self.joined >= self.pending_actions.len() {
            None
        } else {
            self.joined += 1;
            Some(self.joined - 1)
        }
    }

    // Submit `actions` to be carried out as soon as possible. When all players'
    // actions have been collected, send the full list to `reply_to`.
    pub fn submit_actions(&mut self,
                          actions: PlayerActions,
                          reply_to: Box<Notifier>) {
        assert_eq!(actions.turn, self.turn);
        assert!(self.pending_actions[actions.player.0].is_none());
        let player = actions.player.0;
        self.pending_actions[player] = Some((actions, reply_to));

        // Have all the players that have joined finally submitted an action?
        if self.pending_actions.iter().take(self.joined).all(|o| o.is_some()) {
            // Grab the list of pending actions and reset it for the next turn.
            let pendings = replace(&mut self.pending_actions, vec![]);

            // Collect all the actions into a single vector,
            // collect all the reply-to's in another vector,
            // and apply all the actions to our state.
            let mut collected_reply_tos = Vec::new();
            let mut collected_actions = Vec::new();

            for player in pendings {
                let (player_actions, reply_to) = player.unwrap();
                for action in player_actions.actions {
                    self.state.take_action(&action);
                    collected_actions.push(action);
                }
                collected_reply_tos.push(reply_to);
            }

            // Compute a checksum for the resulting state.
            let mut hasher = DefaultHasher::new();
            self.state.hash(&mut hasher);
            let state_checksum = hasher.finish();

            // We are now in the new turn.
            self.turn += 1;

            let collected = CollectedActions {
                turn: self.turn,
                actions: collected_actions,
                state_checksum
            };

            // Broadcast out the new state of the world to all players.
            for reply_to in collected_reply_tos {
                reply_to.notify(collected.clone());
            }
        }
    }
}

/// A set of actions submitted by a single player on a single turn.
#[derive(Clone, Debug)]
pub struct PlayerActions {
    // The player submitting these actions.
    player: Player,

    // The turn number they believe they're on.
    turn: usize,

    // The actions they wish to submit.
    actions: Vec<Action>,
}

/// A collection of all actions submitted by all players.
#[derive(Clone, Debug)]
pub struct CollectedActions {
    // The turn these moves produce when applied.
    turn: usize,

    // The actions to apply to the prior state.
    actions: Vec<Action>,

    // The hash value of the State that should result, as a checksum.
    state_checksum: u64
}
<|endoftext|>


<commit_before>// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.

//! jsonrpc server over win named pipes
//!
//! ```no_run
//! extern crate jsonrpc_core;
//! extern crate jsonrpc_ipc_server;
//!
//! use std::sync::Arc;
//! use jsonrpc_core::*;
//! use jsonrpc_ipc_server::Server;
//!
//! struct SayHello;
//! impl SyncMethodCommand for SayHello {
//! 	fn execute(&self, _params: Params) -> Result<Value, Error> {
//! 		Ok(Value::String("hello".to_string()))
//! 	}
//! }
//!
//! fn main() {
//! 	let io = IoHandler::new();
//! 	io.add_method("say_hello", SayHello);
//! 	let server = Server::new("/tmp/json-ipc-test.ipc", &Arc::new(io)).unwrap();
//!     ::std::thread::spawn(move || server.run());
//! }
//! ```

//! Named pipes library

use miow::pipe::{NamedPipe, NamedPipeBuilder};
use std;
use std::io;
use std::io::{Read, Write};
use std::sync::atomic::*;
use std::sync::Arc;
use jsonrpc_core::IoHandler;
use validator;

pub type Result<T> = std::result::Result<T, Error>;

const MAX_REQUEST_LEN: u32 = 65536;
const REQUEST_READ_BATCH: usize = 4096;

#[derive(Debug)]
pub enum Error {
	Io(std::io::Error),
	NotStarted,
	AlreadyStopping,
	NotStopped,
	IsStopping,
}

impl std::convert::From<std::io::Error> for Error {
	fn from(io_error: std::io::Error) -> Error {
		Error::Io(io_error)
	}
}

pub struct PipeHandler {
	waiting_pipe: NamedPipe,
	io_handler: Arc<IoHandler>,
}

impl PipeHandler {
	/// start ipc rpc server (blocking)
	pub fn start(addr: &str, io_handler: &Arc<IoHandler>) -> Result<PipeHandler> {
		Ok(PipeHandler {
			waiting_pipe: try!(
				NamedPipeBuilder::new(addr)
					.first(true)
					.accept_remote(true)
					.max_instances(255)
					.inbound(true)
					.outbound(true)
					.out_buffer_size(MAX_REQUEST_LEN)
					.in_buffer_size(MAX_REQUEST_LEN)
					.create()
			),
			io_handler: io_handler.clone(),
		})
	}

	fn handle_incoming(&mut self, addr: &str, stop: Arc<AtomicBool>) -> io::Result<()> {
		trace!(target: "ipc", "Waiting for client: [{}]", addr);
		try!(self.waiting_pipe.connect());
		trace!(target: "ipc", "Received connection to address [{}]", addr);
		if stop.load(Ordering::Relaxed) {
			trace!(target: "ipc", "Stopped listening sequence [{}]", addr);
			return Ok(())
		}

		let mut connected_pipe = std::mem::replace::<NamedPipe>(&mut self.waiting_pipe,
			try!(NamedPipeBuilder::new(addr)
				.first(false)
				.accept_remote(true)
				.inbound(true)
				.outbound(true)
				.out_buffer_size(MAX_REQUEST_LEN)
				.in_buffer_size(MAX_REQUEST_LEN)
				.create()));

		let thread_handler = self.io_handler.clone();
		std::thread::spawn(move || {
			let mut buf = vec![0u8; MAX_REQUEST_LEN as usize];
			let mut fin = REQUEST_READ_BATCH;
			loop {
				let start = fin - REQUEST_READ_BATCH;
				trace!(target: "ipc", "Reading {} - {} of the buffer", start, fin);
				match connected_pipe.read(&mut buf[start..fin]) {
					Ok(size) => {
						let (requests, last_index) = {
							let effective = &buf[0..start + size];
							fin = fin + size;
							trace!(target: "ipc", "Received rpc data: {} bytes", effective.len());

							validator::extract_requests(effective)
						};
						if requests.len() > 0 {
							let mut response_buf = Vec::new();
							for rpc_msg in requests  {
								trace!(target: "ipc", "Request: {}", rpc_msg);

								let response: Option<String> = thread_handler.handle_request_sync(&rpc_msg);

								if let Some(response_str) = response {
									trace!(target: "ipc", "Response: {}", &response_str);
									response_buf.extend(response_str.into_bytes());
								}
							}

							if let Err(write_err) = connected_pipe.write_all(&response_buf[..]).and_then(|_| connected_pipe.flush()) {
								trace!(target: "ipc", "Response write error: {:?}", write_err);
							}
							else {
								trace!(target: "ipc", "Sent rpc response: {} bytes", response_buf.len());
							}

							let leftover_len = start + size - (last_index + 1);
							if leftover_len > 0 {
								let leftover = buf[last_index + 1..start + size].to_vec();
								buf[0..leftover_len].copy_from_slice(&leftover[..]);
							}
							fin = leftover_len + REQUEST_READ_BATCH;
						}
						else { continue; }
					},
					Err(e) => {
						// closed connection
						trace!(target: "ipc", "Dropped connection {:?}", e);
						break;
					}
				}
			}
		});

		Ok(())
	}
}

pub struct Server {
	is_stopping: Arc<AtomicBool>,
	is_stopped: Arc<AtomicBool>,
	addr: String,
	io_handler: Arc<IoHandler>,
}

impl Server {
	/// New server
	pub fn new(socket_addr: &str, io_handler: &Arc<IoHandler>) -> Result<Server> {
		Ok(Server {
			io_handler: io_handler.clone(),
			is_stopping: Arc::new(AtomicBool::new(false)),
			is_stopped: Arc::new(AtomicBool::new(true)),
			addr: socket_addr.to_owned(),
		})
	}

	/// Run server (in this thread)
	pub fn run(&self) -> Result<()> {
		let mut pipe_handler = try!(PipeHandler::start(&self.addr, &self.io_handler));
		loop  {
			try!(pipe_handler.handle_incoming(&self.addr, Arc::new(AtomicBool::new(false))));
		}
	}

	/// Run server (in separate thread)
	pub fn run_async(&self) -> Result<()> {
		if self.is_stopping.load(Ordering::Relaxed) { return Err(Error::IsStopping) }
		if !self.is_stopped.load(Ordering::Relaxed) { return Err(Error::NotStopped) }

		trace!(target: "ipc", "Started named pipes server [{}]", self.addr);

		let thread_stopping = self.is_stopping.clone();
		let thread_stopped = self.is_stopped.clone();
		let thread_handler = self.io_handler.clone();
		let addr = self.addr.clone();
		std::thread::spawn(move || {
			let mut pipe_handler = PipeHandler::start(&addr, &thread_handler).unwrap();
			while !thread_stopping.load(Ordering::Relaxed) {
				trace!(target: "ipc", "Accepting pipe connection");
				if let Err(pipe_listener_error) = pipe_handler.handle_incoming(&addr, thread_stopping.clone()) {
					trace!(target: "ipc", "Pipe listening error: {:?}", pipe_listener_error);
				}
			}
			thread_stopped.store(true, Ordering::Relaxed);
		});

		self.is_stopped.store(false, Ordering::Relaxed);
		Ok(())
	}

	pub fn stop_async(&self) -> Result<()> {
		if self.is_stopped.load(Ordering::Relaxed) { return Err(Error::NotStarted) }
		if self.is_stopping.load(Ordering::Relaxed) { return Err(Error::AlreadyStopping)}
		self.is_stopping.store(true, Ordering::Relaxed);
		Ok(())
	}

	pub fn stop(&self) -> Result<()> {
		if self.is_stopped.load(Ordering::Relaxed) { return Err(Error::NotStarted) }
		if self.is_stopping.load(Ordering::Relaxed) { return Err(Error::AlreadyStopping)}
		self.is_stopping.store(true, Ordering::Relaxed);
		while !self.is_stopped.load(Ordering::Relaxed) { std::thread::park_timeout(std::time::Duration::new(0, 50)); }
		Ok(())
	}
}

impl Drop for Server {
	fn drop(&mut self) {
		self.stop_async().unwrap_or_else(|_| {}); // ignore error - can be stopped already
		// todo : no stable logging for windows?
		trace!(target: "ipc", "IPC Server : shutdown");
	}
}
<commit_msg>Use GenericIoHandler in windows IPC layer<commit_after>// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.

//! jsonrpc server over win named pipes
//!
//! ```no_run
//! extern crate jsonrpc_core;
//! extern crate jsonrpc_ipc_server;
//!
//! use std::sync::Arc;
//! use jsonrpc_core::*;
//! use jsonrpc_ipc_server::Server;
//!
//! struct SayHello;
//! impl SyncMethodCommand for SayHello {
//! 	fn execute(&self, _params: Params) -> Result<Value, Error> {
//! 		Ok(Value::String("hello".to_string()))
//! 	}
//! }
//!
//! fn main() {
//! 	let io = IoHandler::new();
//! 	io.add_method("say_hello", SayHello);
//! 	let server = Server::new("/tmp/json-ipc-test.ipc", &Arc::new(io)).unwrap();
//!     ::std::thread::spawn(move || server.run());
//! }
//! ```

//! Named pipes library

use miow::pipe::{NamedPipe, NamedPipeBuilder};
use std;
use std::io;
use std::io::{Read, Write};
use std::sync::atomic::*;
use std::sync::Arc;
use jsonrpc_core::GenericIoHandler;
use validator;

pub type Result<T> = std::result::Result<T, Error>;

const MAX_REQUEST_LEN: u32 = 65536;
const REQUEST_READ_BATCH: usize = 4096;

#[derive(Debug)]
pub enum Error {
	Io(std::io::Error),
	NotStarted,
	AlreadyStopping,
	NotStopped,
	IsStopping,
}

impl std::convert::From<std::io::Error> for Error {
	fn from(io_error: std::io::Error) -> Error {
		Error::Io(io_error)
	}
}

pub struct PipeHandler {
	waiting_pipe: NamedPipe,
	io_handler: Arc<GenericIoHandler>,
}

impl PipeHandler {
	/// start ipc rpc server (blocking)
	pub fn start(addr: &str, io_handler: &Arc<GenericIoHandler>) -> Result<PipeHandler> {
		Ok(PipeHandler {
			waiting_pipe: try!(
				NamedPipeBuilder::new(addr)
					.first(true)
					.accept_remote(true)
					.max_instances(255)
					.inbound(true)
					.outbound(true)
					.out_buffer_size(MAX_REQUEST_LEN)
					.in_buffer_size(MAX_REQUEST_LEN)
					.create()
			),
			io_handler: io_handler.clone(),
		})
	}

	fn handle_incoming(&mut self, addr: &str, stop: Arc<AtomicBool>) -> io::Result<()> {
		trace!(target: "ipc", "Waiting for client: [{}]", addr);
		try!(self.waiting_pipe.connect());
		trace!(target: "ipc", "Received connection to address [{}]", addr);
		if stop.load(Ordering::Relaxed) {
			trace!(target: "ipc", "Stopped listening sequence [{}]", addr);
			return Ok(())
		}

		let mut connected_pipe = std::mem::replace::<NamedPipe>(&mut self.waiting_pipe,
			try!(NamedPipeBuilder::new(addr)
				.first(false)
				.accept_remote(true)
				.inbound(true)
				.outbound(true)
				.out_buffer_size(MAX_REQUEST_LEN)
				.in_buffer_size(MAX_REQUEST_LEN)
				.create()));

		let thread_handler = self.io_handler.clone();
		std::thread::spawn(move || {
			let mut buf = vec![0u8; MAX_REQUEST_LEN as usize];
			let mut fin = REQUEST_READ_BATCH;
			loop {
				let start = fin - REQUEST_READ_BATCH;
				trace!(target: "ipc", "Reading {} - {} of the buffer", start, fin);
				match connected_pipe.read(&mut buf[start..fin]) {
					Ok(size) => {
						let (requests, last_index) = {
							let effective = &buf[0..start + size];
							fin = fin + size;
							trace!(target: "ipc", "Received rpc data: {} bytes", effective.len());

							validator::extract_requests(effective)
						};
						if requests.len() > 0 {
							let mut response_buf = Vec::new();
							for rpc_msg in requests  {
								trace!(target: "ipc", "Request: {}", rpc_msg);

								let response: Option<String> = thread_handler.handle_request_sync(&rpc_msg);

								if let Some(response_str) = response {
									trace!(target: "ipc", "Response: {}", &response_str);
									response_buf.extend(response_str.into_bytes());
								}
							}

							if let Err(write_err) = connected_pipe.write_all(&response_buf[..]).and_then(|_| connected_pipe.flush()) {
								trace!(target: "ipc", "Response write error: {:?}", write_err);
							}
							else {
								trace!(target: "ipc", "Sent rpc response: {} bytes", response_buf.len());
							}

							let leftover_len = start + size - (last_index + 1);
							if leftover_len > 0 {
								let leftover = buf[last_index + 1..start + size].to_vec();
								buf[0..leftover_len].copy_from_slice(&leftover[..]);
							}
							fin = leftover_len + REQUEST_READ_BATCH;
						}
						else { continue; }
					},
					Err(e) => {
						// closed connection
						trace!(target: "ipc", "Dropped connection {:?}", e);
						break;
					}
				}
			}
		});

		Ok(())
	}
}

pub struct Server {
	is_stopping: Arc<AtomicBool>,
	is_stopped: Arc<AtomicBool>,
	addr: String,
	io_handler: Arc<GenericIoHandler>,
}

impl Server {
	/// New server
	pub fn new(socket_addr: &str, io_handler: &Arc<GenericIoHandler>) -> Result<Server> {
		Ok(Server {
			io_handler: io_handler.clone(),
			is_stopping: Arc::new(AtomicBool::new(false)),
			is_stopped: Arc::new(AtomicBool::new(true)),
			addr: socket_addr.to_owned(),
		})
	}

	/// Run server (in this thread)
	pub fn run(&self) -> Result<()> {
		let mut pipe_handler = try!(PipeHandler::start(&self.addr, &self.io_handler));
		loop  {
			try!(pipe_handler.handle_incoming(&self.addr, Arc::new(AtomicBool::new(false))));
		}
	}

	/// Run server (in separate thread)
	pub fn run_async(&self) -> Result<()> {
		if self.is_stopping.load(Ordering::Relaxed) { return Err(Error::IsStopping) }
		if !self.is_stopped.load(Ordering::Relaxed) { return Err(Error::NotStopped) }

		trace!(target: "ipc", "Started named pipes server [{}]", self.addr);

		let thread_stopping = self.is_stopping.clone();
		let thread_stopped = self.is_stopped.clone();
		let thread_handler = self.io_handler.clone();
		let addr = self.addr.clone();
		std::thread::spawn(move || {
			let mut pipe_handler = PipeHandler::start(&addr, &thread_handler).unwrap();
			while !thread_stopping.load(Ordering::Relaxed) {
				trace!(target: "ipc", "Accepting pipe connection");
				if let Err(pipe_listener_error) = pipe_handler.handle_incoming(&addr, thread_stopping.clone()) {
					trace!(target: "ipc", "Pipe listening error: {:?}", pipe_listener_error);
				}
			}
			thread_stopped.store(true, Ordering::Relaxed);
		});

		self.is_stopped.store(false, Ordering::Relaxed);
		Ok(())
	}

	pub fn stop_async(&self) -> Result<()> {
		if self.is_stopped.load(Ordering::Relaxed) { return Err(Error::NotStarted) }
		if self.is_stopping.load(Ordering::Relaxed) { return Err(Error::AlreadyStopping)}
		self.is_stopping.store(true, Ordering::Relaxed);
		Ok(())
	}

	pub fn stop(&self) -> Result<()> {
		if self.is_stopped.load(Ordering::Relaxed) { return Err(Error::NotStarted) }
		if self.is_stopping.load(Ordering::Relaxed) { return Err(Error::AlreadyStopping)}
		self.is_stopping.store(true, Ordering::Relaxed);
		while !self.is_stopped.load(Ordering::Relaxed) { std::thread::park_timeout(std::time::Duration::new(0, 50)); }
		Ok(())
	}
}

impl Drop for Server {
	fn drop(&mut self) {
		self.stop_async().unwrap_or_else(|_| {}); // ignore error - can be stopped already
		// todo : no stable logging for windows?
		trace!(target: "ipc", "IPC Server : shutdown");
	}
}
<|endoftext|>