<commit_before>#![allow(non_upper_case_globals)]
use serde_json;

use rs_es::Client;

use iron::prelude::*;
use iron::{status, Handler, Headers};
use iron::mime::Mime;
use iron::typemap::Key;
use iron::headers;
use iron::middleware::AfterMiddleware;
use unicase::UniCase;

use persistent::Write;

use http_logger::Logger as HTTPLogger;

use router::Router;

use params::*;

use oath::*;

use config::Auth as AuthConfig;
use config::Config;

use resource::Resource;
use logger::start_logging;

use std::collections::HashMap;
use std::io::Read;
use std::marker::PhantomData;

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

impl Key for SharedClient { type Value = Client; }

macro_rules! try_or_422 {
  ($expr:expr) => (match $expr {
    Ok(val)  => val,
    Err(err) => {
      let error_message = err.to_string();
      error!("{}", error_message);

      let mut error = HashMap::new();
      error.insert("error", error_message);

      let content_type = "application/json".parse::<Mime>().unwrap();
      return Ok(Response::with(
        (content_type, status::UnprocessableEntity, serde_json::to_string(&error).unwrap())
      ))
    }
  })
}

macro_rules! unauthorized {
  () => ({
    return Ok(Response::with(
      (status::Unauthorized)
    ))
  })
}

macro_rules! authorization {
  ($trait_name:ident, $mode:ident) => {
    trait $trait_name {
      fn is_authorized(&self, auth_config: &AuthConfig, headers: &Headers, token_lifetime: u64) -> bool {
        if auth_config.enabled == false {
          return true;
        }

        match headers.get_raw("Authorization") {
          Some(header) => match String::from_utf8(header[0].to_owned()) {
            Ok(header) => {
              match header.split("token ").collect::<Vec<&str>>().last() {
                Some(token) => {
                  match token.parse::<u64>() {
                    Ok(token) => totp_raw(auth_config.$mode.as_bytes(), 6, 0, token_lifetime as u64) == token,
                    Err(_)    => false,
                  }
                },
                None => false
              }
            },
            Err(_) => false
          },
          None => false
        }
      }
    }
  }
}

authorization!(ReadableEndpoint, read);
authorization!(WritableEndpoint, write);

pub struct Server<R: Resource> {
  config:   Config,
  endpoint: String,
  resource: PhantomData<R>
}

pub struct SearchableHandler<R> {
  config:   Config,
  resource: PhantomData<R>
}

impl<R: Resource> SearchableHandler<R> {
  fn new(config: Config) -> Self {
    SearchableHandler::<R> {
      resource: PhantomData,
      config:   config
    }
  }
}

impl<R: Resource> ReadableEndpoint for SearchableHandler<R> {}

impl<R: Resource> Handler for SearchableHandler<R> {
  fn handle(&self, req: &mut Request) -> IronResult<Response> {
    let ref lifetimes = self.config.tokens.lifetime;
    if !self.is_authorized(&self.config.auth, &req.headers, lifetimes.read) {
      unauthorized!();
    }

    let client = req.get::<Write<SharedClient>>().unwrap();
    let params = try_or_422!(req.get_ref::<Params>());

    let response = R::search(&mut client.lock().unwrap(), &*self.config.es.index, params);

    let content_type = "application/json".parse::<Mime>().unwrap();
    Ok(Response::with(
      (content_type, status::Ok, try_or_422!(serde_json::to_string(&response)))
    ))
  }
}

pub struct IndexableHandler<R> {
  config:   Config,
  resource: PhantomData<R>
}

impl<R: Resource> IndexableHandler<R> {
  fn new(config: Config) -> Self {
    IndexableHandler::<R> {
      resource: PhantomData,
      config:   config
    }
  }
}

impl<R: Resource> WritableEndpoint for IndexableHandler<R> {}

impl<R: Resource> Handler for IndexableHandler<R> {
  fn handle(&self, req: &mut Request) -> IronResult<Response> {
    let ref lifetimes = self.config.tokens.lifetime;
    if !self.is_authorized(&self.config.auth, &req.headers, lifetimes.write) {
      unauthorized!();
    }

    let mut payload = String::new();
    req.body.read_to_string(&mut payload).unwrap();

    let resources: Vec<R> = try_or_422!(serde_json::from_str(&payload));
    let client = req.get::<Write<SharedClient>>().unwrap();
    try_or_422!(R::index(&mut client.lock().unwrap(), &*self.config.es.index, resources));

    Ok(Response::with(status::Created))
  }
}

pub struct DeletableHandler<R> {
  config:   Config,
  resource: PhantomData<R>
}

impl<R: Resource> DeletableHandler<R> {
  fn new(config: Config) -> Self {
    DeletableHandler::<R> {
      resource: PhantomData,
      config:   config
    }
  }
}

impl<R: Resource> WritableEndpoint for DeletableHandler<R> {}

impl<R: Resource> Handler for DeletableHandler<R> {
  fn handle(&self, req: &mut Request) -> IronResult<Response> {
    let ref lifetimes = self.config.tokens.lifetime;
    if !self.is_authorized(&self.config.auth, &req.headers, lifetimes.write) {
      unauthorized!();
    }

    let     client = req.get::<Write<SharedClient>>().unwrap();
    let mut client = client.lock().unwrap();

    let ref id = try_or_422!(req.extensions.get::<Router>().unwrap()
                                                           .find("id")
                                                           .ok_or("DELETE#:id not found"));

    match R::delete(&mut client, id, &*self.config.es.index) {
      Ok(_)  => Ok(Response::with(status::NoContent)),
      Err(e) => {
        let error_message = e.to_string();
        error!("{}", error_message);

        let content_type = "application/json".parse::<Mime>().unwrap();
        Ok(Response::with(
          (content_type, status::UnprocessableEntity, error_message)
        ))
      }
    }
  }
}

pub struct ResettableHandler<R> {
  config:   Config,
  resource: PhantomData<R>
}

impl<R: Resource> ResettableHandler<R> {
  fn new(config: Config) -> Self {
    ResettableHandler::<R> {
      resource: PhantomData,
      config:   config
    }
  }
}

impl<R: Resource> WritableEndpoint for ResettableHandler<R> {}

impl<R: Resource> Handler for ResettableHandler<R> {
  fn handle(&self, req: &mut Request) -> IronResult<Response> {
    let ref lifetimes = self.config.tokens.lifetime;
    if !self.is_authorized(&self.config.auth, &req.headers, lifetimes.write) {
      unauthorized!();
    }

    let     client = req.get::<Write<SharedClient>>().unwrap();
    let mut client = client.lock().unwrap();
    match R::reset_index(&mut client, &*self.config.es.index) {
      Ok(_)  => Ok(Response::with(status::NoContent)),
      Err(e) => {
        let error_message = e.to_string();
        error!("{}", error_message);

        let content_type = "application/json".parse::<Mime>().unwrap();
        Ok(Response::with(
          (content_type, status::UnprocessableEntity, error_message)
        ))
      }
    }
  }
}

struct CorsMiddleware;

impl AfterMiddleware for CorsMiddleware {
  fn after(&self, _: &mut Request, mut res: Response) -> IronResult<Response> {
    res.headers.set(headers::AccessControlAllowOrigin::Any);
    res.headers.set(headers::AccessControlAllowHeaders(vec![
      UniCase("x-requested-withcontent-type".to_owned()),
      UniCase("content-type".to_owned()),
      UniCase("accept".to_owned()),
      UniCase("authorization".to_owned())
    ]));
    Ok(res)
  }
}

impl<R: Resource> Server<R> {
  pub fn new(config: Config, endpoint: &str) -> Self {
    Server {
      config:   config,
      endpoint: endpoint.to_owned(),
      resource: PhantomData
    }
  }

  pub fn start(&self) {
    start_logging(&self.config).unwrap();

    let host = format!("{}:{}", self.config.http.host, self.config.http.port);

    println!("Searchspot v{}\n{}\n", env!("CARGO_PKG_VERSION"), self.config);

    let mut router = Router::new();
    router.get(&self.endpoint,    SearchableHandler::<R>::new(self.config.to_owned()), "search");
    router.post(&self.endpoint,   IndexableHandler::<R>::new(self.config.to_owned()),  "index");
    router.delete(&self.endpoint, ResettableHandler::<R>::new(self.config.to_owned()), "reset");

    let deletable_endpoint = format!("{}/:id", self.endpoint);
    router.delete(deletable_endpoint, DeletableHandler::<R>::new(self.config.to_owned()), "delete");

    let client = Client::new(&*self.config.to_owned().es.url).unwrap();

    let mut chain = Chain::new(router);
    chain.link(Write::<SharedClient>::both(client));
    chain.link(HTTPLogger::new(None));
    chain.link_after(CorsMiddleware);
    Iron::new(chain).http(&*host).unwrap();
  }
}

#[cfg(test)]
mod tests {
  use resource::Resource;

  use params::*;

  use rs_es::Client;
  use rs_es::operations::bulk::{BulkResult, Action};
  use rs_es::operations::delete::DeleteResult;
  use rs_es::operations::mapping::{MappingOperation, MappingResult};
  use rs_es::error::EsError;

  #[derive(Serialize, Deserialize, Clone, Debug)]
  pub struct TestResource {
    pub id: u32
  }

  const ES_TYPE: &'static str = "test_resource";

  impl Resource for TestResource {
    type Results = Vec<u32>;

    fn search(_: &mut Client, _: &str, _: &Map) -> Self::Results {
      vec![]
    }

    fn index(mut es: &mut Client, index: &str, resources: Vec<Self>) -> Result<BulkResult, EsError> {
      es.bulk(&resources.into_iter()
                        .map(|r| {
                            let id = r.id.to_string();
                            Action::index(r).with_id(id)
                        })
                        .collect::<Vec<Action<TestResource>>>())
        .with_index(index)
        .with_doc_type(ES_TYPE)
        .send()
    }

    fn delete(mut es: &mut Client, id: &str, index: &str) -> Result<DeleteResult, EsError> {
      es.delete(index, ES_TYPE, id)
        .send()
    }

    fn reset_index(mut es: &mut Client, index: &str) -> Result<MappingResult, EsError> {
      MappingOperation::new(&mut es, index).send()
    }
  }
}
<commit_msg>server: specify AccessControlAllowMethods<commit_after>#![allow(non_upper_case_globals)]
use serde_json;

use rs_es::Client;

use iron::prelude::*;
use iron::{status, Handler, Headers};
use iron::mime::Mime;
use iron::typemap::Key;
use iron::headers;
use iron::middleware::AfterMiddleware;
use iron::method::Method::*;
use unicase::UniCase;

use persistent::Write;

use http_logger::Logger as HTTPLogger;

use router::Router;

use params::*;

use oath::*;

use config::Auth as AuthConfig;
use config::Config;

use resource::Resource;
use logger::start_logging;

use std::collections::HashMap;
use std::io::Read;
use std::marker::PhantomData;

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

impl Key for SharedClient { type Value = Client; }

macro_rules! try_or_422 {
  ($expr:expr) => (match $expr {
    Ok(val)  => val,
    Err(err) => {
      let error_message = err.to_string();
      error!("{}", error_message);

      let mut error = HashMap::new();
      error.insert("error", error_message);

      let content_type = "application/json".parse::<Mime>().unwrap();
      return Ok(Response::with(
        (content_type, status::UnprocessableEntity, serde_json::to_string(&error).unwrap())
      ))
    }
  })
}

macro_rules! unauthorized {
  () => ({
    return Ok(Response::with(
      (status::Unauthorized)
    ))
  })
}

macro_rules! authorization {
  ($trait_name:ident, $mode:ident) => {
    trait $trait_name {
      fn is_authorized(&self, auth_config: &AuthConfig, headers: &Headers, token_lifetime: u64) -> bool {
        if auth_config.enabled == false {
          return true;
        }

        match headers.get_raw("Authorization") {
          Some(header) => match String::from_utf8(header[0].to_owned()) {
            Ok(header) => {
              match header.split("token ").collect::<Vec<&str>>().last() {
                Some(token) => {
                  match token.parse::<u64>() {
                    Ok(token) => totp_raw(auth_config.$mode.as_bytes(), 6, 0, token_lifetime as u64) == token,
                    Err(_)    => false,
                  }
                },
                None => false
              }
            },
            Err(_) => false
          },
          None => false
        }
      }
    }
  }
}

authorization!(ReadableEndpoint, read);
authorization!(WritableEndpoint, write);

pub struct Server<R: Resource> {
  config:   Config,
  endpoint: String,
  resource: PhantomData<R>
}

pub struct SearchableHandler<R> {
  config:   Config,
  resource: PhantomData<R>
}

impl<R: Resource> SearchableHandler<R> {
  fn new(config: Config) -> Self {
    SearchableHandler::<R> {
      resource: PhantomData,
      config:   config
    }
  }
}

impl<R: Resource> ReadableEndpoint for SearchableHandler<R> {}

impl<R: Resource> Handler for SearchableHandler<R> {
  fn handle(&self, req: &mut Request) -> IronResult<Response> {
    let ref lifetimes = self.config.tokens.lifetime;
    if !self.is_authorized(&self.config.auth, &req.headers, lifetimes.read) {
      unauthorized!();
    }

    let client = req.get::<Write<SharedClient>>().unwrap();
    let params = try_or_422!(req.get_ref::<Params>());

    let response = R::search(&mut client.lock().unwrap(), &*self.config.es.index, params);

    let content_type = "application/json".parse::<Mime>().unwrap();
    Ok(Response::with(
      (content_type, status::Ok, try_or_422!(serde_json::to_string(&response)))
    ))
  }
}

pub struct IndexableHandler<R> {
  config:   Config,
  resource: PhantomData<R>
}

impl<R: Resource> IndexableHandler<R> {
  fn new(config: Config) -> Self {
    IndexableHandler::<R> {
      resource: PhantomData,
      config:   config
    }
  }
}

impl<R: Resource> WritableEndpoint for IndexableHandler<R> {}

impl<R: Resource> Handler for IndexableHandler<R> {
  fn handle(&self, req: &mut Request) -> IronResult<Response> {
    let ref lifetimes = self.config.tokens.lifetime;
    if !self.is_authorized(&self.config.auth, &req.headers, lifetimes.write) {
      unauthorized!();
    }

    let mut payload = String::new();
    req.body.read_to_string(&mut payload).unwrap();

    let resources: Vec<R> = try_or_422!(serde_json::from_str(&payload));
    let client = req.get::<Write<SharedClient>>().unwrap();
    try_or_422!(R::index(&mut client.lock().unwrap(), &*self.config.es.index, resources));

    Ok(Response::with(status::Created))
  }
}

pub struct DeletableHandler<R> {
  config:   Config,
  resource: PhantomData<R>
}

impl<R: Resource> DeletableHandler<R> {
  fn new(config: Config) -> Self {
    DeletableHandler::<R> {
      resource: PhantomData,
      config:   config
    }
  }
}

impl<R: Resource> WritableEndpoint for DeletableHandler<R> {}

impl<R: Resource> Handler for DeletableHandler<R> {
  fn handle(&self, req: &mut Request) -> IronResult<Response> {
    let ref lifetimes = self.config.tokens.lifetime;
    if !self.is_authorized(&self.config.auth, &req.headers, lifetimes.write) {
      unauthorized!();
    }

    let     client = req.get::<Write<SharedClient>>().unwrap();
    let mut client = client.lock().unwrap();

    let ref id = try_or_422!(req.extensions.get::<Router>().unwrap()
                                                           .find("id")
                                                           .ok_or("DELETE#:id not found"));

    match R::delete(&mut client, id, &*self.config.es.index) {
      Ok(_)  => Ok(Response::with(status::NoContent)),
      Err(e) => {
        let error_message = e.to_string();
        error!("{}", error_message);

        let content_type = "application/json".parse::<Mime>().unwrap();
        Ok(Response::with(
          (content_type, status::UnprocessableEntity, error_message)
        ))
      }
    }
  }
}

pub struct ResettableHandler<R> {
  config:   Config,
  resource: PhantomData<R>
}

impl<R: Resource> ResettableHandler<R> {
  fn new(config: Config) -> Self {
    ResettableHandler::<R> {
      resource: PhantomData,
      config:   config
    }
  }
}

impl<R: Resource> WritableEndpoint for ResettableHandler<R> {}

impl<R: Resource> Handler for ResettableHandler<R> {
  fn handle(&self, req: &mut Request) -> IronResult<Response> {
    let ref lifetimes = self.config.tokens.lifetime;
    if !self.is_authorized(&self.config.auth, &req.headers, lifetimes.write) {
      unauthorized!();
    }

    let     client = req.get::<Write<SharedClient>>().unwrap();
    let mut client = client.lock().unwrap();
    match R::reset_index(&mut client, &*self.config.es.index) {
      Ok(_)  => Ok(Response::with(status::NoContent)),
      Err(e) => {
        let error_message = e.to_string();
        error!("{}", error_message);

        let content_type = "application/json".parse::<Mime>().unwrap();
        Ok(Response::with(
          (content_type, status::UnprocessableEntity, error_message)
        ))
      }
    }
  }
}

struct CorsMiddleware;

impl AfterMiddleware for CorsMiddleware {
  fn after(&self, _: &mut Request, mut res: Response) -> IronResult<Response> {
    res.headers.set(headers::AccessControlAllowOrigin::Any);
    res.headers.set(headers::AccessControlAllowHeaders(vec![
      UniCase("x-requested-withcontent-type".to_owned()),
      UniCase("content-type".to_owned()),
      UniCase("accept".to_owned()),
      UniCase("authorization".to_owned())
    ]));
    res.headers.set(headers::AccessControlAllowMethods(vec![Get, Post, Put, Delete]));
    Ok(res)
  }
}

impl<R: Resource> Server<R> {
  pub fn new(config: Config, endpoint: &str) -> Self {
    Server {
      config:   config,
      endpoint: endpoint.to_owned(),
      resource: PhantomData
    }
  }

  pub fn start(&self) {
    start_logging(&self.config).unwrap();

    let host = format!("{}:{}", self.config.http.host, self.config.http.port);

    println!("Searchspot v{}\n{}\n", env!("CARGO_PKG_VERSION"), self.config);

    let mut router = Router::new();
    router.get(&self.endpoint,    SearchableHandler::<R>::new(self.config.to_owned()), "search");
    router.post(&self.endpoint,   IndexableHandler::<R>::new(self.config.to_owned()),  "index");
    router.delete(&self.endpoint, ResettableHandler::<R>::new(self.config.to_owned()), "reset");

    let deletable_endpoint = format!("{}/:id", self.endpoint);
    router.delete(deletable_endpoint, DeletableHandler::<R>::new(self.config.to_owned()), "delete");

    let client = Client::new(&*self.config.to_owned().es.url).unwrap();

    let mut chain = Chain::new(router);
    chain.link(Write::<SharedClient>::both(client));
    chain.link(HTTPLogger::new(None));
    chain.link_after(CorsMiddleware);
    Iron::new(chain).http(&*host).unwrap();
  }
}

#[cfg(test)]
mod tests {
  use resource::Resource;

  use params::*;

  use rs_es::Client;
  use rs_es::operations::bulk::{BulkResult, Action};
  use rs_es::operations::delete::DeleteResult;
  use rs_es::operations::mapping::{MappingOperation, MappingResult};
  use rs_es::error::EsError;

  #[derive(Serialize, Deserialize, Clone, Debug)]
  pub struct TestResource {
    pub id: u32
  }

  const ES_TYPE: &'static str = "test_resource";

  impl Resource for TestResource {
    type Results = Vec<u32>;

    fn search(_: &mut Client, _: &str, _: &Map) -> Self::Results {
      vec![]
    }

    fn index(mut es: &mut Client, index: &str, resources: Vec<Self>) -> Result<BulkResult, EsError> {
      es.bulk(&resources.into_iter()
                        .map(|r| {
                            let id = r.id.to_string();
                            Action::index(r).with_id(id)
                        })
                        .collect::<Vec<Action<TestResource>>>())
        .with_index(index)
        .with_doc_type(ES_TYPE)
        .send()
    }

    fn delete(mut es: &mut Client, id: &str, index: &str) -> Result<DeleteResult, EsError> {
      es.delete(index, ES_TYPE, id)
        .send()
    }

    fn reset_index(mut es: &mut Client, index: &str) -> Result<MappingResult, EsError> {
      MappingOperation::new(&mut es, index).send()
    }
  }
}
<|endoftext|>


<commit_before>mod arena;
mod messages;
mod primitives;

use actix::{Actor, AsyncContext, Context, Handler};
use anyhow::{anyhow, Context as ResultContext, Error};
use log::{error, info};
use std::collections::HashMap;
use std::time::Duration;

pub use arena::{Arena, ArenaInput, ArenaOverview, ArenaUpdate};
pub use messages::{MessageIn, MessageOut};
pub use primitives::*;

use crate::get_error_chain;
use messages::MessageInPayload;

const UPDATE_RATE_MILLISECONDS: u64 = 25; // 1000 / 25 = 40 updates per second

#[derive(Debug, Default)]
pub struct Server {
    message_queue: Vec<MessageIn>,
    clients: HashMap<ClientId, Client>,
    arenas: HashMap<ArenaId, Arena>,
}

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

    pub fn new_arena(&mut self) -> ArenaId {
        let arena = Arena::default();
        let id = arena.id;

        self.arenas.insert(id, arena);

        id
    }

    pub fn client_input(&mut self, client_id: ClientId, input: ArenaInput) -> Result<(), Error> {
        let client = self
            .clients
            .get(&client_id)
            .with_context(|| anyhow!("Client {} not found", client_id))?;

        let arena_id = client
            .arena
            .with_context(|| anyhow!("Client {} not in an arena"))?;

        let arena = self
            .arenas
            .get_mut(&arena_id)
            .with_context(|| anyhow!("Arena {} not found", arena_id))?;

        let player_id = client
            .player
            .with_context(|| anyhow!("Client {} has no player", client_id))?;

        arena.process_input(player_id, input);

        Ok(())
    }

    pub fn client_part_arena(&mut self, client_id: ClientId) -> Result<(), Error> {
        let client = self
            .clients
            .get_mut(&client_id)
            .with_context(|| anyhow!("Client {} not found", client_id))?;

        client.updates_sent_so_far = 0;

        let arena_id = client
            .arena
            .with_context(|| anyhow!("Client {} not in an arena"))?;

        let arena = self
            .arenas
            .get_mut(&arena_id)
            .with_context(|| anyhow!("Arena {} not found", arena_id))?;

        let player_id = client
            .player
            .with_context(|| anyhow!("Client {} has no player", client_id))?;

        arena.remove_player(player_id);

        // TODO: Remove empty arenas

        Ok(())
    }
}

impl Server {
    pub fn handle_message(
        &mut self,
        client_id: ClientId,
        payload: MessageInPayload,
    ) -> Result<(), Error> {
        match payload {
            MessageInPayload::Connect(ip_address, address) => {
                info!("Client connected: {}", client_id);
                self.clients.insert(
                    client_id,
                    Client {
                        id: client_id,
                        ip_address,
                        address,
                        player: None,
                        arena: None,
                        updates_sent_so_far: 0,
                    },
                );
            }
            MessageInPayload::Disconnect => {
                info!("Client disconnected: {}", client_id);

                self.client_part_arena(client_id)
                    .with_context(|| anyhow!("Failed to remove client from their arena"))?;

                self.clients
                    .remove(&client_id)
                    .ok_or_else(|| anyhow!("Failed to remove client {}", client_id))?;
            }

            MessageInPayload::GetArenaList => {
                let arena_list: Vec<ArenaOverview> =
                    self.arenas.values().map(ArenaOverview::from).collect();

                let client = self
                    .clients
                    .get_mut(&client_id)
                    .ok_or_else(|| anyhow!("Client {} not found", client_id))?;

                client
                    .address
                    .try_send(MessageOut::ArenaList(arena_list))
                    .with_context(|| anyhow!("Failed to send ArenaList to client {}", client_id))?;
            }
            MessageInPayload::Join { player, arena_id } => {
                self.client_part_arena(client_id)
                    .with_context(|| anyhow!("Failed to remove client from their arena"))?;

                let arena_id = match arena_id {
                    Some(arena_id) => {
                        if self.arenas.contains_key(&arena_id) {
                            arena_id
                        } else {
                            self.new_arena()
                        }
                    }
                    None => self.new_arena(),
                };

                let arena = self
                    .arenas
                    .get_mut(&arena_id)
                    .ok_or_else(|| anyhow!("Arena {} not found", arena_id))?;

                if arena.players.len() >= arena.max_players {
                    return Err(anyhow!("Arena {} is full", arena_id));
                }

                let player_id = player.id;

                let client = self
                    .clients
                    .get_mut(&client_id)
                    .ok_or_else(|| anyhow!("Client {} not found", client_id))?;

                arena.add_player(player);
                client.player = Some(player_id);
                client.arena = Some(arena_id);

                client
                    .address
                    .try_send(MessageOut::ArenaJoined(arena.id))
                    .with_context(|| {
                        anyhow!("Failed to send ArenaJoined to client {}", client_id)
                    })?;

                info!("Player {} joined arena {}", player_id, arena_id);
            }

            MessageInPayload::Start => {
                self.client_input(client_id, ArenaInput::Start)?;
                info!("Client {} started game", client_id);
            }
            MessageInPayload::Turn(direction) => {
                self.client_input(client_id, ArenaInput::Turn(direction))?;
            }
        }
        Ok(())
    }
}

impl Server {
    pub fn process_messages(&mut self) {
        // take ownership of queued messages
        let mut process_messages_queue = Vec::with_capacity(self.message_queue.len());

        // move all message_queue messages into process_messages_queue
        process_messages_queue.append(&mut self.message_queue);

        // process each message
        process_messages_queue.drain(..).for_each(|message| {
            self.handle_message(message.client_id, message.payload)
                .unwrap_or_else(|error| {
                    error!("Failed processing MessageIn: {}", get_error_chain(error))
                });
        });
    }

    pub fn update(&mut self) {
        self.arenas.values_mut().for_each(|arena| arena.update());
    }

    pub fn send_updates(&mut self) {
        let clients = &mut self.clients;
        let arenas = &self.arenas;

        clients.values_mut().for_each(|client| {
            let arena = match client.arena {
                Some(arena) => arena,
                None => return,
            };

            let arena = match arenas.get(&arena) {
                Some(arena) => arena,
                None => return,
            };

            if client.updates_sent_so_far == 0 {
                unwrap_or_return!(
                    client
                        .address
                        .try_send(MessageOut::ArenaState(Box::from(arena.clone()))),
                    |error| error!("Failed to send ArenaState to client: {}", error)
                );
                client.updates_sent_so_far = arena.updates.len();
                return;
            }

            if client.updates_sent_so_far < arena.updates.len() {
                client
                    .address
                    .try_send(MessageOut::ArenaStatePatch(
                        arena
                            .updates
                            .iter()
                            .skip(client.updates_sent_so_far)
                            .cloned()
                            .collect(),
                    ))
                    .unwrap_or_else(|error| {
                        error!("Failed to send ArenaStatePatch to client: {}", error);
                    });
                client.updates_sent_so_far = arena.updates.len();
                return;
            }
        })
    }
}

impl Actor for Server {
    type Context = Context<Self>;

    fn started(&mut self, context: &mut Context<Self>) {
        context.run_interval(
            Duration::from_millis(UPDATE_RATE_MILLISECONDS),
            |server, _context| {
                server.process_messages();
                server.update();
                server.send_updates();
            },
        );
    }
}

impl Handler<MessageIn> for Server {
    type Result = ();

    fn handle(&mut self, message: MessageIn, _context: &mut Context<Self>) {
        self.message_queue.push(message);
    }
}
<commit_msg>fixed server not forgetting disconnected clients<commit_after>mod arena;
mod messages;
mod primitives;

use actix::{Actor, AsyncContext, Context, Handler};
use anyhow::{anyhow, Context as ResultContext, Error};
use log::{error, info, warn};
use std::collections::HashMap;
use std::time::Duration;

pub use arena::{Arena, ArenaInput, ArenaOverview, ArenaUpdate};
pub use messages::{MessageIn, MessageOut};
pub use primitives::*;

use crate::get_error_chain;
use messages::MessageInPayload;

const UPDATE_RATE_MILLISECONDS: u64 = 25; // 1000 / 25 = 40 updates per second

#[derive(Debug, Default)]
pub struct Server {
    message_queue: Vec<MessageIn>,
    clients: HashMap<ClientId, Client>,
    arenas: HashMap<ArenaId, Arena>,
}

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

    pub fn new_arena(&mut self) -> ArenaId {
        let arena = Arena::default();
        let id = arena.id;

        self.arenas.insert(id, arena);

        id
    }

    pub fn client_input(&mut self, client_id: ClientId, input: ArenaInput) -> Result<(), Error> {
        let client = self
            .clients
            .get(&client_id)
            .with_context(|| anyhow!("Client {} not found", client_id))?;

        let arena_id = client
            .arena
            .with_context(|| anyhow!("Client {} not in an arena"))?;

        let arena = self
            .arenas
            .get_mut(&arena_id)
            .with_context(|| anyhow!("Arena {} not found", arena_id))?;

        let player_id = client
            .player
            .with_context(|| anyhow!("Client {} has no player", client_id))?;

        arena.process_input(player_id, input);

        Ok(())
    }

    pub fn client_part_arena(&mut self, client_id: ClientId) -> Result<(), Error> {
        let client = self
            .clients
            .get_mut(&client_id)
            .with_context(|| anyhow!("Client {} not found", client_id))?;

        client.updates_sent_so_far = 0;

        let arena_id = client
            .arena
            .with_context(|| anyhow!("Client {} not in an arena"))?;

        let arena = self
            .arenas
            .get_mut(&arena_id)
            .with_context(|| anyhow!("Arena {} not found", arena_id))?;

        let player_id = client
            .player
            .with_context(|| anyhow!("Client {} has no player", client_id))?;

        arena.remove_player(player_id);

        // TODO: Remove empty arenas

        Ok(())
    }
}

impl Server {
    pub fn handle_message(
        &mut self,
        client_id: ClientId,
        payload: MessageInPayload,
    ) -> Result<(), Error> {
        match payload {
            MessageInPayload::Connect(ip_address, address) => {
                info!("Client connected: {}", client_id);
                self.clients.insert(
                    client_id,
                    Client {
                        id: client_id,
                        ip_address,
                        address,
                        player: None,
                        arena: None,
                        updates_sent_so_far: 0,
                    },
                );
            }
            MessageInPayload::Disconnect => {
                info!("Client disconnected: {}", client_id);

                self.client_part_arena(client_id).unwrap_or_else(|error| {
                    warn!("Failed to remove client from their arena: {}", error)
                });

                self.clients
                    .remove(&client_id)
                    .ok_or_else(|| anyhow!("Failed to remove client {}", client_id))?;
            }

            MessageInPayload::GetArenaList => {
                let arena_list: Vec<ArenaOverview> =
                    self.arenas.values().map(ArenaOverview::from).collect();

                let client = self
                    .clients
                    .get_mut(&client_id)
                    .ok_or_else(|| anyhow!("Client {} not found", client_id))?;

                client
                    .address
                    .try_send(MessageOut::ArenaList(arena_list))
                    .with_context(|| anyhow!("Failed to send ArenaList to client {}", client_id))?;
            }
            MessageInPayload::Join { player, arena_id } => {
                self.client_part_arena(client_id)
                    .with_context(|| anyhow!("Failed to remove client from their arena"))?;

                let arena_id = match arena_id {
                    Some(arena_id) => {
                        if self.arenas.contains_key(&arena_id) {
                            arena_id
                        } else {
                            self.new_arena()
                        }
                    }
                    None => self.new_arena(),
                };

                let arena = self
                    .arenas
                    .get_mut(&arena_id)
                    .ok_or_else(|| anyhow!("Arena {} not found", arena_id))?;

                if arena.players.len() >= arena.max_players {
                    return Err(anyhow!("Arena {} is full", arena_id));
                }

                let player_id = player.id;

                let client = self
                    .clients
                    .get_mut(&client_id)
                    .ok_or_else(|| anyhow!("Client {} not found", client_id))?;

                arena.add_player(player);
                client.player = Some(player_id);
                client.arena = Some(arena_id);

                client
                    .address
                    .try_send(MessageOut::ArenaJoined(arena.id))
                    .with_context(|| {
                        anyhow!("Failed to send ArenaJoined to client {}", client_id)
                    })?;

                info!("Player {} joined arena {}", player_id, arena_id);
            }

            MessageInPayload::Start => {
                self.client_input(client_id, ArenaInput::Start)?;
                info!("Client {} started game", client_id);
            }
            MessageInPayload::Turn(direction) => {
                self.client_input(client_id, ArenaInput::Turn(direction))?;
            }
        }
        Ok(())
    }
}

impl Server {
    pub fn process_messages(&mut self) {
        // take ownership of queued messages
        let mut process_messages_queue = Vec::with_capacity(self.message_queue.len());

        // move all message_queue messages into process_messages_queue
        process_messages_queue.append(&mut self.message_queue);

        // process each message
        process_messages_queue.drain(..).for_each(|message| {
            self.handle_message(message.client_id, message.payload)
                .unwrap_or_else(|error| {
                    error!("Failed processing MessageIn: {}", get_error_chain(error))
                });
        });
    }

    pub fn update(&mut self) {
        self.arenas.values_mut().for_each(|arena| arena.update());
    }

    pub fn send_updates(&mut self) {
        let clients = &mut self.clients;
        let arenas = &self.arenas;

        clients.values_mut().for_each(|client| {
            let arena = match client.arena {
                Some(arena) => arena,
                None => return,
            };

            let arena = match arenas.get(&arena) {
                Some(arena) => arena,
                None => return,
            };

            if client.updates_sent_so_far == 0 {
                unwrap_or_return!(
                    client
                        .address
                        .try_send(MessageOut::ArenaState(Box::from(arena.clone()))),
                    |error| error!("Failed to send ArenaState to client: {}", error)
                );
                client.updates_sent_so_far = arena.updates.len();
                return;
            }

            if client.updates_sent_so_far < arena.updates.len() {
                client
                    .address
                    .try_send(MessageOut::ArenaStatePatch(
                        arena
                            .updates
                            .iter()
                            .skip(client.updates_sent_so_far)
                            .cloned()
                            .collect(),
                    ))
                    .unwrap_or_else(|error| {
                        error!("Failed to send ArenaStatePatch to client: {}", error);
                    });
                client.updates_sent_so_far = arena.updates.len();
                return;
            }
        })
    }
}

impl Actor for Server {
    type Context = Context<Self>;

    fn started(&mut self, context: &mut Context<Self>) {
        context.run_interval(
            Duration::from_millis(UPDATE_RATE_MILLISECONDS),
            |server, _context| {
                server.process_messages();
                server.update();
                server.send_updates();
            },
        );
    }
}

impl Handler<MessageIn> for Server {
    type Result = ();

    fn handle(&mut self, message: MessageIn, _context: &mut Context<Self>) {
        self.message_queue.push(message);
    }
}
<|endoftext|>


<commit_before>use gl;
use gl::types::*;
use gl_context::GLContext;
use std::collections::HashMap;
use std::ptr;
use std::str;

pub struct ProgramHandle<'a> {
  pub gl_id: GLuint,
}

impl<'a> ProgramHandle<'a> {
  pub fn new<'b: 'a>(_gl: &'b GLContext) -> ProgramHandle<'a> {
    let gl_id = unsafe {
      gl::CreateProgram()
    };

    ProgramHandle {
      gl_id: gl_id,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for ProgramHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteProgram(self.gl_id);
    }
  }
}

pub struct ShaderHandle<'a> {
  pub gl_id: GLuint,
}

impl<'a> ShaderHandle<'a> {
  pub fn compile_from<'b: 'a>(
    _gl: &'b GLContext,
    shader_source: String,
    typ: GLenum
  ) -> ShaderHandle<'a> {
    let gl_id = unsafe {
      gl::CreateShader(typ)
    };
    // Attempt to compile the shader
    shader_source.with_c_str(|ptr| unsafe { gl::ShaderSource(gl_id, 1, &ptr, ptr::null()) });
    unsafe {
      gl::CompileShader(gl_id);
    }

    // Get the compile status
    let mut status = gl::FALSE as GLint;
    unsafe {
      gl::GetShaderiv(gl_id, gl::COMPILE_STATUS, &mut status);
    }

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len = 0;
      unsafe {
        gl::GetShaderiv(gl_id, gl::INFO_LOG_LENGTH, &mut len);
      }
      let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
      unsafe {
        gl::GetShaderInfoLog(gl_id, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
      }
      panic!("error compiling 0x{:x} shader: {}", typ, str::from_utf8(buf.as_slice()).expect("ShaderInfoLog not valid utf8"));
    }

    ShaderHandle {
      gl_id: gl_id,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for ShaderHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteShader(self.gl_id);
    }
  }
}

pub struct Shader<'a> {
  pub handle: ProgramHandle<'a>,
  pub components: Vec<ShaderHandle<'a>>,
  pub uniforms: HashMap<String, GLint>,
}

impl<'a> Shader<'a> {
  pub fn new<'b: 'a, T: Iterator<(String, GLenum)>>(
    gl: &'b GLContext,
    shader_components: T,
  ) -> Shader<'a> {
    let mut shader_components = shader_components;
    let handle = ProgramHandle::new(gl);

    let mut components = Vec::new();
    for (content, component) in shader_components {
      let s = ShaderHandle::compile_from(gl, content, component);
      unsafe { gl::AttachShader(handle.gl_id, s.gl_id) };
      components.push(s);
    }

    unsafe {
      gl::LinkProgram(handle.gl_id);
    }

    // Get the link status
    let mut status = gl::FALSE as GLint;
    unsafe {
      gl::GetProgramiv(handle.gl_id, gl::LINK_STATUS, &mut status);
    }

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len: GLint = 0;
      unsafe {
        gl::GetProgramiv(handle.gl_id, gl::INFO_LOG_LENGTH, &mut len);
      }
      let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
      unsafe {
        gl::GetProgramInfoLog(handle.gl_id, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
      }
      panic!("{}", str::from_utf8(buf.as_slice()).expect("ProgramInfoLog not valid utf8"));
    }

    Shader {
      handle: handle,
      components: components,
      uniforms: HashMap::new(),
    }
  }

  pub fn use_shader(&self, _gl: &mut GLContext) {
    unsafe {
      gl::UseProgram(self.handle.gl_id)
    }
  }

  pub fn get_uniform_location<T>(
    &mut self,
    gl: &mut GLContext,
    name: &'static str,
  ) -> GLint {
    let s_name = String::from_str(name);
    let name = name.to_c_str().as_ptr();
    match self.uniforms.get(&s_name) {
      None => {
        self.use_shader(gl);
        let loc = unsafe { gl::GetUniformLocation(self.handle.gl_id, name) };
        assert!(loc != -1, "couldn't find shader uniform: {}", s_name);

        self.uniforms.insert(s_name, loc);
        loc
      },
      Some(&loc) => loc,
    }
  }
}
<commit_msg>remove unused type parameter<commit_after>use gl;
use gl::types::*;
use gl_context::GLContext;
use std::collections::HashMap;
use std::ptr;
use std::str;

pub struct ProgramHandle<'a> {
  pub gl_id: GLuint,
}

impl<'a> ProgramHandle<'a> {
  pub fn new<'b: 'a>(_gl: &'b GLContext) -> ProgramHandle<'a> {
    let gl_id = unsafe {
      gl::CreateProgram()
    };

    ProgramHandle {
      gl_id: gl_id,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for ProgramHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteProgram(self.gl_id);
    }
  }
}

pub struct ShaderHandle<'a> {
  pub gl_id: GLuint,
}

impl<'a> ShaderHandle<'a> {
  pub fn compile_from<'b: 'a>(
    _gl: &'b GLContext,
    shader_source: String,
    typ: GLenum
  ) -> ShaderHandle<'a> {
    let gl_id = unsafe {
      gl::CreateShader(typ)
    };
    // Attempt to compile the shader
    shader_source.with_c_str(|ptr| unsafe { gl::ShaderSource(gl_id, 1, &ptr, ptr::null()) });
    unsafe {
      gl::CompileShader(gl_id);
    }

    // Get the compile status
    let mut status = gl::FALSE as GLint;
    unsafe {
      gl::GetShaderiv(gl_id, gl::COMPILE_STATUS, &mut status);
    }

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len = 0;
      unsafe {
        gl::GetShaderiv(gl_id, gl::INFO_LOG_LENGTH, &mut len);
      }
      let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
      unsafe {
        gl::GetShaderInfoLog(gl_id, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
      }
      panic!("error compiling 0x{:x} shader: {}", typ, str::from_utf8(buf.as_slice()).expect("ShaderInfoLog not valid utf8"));
    }

    ShaderHandle {
      gl_id: gl_id,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for ShaderHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteShader(self.gl_id);
    }
  }
}

pub struct Shader<'a> {
  pub handle: ProgramHandle<'a>,
  pub components: Vec<ShaderHandle<'a>>,
  pub uniforms: HashMap<String, GLint>,
}

impl<'a> Shader<'a> {
  pub fn new<'b: 'a, T: Iterator<(String, GLenum)>>(
    gl: &'b GLContext,
    shader_components: T,
  ) -> Shader<'a> {
    let mut shader_components = shader_components;
    let handle = ProgramHandle::new(gl);

    let mut components = Vec::new();
    for (content, component) in shader_components {
      let s = ShaderHandle::compile_from(gl, content, component);
      unsafe { gl::AttachShader(handle.gl_id, s.gl_id) };
      components.push(s);
    }

    unsafe {
      gl::LinkProgram(handle.gl_id);
    }

    // Get the link status
    let mut status = gl::FALSE as GLint;
    unsafe {
      gl::GetProgramiv(handle.gl_id, gl::LINK_STATUS, &mut status);
    }

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len: GLint = 0;
      unsafe {
        gl::GetProgramiv(handle.gl_id, gl::INFO_LOG_LENGTH, &mut len);
      }
      let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
      unsafe {
        gl::GetProgramInfoLog(handle.gl_id, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
      }
      panic!("{}", str::from_utf8(buf.as_slice()).expect("ProgramInfoLog not valid utf8"));
    }

    Shader {
      handle: handle,
      components: components,
      uniforms: HashMap::new(),
    }
  }

  pub fn use_shader(&self, _gl: &mut GLContext) {
    unsafe {
      gl::UseProgram(self.handle.gl_id)
    }
  }

  pub fn get_uniform_location(
    &mut self,
    gl: &mut GLContext,
    name: &'static str,
  ) -> GLint {
    let s_name = String::from_str(name);
    let name = name.to_c_str().as_ptr();
    match self.uniforms.get(&s_name) {
      None => {
        self.use_shader(gl);
        let loc = unsafe { gl::GetUniformLocation(self.handle.gl_id, name) };
        assert!(loc != -1, "couldn't find shader uniform: {}", s_name);

        self.uniforms.insert(s_name, loc);
        loc
      },
      Some(&loc) => loc,
    }
  }
}
<|endoftext|>


<commit_before>//! Various useful traits

/// Useful constants for radians.
pub trait Radians {
    /// Returns radians corresponding to 90 degrees.
    fn _90() -> Self;

    /// Returns radians corresponding to 180 degrees.
    fn _180() -> Self;

    /// Returns radians corresponding to 360 degrees.
    fn _360() -> Self;

    /// Convert a value to radians from degrees.
    /// Equivalent to ```value * (π / 180)```.
    fn deg_to_rad(self) -> Self;

    /// Convert a value to degrees from radians.
    /// Equivalent to ```value * (180 / π)```.
    fn rad_to_deg(self) -> Self;
}

impl Radians for f32 {
    #[inline(always)]
    fn _90() -> f32 {
        ::std::f32::consts::FRAC_PI_2
    }

    #[inline(always)]
    fn _180() -> f32 {
        ::std::f32::consts::PI
    }

    #[inline(always)]
    fn _360() -> f32 {
        <Self as Radians>::_180() * 2.0
    }

    #[inline(always)]
    fn deg_to_rad(self) -> Self {
        self * (::std::f32::consts::PI / 180.0f32)
    }

    #[inline(always)]
    fn rad_to_deg(self) -> Self {
        self * (180.0f32 / ::std::f32::consts::PI)
    }
}

impl Radians for f64 {
    #[inline(always)]
    fn _90() -> f64 {
        ::std::f64::consts::FRAC_PI_2
    }

    #[inline(always)]
    fn _180() -> f64 {
        ::std::f64::consts::PI
    }

    #[inline(always)]
    fn _360() -> f64 {
        <Self as Radians>::_180() * 2.0
    }

    #[inline(always)]
    fn deg_to_rad(self) -> Self {
        self * (::std::f64::consts::PI / 180.0f64)
    }

    #[inline(always)]
    fn rad_to_deg(self) -> Self {
        self * (180.0f64 / ::std::f64::consts::PI)
    }
}

/// Number 1.
pub trait One {
    /// Returns 1.
    fn one() -> Self;
}

/// Number 0.
pub trait Zero {
    /// Returns 0.
    fn zero() -> Self;
}

impl One for f64 {
    #[inline(always)]
    fn one() -> f64 { 1.0 }
}

impl One for f32 {
    #[inline(always)]
    fn one() -> f32 { 1.0 }
}

impl Zero for f64 {
    #[inline(always)]
    fn zero() -> f64 { 0.0 }
}

impl Zero for f32 {
    #[inline(always)]
    fn zero() -> f32 { 0.0 }
}

/// Square root.
pub trait Sqrt {
    /// Returns square root.
    fn sqrt(self) -> Self;
}

impl Sqrt for f32 {
    #[inline(always)]
    fn sqrt(self) -> f32 { self.sqrt() }
}

impl Sqrt for f64 {
    #[inline(always)]
    fn sqrt(self) -> f64 { self.sqrt() }
}

/// Casts into another type.
pub trait Cast<T> {
    /// Casts into other type.
    fn cast(self) -> T;
}

impl Cast<f32> for f64 {
    fn cast(self) -> f32 { self as f32 }
}

impl Cast<f64> for f32 {
    fn cast(self) -> f64 { self as f64 }
}

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

    #[test]
    fn test_f32_sqrt() {
        let a = 4.0f32;
        let b = <f32 as Sqrt>::sqrt(a);
        assert_eq!(b, 2.0f32);
    }

    #[test]
    fn test_f64_sqrt() {
        let a = 4.0f64;
        let b = <f64 as Sqrt>::sqrt(a);
        assert_eq!(b, 2.0f64);
    }

    #[test]
    fn test_f32_deg_to_rad() {
        let degrees = 23.0f32;
        let radians = degrees.deg_to_rad();
        assert!(f32::abs_sub(radians, 0.401425) > ::std::f32::EPSILON);
    }

    #[test]
    fn test_f64_deg_to_rad() {
        let degrees = 60.0f64;
        let radians = degrees.deg_to_rad();
        assert!(f64::abs_sub(radians, 1.047197)  > ::std::f64::EPSILON);
    }
}
<commit_msg>Added 'Trig' trait for basic trig functions<commit_after>//! Various useful traits

/// Useful constants for radians.
pub trait Radians {
    /// Returns radians corresponding to 90 degrees.
    fn _90() -> Self;

    /// Returns radians corresponding to 180 degrees.
    fn _180() -> Self;

    /// Returns radians corresponding to 360 degrees.
    fn _360() -> Self;

    /// Convert a value to radians from degrees.
    /// Equivalent to ```value * (π / 180)```.
    fn deg_to_rad(self) -> Self;

    /// Convert a value to degrees from radians.
    /// Equivalent to ```value * (180 / π)```.
    fn rad_to_deg(self) -> Self;
}

impl Radians for f32 {
    #[inline(always)]
    fn _90() -> f32 {
        ::std::f32::consts::FRAC_PI_2
    }

    #[inline(always)]
    fn _180() -> f32 {
        ::std::f32::consts::PI
    }

    #[inline(always)]
    fn _360() -> f32 {
        <Self as Radians>::_180() * 2.0
    }

    #[inline(always)]
    fn deg_to_rad(self) -> Self {
        self * (::std::f32::consts::PI / 180.0f32)
    }

    #[inline(always)]
    fn rad_to_deg(self) -> Self {
        self * (180.0f32 / ::std::f32::consts::PI)
    }
}

impl Radians for f64 {
    #[inline(always)]
    fn _90() -> f64 {
        ::std::f64::consts::FRAC_PI_2
    }

    #[inline(always)]
    fn _180() -> f64 {
        ::std::f64::consts::PI
    }

    #[inline(always)]
    fn _360() -> f64 {
        <Self as Radians>::_180() * 2.0
    }

    #[inline(always)]
    fn deg_to_rad(self) -> Self {
        self * (::std::f64::consts::PI / 180.0f64)
    }

    #[inline(always)]
    fn rad_to_deg(self) -> Self {
        self * (180.0f64 / ::std::f64::consts::PI)
    }
}

/// Number 1.
pub trait One {
    /// Returns 1.
    fn one() -> Self;
}

/// Number 0.
pub trait Zero {
    /// Returns 0.
    fn zero() -> Self;
}

impl One for f64 {
    #[inline(always)]
    fn one() -> f64 { 1.0 }
}

impl One for f32 {
    #[inline(always)]
    fn one() -> f32 { 1.0 }
}

impl Zero for f64 {
    #[inline(always)]
    fn zero() -> f64 { 0.0 }
}

impl Zero for f32 {
    #[inline(always)]
    fn zero() -> f32 { 0.0 }
}

/// Square root.
pub trait Sqrt {
    /// Returns square root.
    fn sqrt(self) -> Self;
}

impl Sqrt for f32 {
    #[inline(always)]
    fn sqrt(self) -> f32 { self.sqrt() }
}

impl Sqrt for f64 {
    #[inline(always)]
    fn sqrt(self) -> f64 { self.sqrt() }
}

/// Basic trigonometry functions
pub trait Trig {
    /// Returns sine of self
    fn sin(self) -> Self;
    /// Returns cosine of self
    fn cos(self) -> Self;
    /// Returns tangent of self
    fn tan(self) -> Self;
}

impl Trig for f32 {
    #[inline(always)]
    fn sin(self) -> f32 { self.sin() }

    #[inline(always)]
    fn cos(self) -> f32 { self.cos() }

    #[inline(always)]
    fn tan(self) -> f32 { self.tan() }
}

impl Trig for f64 {
    #[inline(always)]
    fn sin(self) -> f64 { self.sin() }

    #[inline(always)]
    fn cos(self) -> f64 { self.cos() }

    #[inline(always)]
    fn tan(self) -> f64 { self.tan() }
}

/// Casts into another type.
pub trait Cast<T> {
    /// Casts into other type.
    fn cast(self) -> T;
}

impl Cast<f32> for f64 {
    fn cast(self) -> f32 { self as f32 }
}

impl Cast<f64> for f32 {
    fn cast(self) -> f64 { self as f64 }
}

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

    #[test]
    fn test_f32_sqrt() {
        let a = 4.0f32;
        let b = <f32 as Sqrt>::sqrt(a);
        assert_eq!(b, 2.0f32);
    }

    #[test]
    fn test_f64_sqrt() {
        let a = 4.0f64;
        let b = <f64 as Sqrt>::sqrt(a);
        assert_eq!(b, 2.0f64);
    }

    #[test]
    fn test_f32_deg_to_rad() {
        let degrees = 23.0f32;
        let radians = degrees.deg_to_rad();
        assert!(f32::abs_sub(radians, 0.401425) > ::std::f32::EPSILON);
    }

    #[test]
    fn test_f64_deg_to_rad() {
        let degrees = 60.0f64;
        let radians = degrees.deg_to_rad();
        assert!(f64::abs_sub(radians, 1.047197)  > ::std::f64::EPSILON);
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use bindings::*;
use heapsize::HeapSizeOf;
use std::fmt::{self, Debug};

// Defines an Arc-like type that manages a refcounted Gecko object stored
// in a ThreadSafeFooHolder smart pointer.  Used in tandem with the
// NS_DECL_HOLDER_FFI_REFCOUNTING-defined types and functions in Gecko.
macro_rules! define_holder_arc {
    ($arc_type:ident, $name:ident, $holder_type:ident, $addref: ident, $release: ident) => (
        #[derive(PartialEq)]
        pub struct $arc_type {
            ptr: *mut $holder_type,
        }

        impl $arc_type {
            pub fn new(data: *mut $holder_type) -> $arc_type {
                debug_assert!(!data.is_null());
                unsafe { $addref(data); }
                $arc_type {
                    ptr: data
                }
            }

            pub fn as_raw(&self) -> *mut $holder_type { self.ptr }
        }

        unsafe impl Send for $arc_type {}
        unsafe impl Sync for $arc_type {}

        impl Clone for $arc_type {
            fn clone(&self) -> $arc_type {
                $arc_type::new(self.ptr)
            }
        }

        impl Drop for $arc_type {
            fn drop(&mut self) {
                unsafe { $release(self.ptr); }
            }
        }

        impl HeapSizeOf for $arc_type {
            fn heap_size_of_children(&self) -> usize { 0 }
        }

        impl Debug for $arc_type {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, stringify!($name))
            }
        }
    )
}

define_holder_arc!(GeckoArcPrincipal, Principal, ThreadSafePrincipalHolder,
                   Gecko_AddRefPrincipalArbitraryThread, Gecko_ReleasePrincipalArbitraryThread);
define_holder_arc!(GeckoArcURI, URI, ThreadSafeURIHolder,
                   Gecko_AddRefURIArbitraryThread, Gecko_ReleaseURIArbitraryThread);
<commit_msg>Rename GeckoArc macro so it sounds like it's useful for already-threadsafely-refcounted objects.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use bindings::*;
use heapsize::HeapSizeOf;
use std::fmt::{self, Debug};

// Defines an Arc-like type that manages a refcounted Gecko object stored
// in a ThreadSafeFooHolder smart pointer (for those Gecko classes that
// do not have thread-safe refcounting support) or as raw pointers (for
// those that do have thread-safe refcounting support).  Used in tandem
// with the NS_DECL_(HOLDER|THREADSAFE)_FFI_REFCOUNTING-defined types and
// functions in Gecko.
macro_rules! define_arc {
    ($arc_type:ident, $name:ident, $gecko_type:ident, $addref: ident, $release: ident) => (
        #[derive(PartialEq)]
        pub struct $arc_type {
            ptr: *mut $gecko_type,
        }

        impl $arc_type {
            pub fn new(data: *mut $gecko_type) -> $arc_type {
                debug_assert!(!data.is_null());
                unsafe { $addref(data); }
                $arc_type {
                    ptr: data
                }
            }

            pub fn as_raw(&self) -> *mut $gecko_type { self.ptr }
        }

        unsafe impl Send for $arc_type {}
        unsafe impl Sync for $arc_type {}

        impl Clone for $arc_type {
            fn clone(&self) -> $arc_type {
                $arc_type::new(self.ptr)
            }
        }

        impl Drop for $arc_type {
            fn drop(&mut self) {
                unsafe { $release(self.ptr); }
            }
        }

        impl HeapSizeOf for $arc_type {
            fn heap_size_of_children(&self) -> usize { 0 }
        }

        impl Debug for $arc_type {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, stringify!($name))
            }
        }
    )
}

define_arc!(GeckoArcPrincipal, Principal, ThreadSafePrincipalHolder,
            Gecko_AddRefPrincipalArbitraryThread, Gecko_ReleasePrincipalArbitraryThread);
define_arc!(GeckoArcURI, URI, ThreadSafeURIHolder,
            Gecko_AddRefURIArbitraryThread, Gecko_ReleaseURIArbitraryThread);
<|endoftext|>


<commit_before>use std::marker::PhantomData;

use string_cache::Atom;

use serde::ser::{Serialize, Serializer};
use serde::de::{Deserialize, Deserializer, Error as DeserializationError, Type as DeserializationType};

use std::cmp::PartialEq;
use std::hash::{Hash, Hasher};

/// A marker for a request that a expects a specific value.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum Exactly<T> {
    /// No constraint.
    Always,

    /// Expect a specific value.
    Exactly(T),

    /// Never accept a constraint. This can happen, for instance, we have have
    /// attempted to `and` two conflicting `Exactly`
    Never,
}

impl<T> Exactly<T> where T: PartialEq {
    /// Combine two constraints.
    pub fn and(self, other: Self) -> Self {
        use self::Exactly::*;
        match (self, other) {
            (Never, _) | (_, Never) => Never,
            (Always, x) | (x, Always) => x,
            (Exactly(x), Exactly(y)) =>
                if x == y {
                    Exactly(y)
                } else {
                    Never
                }
        }
    }

    pub fn is_empty(&self) -> bool {
        match *self {
            Exactly::Always => true,
            _ => false,
        }
    }

    pub fn matches(&self, value: &T) -> bool {
        match *self {
            Exactly::Always => true,
            Exactly::Exactly(ref id) => id == value,
            _ => false
        }
    }
}

impl<T> Default for Exactly<T> {
    fn default() -> Self {
        Exactly::Always
    }
}

/// A variant of `PhantomData` that supports [De]serialization
#[derive(Clone, Debug, PartialEq, Hash, Eq)]
pub struct Phantom<T> {
    phantom: PhantomData<T>
}

impl<T> Default for Phantom<T> {
    fn default() -> Self {
        Self::new()
    }
}

impl<T> Phantom<T> {
    pub fn new() -> Self {
        Phantom {
            phantom: PhantomData
        }
    }
}
impl<T> Serialize for Phantom<T> {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer {
            ().serialize(serializer)
    }
}
impl<T> Deserialize for Phantom<T> {
    fn deserialize<D>(_: &mut D) -> Result<Self, D::Error>
        where D: Deserializer {
        // Nothing to consume
        Ok(Phantom {
            phantom: PhantomData
        })
    }
}

/// A unique id for values of a given kind.
///
/// # Performance
///
/// This data structure is tuned for specific use cases and should be used accordingly.
///
/// - Using an instances of `Id` as a key in a `HashMap` or `HashSet` is much faster than
///   using a `String`.
/// - Comparing two instances of `Id` is much faster than comparing two `String`s.
/// - Instances of `Id` take very little memory.
/// - Cloning an instance of `Id` is relatively fast, but should be avoided if possible.
/// - Calling `Id::new`, on the other hand, is *very slow*. **Always prefer cloning to calling
///   `Id::new`**.
///
/// # (De)serialization
///
/// Serialized values of this type are represented by plain strings.
///
/// ```
/// extern crate serde;
/// extern crate serde_json;
/// extern crate foxbox_taxonomy;
///
/// #[derive(Debug)]
/// struct UniqueId;
///
/// let my_id = foxbox_taxonomy::util::Id::<UniqueId>::new("Unique Identifier".to_owned());
///
/// let my_serialized_id = serde_json::to_string(&my_id).unwrap();
/// assert_eq!(my_serialized_id, "\"Unique Identifier\"");
///
/// let my_deserialized_id: foxbox_taxonomy::util::Id<UniqueId> =
///     serde_json::from_str("\"Unique Identifier\"").unwrap();
/// assert_eq!(my_deserialized_id, my_id);
/// ```
#[derive(Debug, Clone)]
pub struct Id<T> {
    id: Atom,

    phantom: Phantom<T>,
}

impl<T> Id<T> {
    pub fn new(id: String) -> Self {
        Id {
            id: Atom::from(id),
            phantom: Phantom::new(),
        }
    }

    pub fn as_atom(&self) -> &Atom {
        &self.id
    }
}

impl<T> PartialEq for Id<T> {
    fn eq(&self, other: &Self) -> bool {
        self.id.eq(&other.id)
    }
}

impl<T> Eq for Id<T> {
}

impl<T> Hash for Id<T> {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        self.id.hash(state)
    }
}

impl<T> Serialize for Id<T> {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer {
        self.id.as_ref().serialize(serializer)
    }
}

impl<T> Deserialize for Id<T> {
    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
        where D: Deserializer {
        let deserialized_string = try!(String::deserialize(deserializer));

        Ok(Id {
            id: Atom::from(deserialized_string),
            phantom: Phantom::new(),
        })
    }
}

/// A bunch of results grouped in an array of (key, result).
pub type ResultSet<I, T, E> = Vec<(I, Result<T, E>)>;

/// By default, the (de)serialization of trivial enums by Serde is surprising, e.g.
/// in JSON,  `enum Foo {A, B, C}` will produce `{"\"A\": []"}` for `A`, where `"\"A\""`
/// would be expected.
///
/// Implementing serialization is very simple, but deserialization is much more annoying.
/// This struct lets us implement simply the deserialization to a predictable and well-specified
/// list of strings.
///
/// # Example
///
/// ```
/// extern crate serde;
/// use serde::de::{Deserialize, Deserializer};
///
/// extern crate foxbox_taxonomy;
/// use foxbox_taxonomy::util::TrivialEnumVisitor;
///
/// enum Foo { A, B, C }
///
/// impl Deserialize for Foo {
///   fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> where D: Deserializer {
///     deserializer.visit_string(TrivialEnumVisitor::new(|source| {
///       match source {
///         "A" => Ok(Foo::A),
///         "B" => Ok(Foo::B),
///         "C" => Ok(Foo::C),
///          _ => Err(())
///       }
///    }))
///   }
/// }
///
/// # fn main() {}
/// ```
pub struct TrivialEnumVisitor<T> where T: Deserialize {
    parser: Box<Fn(&str) -> Result<T, ()>>
}

impl<T> TrivialEnumVisitor<T> where T: Deserialize {
    pub fn new<F>(parser: F) -> Self
        where F: Fn(&str) -> Result<T, ()> + 'static {
            TrivialEnumVisitor {
                parser: Box::new(parser)
            }
        }
    fn parse<E>(&self, source: &str) -> Result<T, E>
        where E: DeserializationError
    {
        (self.parser)(source)
            .map_err(|()| E::unknown_field(&source.to_owned()))
    }
}

use serde::de::Visitor;
impl<T> Visitor for TrivialEnumVisitor<T> where T: Deserialize {
    type Value = T;
    fn visit_str<E>(&mut self, v: &str) -> Result<T, E>
        where E: DeserializationError,
    {
        self.parse(v)
    }

    fn visit_string<E>(&mut self, v: String) -> Result<T, E>
        where E: DeserializationError,
    {
        self.parse(&v)
    }

    fn visit_bytes<E>(&mut self, v: &[u8]) -> Result<T, E>
        where E: DeserializationError,
    {
        use std::str;
        match str::from_utf8(v) {
            Ok(s) => self.parse(s),
            Err(_) => Err(E::type_mismatch(DeserializationType::String)),
        }
    }

    fn visit_byte_buf<E>(&mut self, v: Vec<u8>) -> Result<T, E>
        where E: DeserializationError,
    {
        match String::from_utf8(v) {
            Ok(s) => self.parse(&s),
            Err(_) => Err(DeserializationError::type_mismatch(DeserializationType::String)),
        }
    }
}
<commit_msg>[fxbox/taxonomy] Merge pull request #23 from hfiguiere/issue21-id-as_string<commit_after>use std::marker::PhantomData;

use string_cache::Atom;

use serde::ser::{Serialize, Serializer};
use serde::de::{Deserialize, Deserializer, Error as DeserializationError, Type as DeserializationType};

use std::cmp::PartialEq;
use std::hash::{Hash, Hasher};
use std::string::ToString;

/// A marker for a request that a expects a specific value.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum Exactly<T> {
    /// No constraint.
    Always,

    /// Expect a specific value.
    Exactly(T),

    /// Never accept a constraint. This can happen, for instance, we have have
    /// attempted to `and` two conflicting `Exactly`
    Never,
}

impl<T> Exactly<T> where T: PartialEq {
    /// Combine two constraints.
    pub fn and(self, other: Self) -> Self {
        use self::Exactly::*;
        match (self, other) {
            (Never, _) | (_, Never) => Never,
            (Always, x) | (x, Always) => x,
            (Exactly(x), Exactly(y)) =>
                if x == y {
                    Exactly(y)
                } else {
                    Never
                }
        }
    }

    pub fn is_empty(&self) -> bool {
        match *self {
            Exactly::Always => true,
            _ => false,
        }
    }

    pub fn matches(&self, value: &T) -> bool {
        match *self {
            Exactly::Always => true,
            Exactly::Exactly(ref id) => id == value,
            _ => false
        }
    }
}

impl<T> Default for Exactly<T> {
    fn default() -> Self {
        Exactly::Always
    }
}

/// A variant of `PhantomData` that supports [De]serialization
#[derive(Clone, Debug, PartialEq, Hash, Eq)]
pub struct Phantom<T> {
    phantom: PhantomData<T>
}

impl<T> Default for Phantom<T> {
    fn default() -> Self {
        Self::new()
    }
}

impl<T> Phantom<T> {
    pub fn new() -> Self {
        Phantom {
            phantom: PhantomData
        }
    }
}
impl<T> Serialize for Phantom<T> {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer {
            ().serialize(serializer)
    }
}
impl<T> Deserialize for Phantom<T> {
    fn deserialize<D>(_: &mut D) -> Result<Self, D::Error>
        where D: Deserializer {
        // Nothing to consume
        Ok(Phantom {
            phantom: PhantomData
        })
    }
}

/// A unique id for values of a given kind.
///
/// # Performance
///
/// This data structure is tuned for specific use cases and should be used accordingly.
///
/// - Using an instances of `Id` as a key in a `HashMap` or `HashSet` is much faster than
///   using a `String`.
/// - Comparing two instances of `Id` is much faster than comparing two `String`s.
/// - Instances of `Id` take very little memory.
/// - Cloning an instance of `Id` is relatively fast, but should be avoided if possible.
/// - Calling `Id::new`, on the other hand, is *very slow*. **Always prefer cloning to calling
///   `Id::new`**.
///
/// # (De)serialization
///
/// Serialized values of this type are represented by plain strings.
///
/// ```
/// extern crate serde;
/// extern crate serde_json;
/// extern crate foxbox_taxonomy;
///
/// #[derive(Debug)]
/// struct UniqueId;
///
/// let my_id = foxbox_taxonomy::util::Id::<UniqueId>::new("Unique Identifier".to_owned());
///
/// assert_eq!(my_id.to_string(), "Unique Identifier");
///
/// let my_serialized_id = serde_json::to_string(&my_id).unwrap();
/// assert_eq!(my_serialized_id, "\"Unique Identifier\"");
///
/// let my_deserialized_id: foxbox_taxonomy::util::Id<UniqueId> =
///     serde_json::from_str("\"Unique Identifier\"").unwrap();
/// assert_eq!(my_deserialized_id, my_id);
/// ```
#[derive(Debug, Clone)]
pub struct Id<T> {
    id: Atom,

    phantom: Phantom<T>,
}

impl<T> Id<T> {
    pub fn new(id: String) -> Self {
        Id {
            id: Atom::from(id),
            phantom: Phantom::new(),
        }
    }

    pub fn as_atom(&self) -> &Atom {
        &self.id
    }
}

impl<T> ToString for Id<T> {
    fn to_string(&self) -> String {
        String::from(self.id.as_ref())
    }
}

impl<T> PartialEq for Id<T> {
    fn eq(&self, other: &Self) -> bool {
        self.id.eq(&other.id)
    }
}

impl<T> Eq for Id<T> {
}

impl<T> Hash for Id<T> {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        self.id.hash(state)
    }
}

impl<T> Serialize for Id<T> {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer {
        self.id.as_ref().serialize(serializer)
    }
}

impl<T> Deserialize for Id<T> {
    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
        where D: Deserializer {
        let deserialized_string = try!(String::deserialize(deserializer));

        Ok(Id {
            id: Atom::from(deserialized_string),
            phantom: Phantom::new(),
        })
    }
}

/// A bunch of results grouped in an array of (key, result).
pub type ResultSet<I, T, E> = Vec<(I, Result<T, E>)>;

/// By default, the (de)serialization of trivial enums by Serde is surprising, e.g.
/// in JSON,  `enum Foo {A, B, C}` will produce `{"\"A\": []"}` for `A`, where `"\"A\""`
/// would be expected.
///
/// Implementing serialization is very simple, but deserialization is much more annoying.
/// This struct lets us implement simply the deserialization to a predictable and well-specified
/// list of strings.
///
/// # Example
///
/// ```
/// extern crate serde;
/// use serde::de::{Deserialize, Deserializer};
///
/// extern crate foxbox_taxonomy;
/// use foxbox_taxonomy::util::TrivialEnumVisitor;
///
/// enum Foo { A, B, C }
///
/// impl Deserialize for Foo {
///   fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> where D: Deserializer {
///     deserializer.visit_string(TrivialEnumVisitor::new(|source| {
///       match source {
///         "A" => Ok(Foo::A),
///         "B" => Ok(Foo::B),
///         "C" => Ok(Foo::C),
///          _ => Err(())
///       }
///    }))
///   }
/// }
///
/// # fn main() {}
/// ```
pub struct TrivialEnumVisitor<T> where T: Deserialize {
    parser: Box<Fn(&str) -> Result<T, ()>>
}

impl<T> TrivialEnumVisitor<T> where T: Deserialize {
    pub fn new<F>(parser: F) -> Self
        where F: Fn(&str) -> Result<T, ()> + 'static {
            TrivialEnumVisitor {
                parser: Box::new(parser)
            }
        }
    fn parse<E>(&self, source: &str) -> Result<T, E>
        where E: DeserializationError
    {
        (self.parser)(source)
            .map_err(|()| E::unknown_field(&source.to_owned()))
    }
}

use serde::de::Visitor;
impl<T> Visitor for TrivialEnumVisitor<T> where T: Deserialize {
    type Value = T;
    fn visit_str<E>(&mut self, v: &str) -> Result<T, E>
        where E: DeserializationError,
    {
        self.parse(v)
    }

    fn visit_string<E>(&mut self, v: String) -> Result<T, E>
        where E: DeserializationError,
    {
        self.parse(&v)
    }

    fn visit_bytes<E>(&mut self, v: &[u8]) -> Result<T, E>
        where E: DeserializationError,
    {
        use std::str;
        match str::from_utf8(v) {
            Ok(s) => self.parse(s),
            Err(_) => Err(E::type_mismatch(DeserializationType::String)),
        }
    }

    fn visit_byte_buf<E>(&mut self, v: Vec<u8>) -> Result<T, E>
        where E: DeserializationError,
    {
        match String::from_utf8(v) {
            Ok(s) => self.parse(&s),
            Err(_) => Err(DeserializationError::type_mismatch(DeserializationType::String)),
        }
    }
}
<|endoftext|>


<commit_before>use ctxt::Context;

use ast::*;
use ast::Expr::*;
use ast::Stmt::*;
use ast::visit::*;

use ir::*;
use ir::Instr::*;
use ir::Opnd::*;

pub fn generate<'a, 'ast>(ctxt: &Context<'a, 'ast>, ast: &'ast Ast) {
    Builder::new(ctxt).visit_ast(ast);
}

struct Builder<'a, 'ast: 'a> {
    ctxt: &'a Context<'a, 'ast>,
    vreg: u32,
    result: Opnd,
    block_id: BlockId,
    fct: Fct,
}

impl<'a, 'ast> Builder<'a, 'ast> {
    fn new(ctxt: &'a Context<'a, 'ast>) -> Builder<'a, 'ast> {
        Builder {
            ctxt: ctxt,
            vreg: 0,
            result: OpndInt(0),
            block_id: BlockId(0),
            fct: Fct::new(),
        }
    }

    fn add_stmt_expr(&mut self, stmt: &'ast StmtExprType) {
        self.visit_expr(&stmt.expr);
    }

    fn add_stmt_if(&mut self, stmt: &'ast StmtIfType) {
        let before_id = self.block_id;
        let then_id = self.fct.add_block();
        let after_id = self.fct.add_block();
        let else_id = if stmt.else_block.is_some() {
            self.fct.add_block()
        } else {
            after_id
        };

        self.visit_expr(&stmt.cond);
        let result = self.result;
        self.add_instr(InstrTest(result));
        self.block_mut().add_successor(then_id);
        self.block_mut().add_successor(else_id);

        self.block_id = then_id;
        self.visit_stmt(&stmt.then_block);
        self.add_instr(InstrGoto(after_id));
        self.block_mut().add_predecessor(before_id);
        self.block_mut().add_successor(after_id);

        if let Some(ref else_block) = stmt.else_block {
            self.block_id = else_id;
            self.visit_stmt(else_block);
            self.add_instr(InstrGoto(after_id));
            self.block_mut().add_predecessor(before_id);
            self.block_mut().add_successor(after_id);
        }

        self.block_id = after_id;
    }

    fn add_stmt_loop(&mut self, stmt: &'ast StmtLoopType) {
        let before_id = self.block_id;
        let loop_id = self.fct.add_block();
        let after_id = self.fct.add_block();

        self.add_instr(InstrGoto(loop_id));
        self.block_mut().add_successor(loop_id);

        self.block_id = loop_id;
        self.visit_stmt(&stmt.block);
        self.add_instr(InstrGoto(loop_id));
        self.block_mut().add_predecessor(before_id);
        self.block_mut().add_successor(loop_id);
        self.block_mut().add_successor(after_id);

        self.block_id = after_id;
    }

    fn add_stmt_while(&mut self, stmt: &'ast StmtWhileType) {

    }

    fn add_stmt_block(&mut self, stmt: &'ast StmtBlockType) {
        for s in &stmt.stmts {
            self.visit_stmt(s);
        }
    }

    fn add_expr_lit_int(&mut self, lit: &'ast ExprLitIntType) {
        self.result = OpndInt(lit.value);
    }

    fn add_expr_lit_bool(&mut self, lit: &'ast ExprLitBoolType) {
        self.result = OpndBool(lit.value);
    }

    fn add_expr_lit_str(&mut self, lit: &'ast ExprLitStrType) {
        let dest = self.next_vreg();
        let instr = InstrStr(dest, lit.value.clone());
        self.add_instr(instr);

        self.result = dest;
    }

    fn add_expr_un(&mut self, expr: &'ast ExprUnType) {
        self.visit_expr(&expr.opnd);
        let src = self.result;

        let dest = self.next_vreg();
        let instr = InstrUn(dest, expr.op, src);
        self.add_instr(instr);
    }

    fn add_expr_bin(&mut self, expr: &'ast ExprBinType) {
        self.visit_expr(&expr.lhs);
        let lhs = self.result;

        self.visit_expr(&expr.rhs);
        let rhs = self.result;

        let dest = self.next_vreg();
        let instr = InstrBin(dest, lhs, expr.op, rhs);
        self.add_instr(instr);
    }

    fn add_instr_assign(&mut self, dest: Opnd, src: Opnd) {
        self.add_instr(InstrAssign(dest, src));
    }

    fn add_instr(&mut self, instr: Instr) {
        self.block_mut().add_instr(instr);
    }

    fn block_mut(&mut self) -> &mut Block {
        self.fct.block_mut(self.block_id)
    }

    fn next_vreg(&mut self) -> Opnd {
        let vreg = self.vreg;

        self.vreg += 1;

        OpndReg(vreg)
    }
}

impl<'a, 'ast> Visitor<'ast> for Builder<'a, 'ast> {
    fn visit_fct(&mut self, f: &'ast Function) {
        self.vreg = 0;
        self.block_id = self.fct.add_block();
    }

    fn visit_param(&mut self, p: &'ast Param) {
    }

    fn visit_stmt(&mut self, s: &'ast Stmt) {
        match *s {
            StmtExpr(ref stmt) => self.add_stmt_expr(stmt),
            StmtIf(ref stmt) => self.add_stmt_if(stmt),
            StmtLoop(ref stmt) => self.add_stmt_loop(stmt),
            StmtWhile(ref stmt) => self.add_stmt_while(stmt),
            StmtBlock(ref stmt) => self.add_stmt_block(stmt),
            _ => panic!("unsupported statement")
        }
    }

    fn visit_expr(&mut self, e: &'ast Expr) {
        match *e {
            ExprLitInt(ref expr) => self.add_expr_lit_int(expr),
            ExprLitBool(ref expr) => self.add_expr_lit_bool(expr),
            ExprLitStr(ref expr) => self.add_expr_lit_str(expr),
            // ExprIdent(ref expr) => self.add_expr_ident(expr),
            ExprUn(ref expr) => self.add_expr_un(expr),
            ExprBin(ref expr) => self.add_expr_bin(expr),
            // ExprAssign(ref expr) => self.add_expr_assign(expr),
            _ => panic!("unsupported expression")
        }
    }
}
<commit_msg>renamed Builder to Generator<commit_after>use ctxt::Context;

use ast::*;
use ast::Expr::*;
use ast::Stmt::*;
use ast::visit::*;

use ir::*;
use ir::Instr::*;
use ir::Opnd::*;

pub fn generate<'a, 'ast>(ctxt: &Context<'a, 'ast>, ast: &'ast Ast) {
    Generator::new(ctxt).visit_ast(ast);
}

struct Generator<'a, 'ast: 'a> {
    ctxt: &'a Context<'a, 'ast>,
    vreg: u32,
    result: Opnd,
    block_id: BlockId,
    fct: Fct,
}

impl<'a, 'ast> Generator<'a, 'ast> {
    fn new(ctxt: &'a Context<'a, 'ast>) -> Generator<'a, 'ast> {
        Generator {
            ctxt: ctxt,
            vreg: 0,
            result: OpndInt(0),
            block_id: BlockId(0),
            fct: Fct::new(),
        }
    }

    fn add_stmt_expr(&mut self, stmt: &'ast StmtExprType) {
        self.visit_expr(&stmt.expr);
    }

    fn add_stmt_if(&mut self, stmt: &'ast StmtIfType) {
        let before_id = self.block_id;
        let then_id = self.fct.add_block();
        let after_id = self.fct.add_block();
        let else_id = if stmt.else_block.is_some() {
            self.fct.add_block()
        } else {
            after_id
        };

        self.visit_expr(&stmt.cond);
        let result = self.result;
        self.add_instr(InstrTest(result));
        self.block_mut().add_successor(then_id);
        self.block_mut().add_successor(else_id);

        self.block_id = then_id;
        self.visit_stmt(&stmt.then_block);
        self.add_instr(InstrGoto(after_id));
        self.block_mut().add_predecessor(before_id);
        self.block_mut().add_successor(after_id);

        if let Some(ref else_block) = stmt.else_block {
            self.block_id = else_id;
            self.visit_stmt(else_block);
            self.add_instr(InstrGoto(after_id));
            self.block_mut().add_predecessor(before_id);
            self.block_mut().add_successor(after_id);
        }

        self.block_id = after_id;
    }

    fn add_stmt_loop(&mut self, stmt: &'ast StmtLoopType) {
        let before_id = self.block_id;
        let loop_id = self.fct.add_block();
        let after_id = self.fct.add_block();

        self.add_instr(InstrGoto(loop_id));
        self.block_mut().add_successor(loop_id);

        self.block_id = loop_id;
        self.visit_stmt(&stmt.block);
        self.add_instr(InstrGoto(loop_id));
        self.block_mut().add_predecessor(before_id);
        self.block_mut().add_successor(loop_id);
        self.block_mut().add_successor(after_id);

        self.block_id = after_id;
    }

    fn add_stmt_while(&mut self, stmt: &'ast StmtWhileType) {

    }

    fn add_stmt_block(&mut self, stmt: &'ast StmtBlockType) {
        for s in &stmt.stmts {
            self.visit_stmt(s);
        }
    }

    fn add_expr_lit_int(&mut self, lit: &'ast ExprLitIntType) {
        self.result = OpndInt(lit.value);
    }

    fn add_expr_lit_bool(&mut self, lit: &'ast ExprLitBoolType) {
        self.result = OpndBool(lit.value);
    }

    fn add_expr_lit_str(&mut self, lit: &'ast ExprLitStrType) {
        let dest = self.next_vreg();
        let instr = InstrStr(dest, lit.value.clone());
        self.add_instr(instr);

        self.result = dest;
    }

    fn add_expr_un(&mut self, expr: &'ast ExprUnType) {
        self.visit_expr(&expr.opnd);
        let src = self.result;

        let dest = self.next_vreg();
        let instr = InstrUn(dest, expr.op, src);
        self.add_instr(instr);
    }

    fn add_expr_bin(&mut self, expr: &'ast ExprBinType) {
        self.visit_expr(&expr.lhs);
        let lhs = self.result;

        self.visit_expr(&expr.rhs);
        let rhs = self.result;

        let dest = self.next_vreg();
        let instr = InstrBin(dest, lhs, expr.op, rhs);
        self.add_instr(instr);
    }

    fn add_instr_assign(&mut self, dest: Opnd, src: Opnd) {
        self.add_instr(InstrAssign(dest, src));
    }

    fn add_instr(&mut self, instr: Instr) {
        self.block_mut().add_instr(instr);
    }

    fn block_mut(&mut self) -> &mut Block {
        self.fct.block_mut(self.block_id)
    }

    fn next_vreg(&mut self) -> Opnd {
        let vreg = self.vreg;

        self.vreg += 1;

        OpndReg(vreg)
    }
}

impl<'a, 'ast> Visitor<'ast> for Generator<'a, 'ast> {
    fn visit_fct(&mut self, f: &'ast Function) {
        self.vreg = 0;
        self.block_id = self.fct.add_block();
    }

    fn visit_param(&mut self, p: &'ast Param) {
    }

    fn visit_stmt(&mut self, s: &'ast Stmt) {
        match *s {
            StmtExpr(ref stmt) => self.add_stmt_expr(stmt),
            StmtIf(ref stmt) => self.add_stmt_if(stmt),
            StmtLoop(ref stmt) => self.add_stmt_loop(stmt),
            StmtWhile(ref stmt) => self.add_stmt_while(stmt),
            StmtBlock(ref stmt) => self.add_stmt_block(stmt),
            _ => panic!("unsupported statement")
        }
    }

    fn visit_expr(&mut self, e: &'ast Expr) {
        match *e {
            ExprLitInt(ref expr) => self.add_expr_lit_int(expr),
            ExprLitBool(ref expr) => self.add_expr_lit_bool(expr),
            ExprLitStr(ref expr) => self.add_expr_lit_str(expr),
            // ExprIdent(ref expr) => self.add_expr_ident(expr),
            ExprUn(ref expr) => self.add_expr_un(expr),
            ExprBin(ref expr) => self.add_expr_bin(expr),
            // ExprAssign(ref expr) => self.add_expr_assign(expr),
            _ => panic!("unsupported expression")
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate failure;
#[macro_use] extern crate failure_derive;
#[macro_use] extern crate lazy_static;
extern crate mal;
extern crate regex;

mod input;
mod series;

use std::path::Path;
use failure::Error;
use mal::MAL;
use series::Series;

fn main() {
    let args = std::env::args().collect::<Vec<String>>();

    let series = match Series::from_path(Path::new(&args[1])) {
        Ok(s) => s,
        Err(err) => {
            eprintln!("{}", err);
            panic!("{:?}", err);
        },
    };

    println!("{:?}", series);

    let mal = MAL::new(args[2].clone(), args[3].clone());
    let selected = find_and_select_series(&mal, &series.name).unwrap();

    println!("selected:\n{:?}", selected);
}

fn find_and_select_series(mal: &MAL, name: &str) -> Result<mal::AnimeEntry, Error> {
    let mut series = mal.search(name)?;

    if series.len() == 0 {
        return Err(format_err!("no anime named [{}] found", name));
    } else if series.len() > 1 {
        println!("multiple anime named [{}] found", name);
        println!("enter the number next to the anime name for the one you want\n");

        for (i, s) in series.iter().enumerate() {
            println!("{} [{}]", 1 + i, s.title);
        }

        let idx = input::read_usize_range(1, series.len())? - 1;
        Ok(series.swap_remove(idx))
    } else {
        Ok(series.swap_remove(0))
    }
}<commit_msg>Make anime selection messages more concise<commit_after>#[macro_use] extern crate failure;
#[macro_use] extern crate failure_derive;
#[macro_use] extern crate lazy_static;
extern crate mal;
extern crate regex;

mod input;
mod series;

use std::path::Path;
use failure::Error;
use mal::MAL;
use series::Series;

fn main() {
    let args = std::env::args().collect::<Vec<String>>();

    let series = match Series::from_path(Path::new(&args[1])) {
        Ok(s) => s,
        Err(err) => {
            eprintln!("{}", err);
            panic!("{:?}", err);
        },
    };

    println!("{:?}", series);

    let mal = MAL::new(args[2].clone(), args[3].clone());
    let selected = find_and_select_series(&mal, &series.name).unwrap();

    println!("selected:\n{:?}", selected);
}

fn find_and_select_series(mal: &MAL, name: &str) -> Result<mal::AnimeEntry, Error> {
    let mut series = mal.search(name)?;

    if series.len() == 0 {
        return Err(format_err!("no anime named [{}] found", name));
    } else if series.len() > 1 {
        println!("found multiple anime named [{}] on MAL", name);
        println!("input the number corrosponding with the intended anime:\n");

        for (i, s) in series.iter().enumerate() {
            println!("{} [{}]", 1 + i, s.title);
        }

        let idx = input::read_usize_range(1, series.len())? - 1;
        Ok(series.swap_remove(idx))
    } else {
        Ok(series.swap_remove(0))
    }
}<|endoftext|>


<commit_before>// Implements the `zakopane checksum` subcommand.

use crate::structs::ZakopaneError;

const MAX_TASKS: i32 = 8;

async fn checksum_impl() -> Result<String, ZakopaneError> {
    // *    Walk the target path.
    // *    If we can, then spawn a task, providing the current path
    //      in the walk and a cloned transmitter.
    // *    Call `poll_recv()` on the receiver repeatedly, updating
    //      our checksum map and `join()`ing the completed tasks.
    todo!()
}

#[allow(dead_code)]
fn checksum() -> Result<String, ZakopaneError> {
    let runtime = tokio::runtime::Runtime::new().unwrap();
    runtime.block_on(checksum_impl())
}
<commit_msg>checksum: Begin ChecksumTaskManager<commit_after>// Implements the `zakopane checksum` subcommand.

use crate::structs::ZakopaneError;

const MAX_TASKS: usize = 8;

#[derive(Default)]
struct ChecksumTaskManager {
    // Non-associative container enumerating paths and checksums.
    sums: std::vec::Vec<(String, String)>,

    // Map of outstanding checksum tasks.
    // *    Keys: absolute paths being checksummed
    // *    Values: tokio JoinHandles for checksum tasks
    tasks: std::collections::HashMap<String, tokio::task::JoinHandle<String>>,
}

async fn do_checksum(path: std::path::PathBuf) -> Result<String, ZakopaneError> {
    todo!()
}

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

    pub async fn spawn_task(&self, path: std::path::PathBuf) {
        assert!(
            self.tasks.len() < MAX_TASKS,
            "attempted to spawn too many tasks"
        );
        tokio::spawn(do_checksum(path));
    }
}

async fn checksum_impl() -> Result<String, ZakopaneError> {
    // *    Walk the target path.
    // *    If we can, then spawn a task, providing the current path
    //      in the walk and a cloned transmitter.
    // *    Call `poll_recv()` on the receiver repeatedly, updating
    //      our checksum map and `join()`ing the completed tasks.
    todo!()
}

#[allow(dead_code)]
fn checksum() -> Result<String, ZakopaneError> {
    let runtime = tokio::runtime::Runtime::new().unwrap();
    runtime.block_on(checksum_impl())
}
<|endoftext|>