<commit_before>use std::collections::HashMap;
use std::io::Write;

use serialize::json::ToJson;

use template::{Template, TemplateError};
use render::{Renderable, RenderError, RenderContext};
use helpers::{HelperDef};
use context::{Context};
use helpers;
use support::str::StringWriter;

pub struct Registry {
    templates: HashMap<String, Template>,
    helpers: HashMap<String, Box<HelperDef + 'static>>
}

impl Registry {
    pub fn new() -> Registry {
        let mut r = Registry {
            templates: HashMap::new(),
            helpers: HashMap::new()
        };

        r.register_helper("if", Box::new(helpers::IF_HELPER));
        r.register_helper("unless", Box::new(helpers::UNLESS_HELPER));
        r.register_helper("each", Box::new(helpers::EACH_HELPER));
        r.register_helper("with", Box::new(helpers::WITH_HELPER));
        r.register_helper("lookup", Box::new(helpers::LOOKUP_HELPER));
        r.register_helper("raw", Box::new(helpers::RAW_HELPER));
        r.register_helper(">", Box::new(helpers::INCLUDE_HELPER));
        r.register_helper("block", Box::new(helpers::BLOCK_HELPER));
        r.register_helper("partial", Box::new(helpers::PARTIAL_HELPER));
        r.register_helper("log", Box::new(helpers::LOG_HELPER));

        r
    }

    pub fn register_template(&mut self, name: &str, template: Template) {
        self.templates.insert(name.to_string(), template);
    }

    pub fn register_template_string(&mut self, name: &str, tpl_str: String) -> Result<(), TemplateError>{
        let t = Template::compile(tpl_str);
        if let Ok(tpl) = t {
            self.templates.insert(name.to_string(), tpl);
            Ok(())
        } else {
            Err(t.err().unwrap())
        }
    }

    pub fn unregister_template(&mut self, name: &String) {
        self.templates.remove(name);
    }

    pub fn register_helper(&mut self, name: &str, def: Box<HelperDef + 'static>) -> Option<Box<HelperDef + 'static>> {
        self.helpers.insert(name.to_string(), def)
    }

    pub fn get_template(&self, name: &String) -> Option<&Template> {
        self.templates.get(name)
    }

    pub fn get_helper(&self, name: &String) -> Option<&Box<HelperDef + 'static>> {
        self.helpers.get(name)
    }

    pub fn get_templates(&self) -> &HashMap<String, Template> {
        &self.templates
    }

    pub fn clear_templates(&mut self) {
        self.templates.clear();
    }

    pub fn render<T>(&self, name: &str, ctx: &T) -> Result<String, RenderError> where T: ToJson {
        let mut writer = StringWriter::new();
        {
            try!(self.renderw(name, ctx, &mut writer));
        }
        Ok(writer.to_string())
    }

    pub fn renderw<T>(&self, name: &str, ctx: &T, writer: &mut Write) -> Result<(), RenderError> where T: ToJson {
        let template = self.get_template(&name.to_string());
        let context = Context::wraps(ctx);

        if let Some(t) = template {
            let mut render_context = RenderContext::new(writer);
            (*t).render(&context, self, &mut render_context)
        } else {
            Err(RenderError{
                desc: "Template not found."
            })
        }
    }
}

#[cfg(test)]
mod test {
    use template::{Template};
    use registry::{Registry};
    use render::{RenderContext, Renderable, RenderError, Helper};
    use helpers::{HelperDef};
    use context::{Context};

    #[derive(Clone, Copy)]
    struct DummyHelper;

    impl HelperDef for DummyHelper {
        fn call(&self, c: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<(), RenderError> {
            try!(h.template().unwrap().render(c, r, rc));
            Ok(())
        }
    }

    static DUMMY_HELPER: DummyHelper = DummyHelper;

    #[test]
    fn test_registry_operations() {
        let mut r = Registry::new();

        let t = Template::compile("

".to_string()).ok().unwrap();
        r.register_template("index", t.clone());

        let t2 = Template::compile("

".to_string()).ok().unwrap();
        r.register_template("index2", t2.clone());

        assert_eq!((*r.get_template(&("index".to_string())).unwrap()).to_string(),
                   t.to_string());
        assert_eq!(r.templates.len(), 2);

        r.unregister_template(&("index".to_string()));
        assert_eq!(r.templates.len(), 1);

        r.clear_templates();
        assert_eq!(r.templates.len(), 0);

        r.register_helper("dummy", Box::new(DUMMY_HELPER));

        // built-in helpers plus 1
        assert_eq!(r.helpers.len(), 10+1);
    }
}
<commit_msg>(test) added test for renderw<commit_after>use std::collections::HashMap;
use std::io::Write;

use serialize::json::ToJson;

use template::{Template, TemplateError};
use render::{Renderable, RenderError, RenderContext};
use helpers::{HelperDef};
use context::{Context};
use helpers;
use support::str::StringWriter;

pub struct Registry {
    templates: HashMap<String, Template>,
    helpers: HashMap<String, Box<HelperDef + 'static>>
}

impl Registry {
    pub fn new() -> Registry {
        let mut r = Registry {
            templates: HashMap::new(),
            helpers: HashMap::new()
        };

        r.register_helper("if", Box::new(helpers::IF_HELPER));
        r.register_helper("unless", Box::new(helpers::UNLESS_HELPER));
        r.register_helper("each", Box::new(helpers::EACH_HELPER));
        r.register_helper("with", Box::new(helpers::WITH_HELPER));
        r.register_helper("lookup", Box::new(helpers::LOOKUP_HELPER));
        r.register_helper("raw", Box::new(helpers::RAW_HELPER));
        r.register_helper(">", Box::new(helpers::INCLUDE_HELPER));
        r.register_helper("block", Box::new(helpers::BLOCK_HELPER));
        r.register_helper("partial", Box::new(helpers::PARTIAL_HELPER));
        r.register_helper("log", Box::new(helpers::LOG_HELPER));

        r
    }

    pub fn register_template(&mut self, name: &str, template: Template) {
        self.templates.insert(name.to_string(), template);
    }

    pub fn register_template_string(&mut self, name: &str, tpl_str: String) -> Result<(), TemplateError>{
        let t = Template::compile(tpl_str);
        if let Ok(tpl) = t {
            self.templates.insert(name.to_string(), tpl);
            Ok(())
        } else {
            Err(t.err().unwrap())
        }
    }

    pub fn unregister_template(&mut self, name: &String) {
        self.templates.remove(name);
    }

    pub fn register_helper(&mut self, name: &str, def: Box<HelperDef + 'static>) -> Option<Box<HelperDef + 'static>> {
        self.helpers.insert(name.to_string(), def)
    }

    pub fn get_template(&self, name: &String) -> Option<&Template> {
        self.templates.get(name)
    }

    pub fn get_helper(&self, name: &String) -> Option<&Box<HelperDef + 'static>> {
        self.helpers.get(name)
    }

    pub fn get_templates(&self) -> &HashMap<String, Template> {
        &self.templates
    }

    pub fn clear_templates(&mut self) {
        self.templates.clear();
    }

    pub fn render<T>(&self, name: &str, ctx: &T) -> Result<String, RenderError> where T: ToJson {
        let mut writer = StringWriter::new();
        {
            try!(self.renderw(name, ctx, &mut writer));
        }
        Ok(writer.to_string())
    }

    pub fn renderw<T>(&self, name: &str, ctx: &T, writer: &mut Write) -> Result<(), RenderError> where T: ToJson {
        let template = self.get_template(&name.to_string());
        let context = Context::wraps(ctx);

        if let Some(t) = template {
            let mut render_context = RenderContext::new(writer);
            (*t).render(&context, self, &mut render_context)
        } else {
            Err(RenderError{
                desc: "Template not found."
            })
        }
    }
}

#[cfg(test)]
mod test {
    use serialize::json::Json;

    use template::{Template};
    use registry::{Registry};
    use render::{RenderContext, Renderable, RenderError, Helper};
    use helpers::{HelperDef};
    use context::{Context};
    use support::str::StringWriter;

    #[derive(Clone, Copy)]
    struct DummyHelper;

    impl HelperDef for DummyHelper {
        fn call(&self, c: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<(), RenderError> {
            try!(h.template().unwrap().render(c, r, rc));
            Ok(())
        }
    }

    static DUMMY_HELPER: DummyHelper = DummyHelper;

    #[test]
    fn test_registry_operations() {
        let mut r = Registry::new();

        let t = Template::compile("

".to_string()).ok().unwrap();
        r.register_template("index", t.clone());

        let t2 = Template::compile("

".to_string()).ok().unwrap();
        r.register_template("index2", t2.clone());

        assert_eq!((*r.get_template(&("index".to_string())).unwrap()).to_string(),
                   t.to_string());
        assert_eq!(r.templates.len(), 2);

        r.unregister_template(&("index".to_string()));
        assert_eq!(r.templates.len(), 1);

        r.clear_templates();
        assert_eq!(r.templates.len(), 0);

        r.register_helper("dummy", Box::new(DUMMY_HELPER));

        // built-in helpers plus 1
        assert_eq!(r.helpers.len(), 10+1);
    }

    #[test]
    fn test_renderw() {
        let mut r = Registry::new();

        let t = Template::compile("

".to_string()).ok().unwrap();
        r.register_template("index", t.clone());

        let mut sw = StringWriter::new();
        let data = Json::Null;

        {
            r.renderw("index", &data, &mut sw).ok().unwrap();
        }

        assert_eq!("

".to_string(), sw.to_string());

    }
}
<|endoftext|>


<commit_before>//! Handlers for the server.

use std::collections::BTreeMap;

use rustc_serialize::json::{Json, ToJson};
use serde_json;
use iron::prelude::*;
use iron::{status, headers, middleware};
use iron::modifiers::Header;
use router::Router;

use urlencoded;

use ::api;
use ::types::RedisPool;
use ::sensors;
use ::modifiers;

#[derive(Debug)]
struct ErrorResponse {
    reason: String,
}

impl ToJson for ErrorResponse {
    /// Serialize an ErrorResponse object into a proper JSON structure.
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("status".into(), "error".to_json());
        d.insert("reason".into(), self.reason.to_json());
        Json::Object(d)
    }
}

pub struct ReadHandler {
    status: api::Status,
    redis_pool: RedisPool,
    sensor_specs: sensors::SafeSensorSpecs,
    status_modifiers: Vec<Box<modifiers::StatusModifier>>,
}

impl ReadHandler {
    pub fn new(status: api::Status,
               redis_pool: RedisPool,
               sensor_specs: sensors::SafeSensorSpecs,
               status_modifiers: Vec<Box<modifiers::StatusModifier>>)
               -> ReadHandler {
        ReadHandler {
            status: status,
            redis_pool: redis_pool,
            sensor_specs: sensor_specs,
            status_modifiers: status_modifiers,
        }
    }

    fn build_response_json(&self) -> Json {

        // Create a mutable copy of the status struct
        let mut status_copy = self.status.clone();

        // Process registered sensors
        for sensor_spec in self.sensor_specs.lock().unwrap().iter() {

            match sensor_spec.get_sensor_value(self.redis_pool.clone()) {

                // Value could be read successfullly
                Ok(value) => {
                    if status_copy.sensors.is_none() {
                        status_copy.sensors = Some(api::Sensors {
                            people_now_present: None,
                            temperature: None,
                        });
                    }
                    sensor_spec.template.to_sensor(&value, &mut status_copy.sensors.as_mut().unwrap());
                },

                // Value could not be read, do error logging
                Err(err) => {
                    warn!("Could not retrieve key '{}' from Redis, omiting the sensor", &sensor_spec.data_key);
                    match err {
                        sensors::SensorError::Redis(e) => debug!("Error: {:?}", e),
                        sensors::SensorError::R2d2(e) => debug!("Error: {:?}", e),
                        sensors::SensorError::UnknownSensor(e) => warn!("Error: {:?}", e),
                    }
                },
            }
        }

        for status_modifier in self.status_modifiers.iter() {
            status_modifier.modify(&mut status_copy);
        }

        // Serialize to JSON
        // TODO this seems cumbersome
        let json_string = serde_json::to_string(&status_copy).unwrap();
        json_string.to_json()
    }
}

impl middleware::Handler for ReadHandler {

    /// Return the current status JSON.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        info!("{} /{} from {}", req.method, req.url.path()[0], req.remote_addr);

        // Get response body
        let body = self.build_response_json().to_string();

        // Create response
        let response = Response::with((status::Ok, body))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any));

        Ok(response)
    }

}

pub struct UpdateHandler {
    redis_pool: RedisPool,
    sensor_specs: sensors::SafeSensorSpecs,
}

impl UpdateHandler {
    pub fn new(redis_pool: RedisPool, sensor_specs: sensors::SafeSensorSpecs)
               -> UpdateHandler {
        UpdateHandler {
            redis_pool: redis_pool,
            sensor_specs: sensor_specs,
        }
    }

    /// Update sensor value in Redis
    fn update_sensor(&self, sensor: &str, value: &str) -> Result<(), sensors::SensorError> {
        // Validate sensor
        let sensor_specs = self.sensor_specs.lock().unwrap();
        let sensor_spec = try!(sensor_specs.iter()
                               .find(|&spec| spec.data_key == sensor)
                               .ok_or(sensors::SensorError::UnknownSensor(sensor.into())));

        // Store data
        sensor_spec.set_sensor_value(self.redis_pool.clone(), value)
    }

    /// Build an OK response with the `HTTP 204 No Content` status code.
    fn ok_response(&self) -> Response {
        Response::with((status::NoContent))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

    /// Build an error response with the specified `error_code` and the specified `reason` text.
    fn err_response(&self, error_code: status::Status, reason: &str) -> Response {
        let error = ErrorResponse { reason: reason.into() };
        Response::with((error_code, error.to_json().to_string()))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

}

impl middleware::Handler for UpdateHandler {

    /// Update the sensor, return correct status code.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        // TODO: create macro for these info! invocations.
        info!("{} /{} from {}", req.method, req.url.path()[0], req.remote_addr);

        // Get sensor name
        let sensor_name;
        {
            // TODO: Properly propagate errors
            let params = req.extensions.get::<Router>().unwrap();
            sensor_name = params.find("sensor").unwrap().to_string();
        }

        // Get sensor value
        let sensor_value;
        {
            let params = req.get_ref::<urlencoded::UrlEncodedBody>().unwrap();
            sensor_value = match params.get("value") {
                Some(ref values) =>  match values.len() {
                    1 => values[0].to_string(),
                    _ => return Ok(self.err_response(status::BadRequest, "Too many values specified")),
                },
                None => return Ok(self.err_response(status::BadRequest, "\"value\" parameter not specified")),
            }
        }

        // Update values in Redis
        if let Err(e) = self.update_sensor(&sensor_name, &sensor_value) {
            error!("Updating sensor value for sensor \"{}\" failed: {:?}", &sensor_name, e);
            let response = match e {
                sensors::SensorError::UnknownSensor(sensor) =>
                    self.err_response(status::BadRequest, &format!("Unknown sensor: {}", sensor)),
                sensors::SensorError::Redis(_) | sensors::SensorError::R2d2(_) =>
                    self.err_response(status::InternalServerError, "Updating values in datastore failed"),
            };
            return Ok(response)
        };

        // Create response
        Ok(self.ok_response())
    }

}
<commit_msg>Fix output of build_response_json<commit_after>//! Handlers for the server.

use std::collections::BTreeMap;

use rustc_serialize::json::{Json, ToJson};
use serde_json;
use iron::prelude::*;
use iron::{status, headers, middleware};
use iron::modifiers::Header;
use router::Router;

use urlencoded;

use ::api;
use ::types::RedisPool;
use ::sensors;
use ::modifiers;

#[derive(Debug)]
struct ErrorResponse {
    reason: String,
}

impl ToJson for ErrorResponse {
    /// Serialize an ErrorResponse object into a proper JSON structure.
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("status".into(), "error".to_json());
        d.insert("reason".into(), self.reason.to_json());
        Json::Object(d)
    }
}

pub struct ReadHandler {
    status: api::Status,
    redis_pool: RedisPool,
    sensor_specs: sensors::SafeSensorSpecs,
    status_modifiers: Vec<Box<modifiers::StatusModifier>>,
}

impl ReadHandler {
    pub fn new(status: api::Status,
               redis_pool: RedisPool,
               sensor_specs: sensors::SafeSensorSpecs,
               status_modifiers: Vec<Box<modifiers::StatusModifier>>)
               -> ReadHandler {
        ReadHandler {
            status: status,
            redis_pool: redis_pool,
            sensor_specs: sensor_specs,
            status_modifiers: status_modifiers,
        }
    }

    fn build_response_json(&self) -> String {

        // Create a mutable copy of the status struct
        let mut status_copy = self.status.clone();

        // Process registered sensors
        for sensor_spec in self.sensor_specs.lock().unwrap().iter() {

            match sensor_spec.get_sensor_value(self.redis_pool.clone()) {

                // Value could be read successfullly
                Ok(value) => {
                    if status_copy.sensors.is_none() {
                        status_copy.sensors = Some(api::Sensors {
                            people_now_present: None,
                            temperature: None,
                        });
                    }
                    sensor_spec.template.to_sensor(&value, &mut status_copy.sensors.as_mut().unwrap());
                },

                // Value could not be read, do error logging
                Err(err) => {
                    warn!("Could not retrieve key '{}' from Redis, omiting the sensor", &sensor_spec.data_key);
                    match err {
                        sensors::SensorError::Redis(e) => debug!("Error: {:?}", e),
                        sensors::SensorError::R2d2(e) => debug!("Error: {:?}", e),
                        sensors::SensorError::UnknownSensor(e) => warn!("Error: {:?}", e),
                    }
                },
            }
        }

        for status_modifier in self.status_modifiers.iter() {
            status_modifier.modify(&mut status_copy);
        }

        // Serialize to JSON
        // TODO Using unwrap may be unsound here
        serde_json::to_string(&status_copy).unwrap()
    }
}

impl middleware::Handler for ReadHandler {

    /// Return the current status JSON.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        info!("{} /{} from {}", req.method, req.url.path()[0], req.remote_addr);

        // Get response body
        let body = self.build_response_json();

        // Create response
        let response = Response::with((status::Ok, body))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any));

        Ok(response)
    }

}

pub struct UpdateHandler {
    redis_pool: RedisPool,
    sensor_specs: sensors::SafeSensorSpecs,
}

impl UpdateHandler {
    pub fn new(redis_pool: RedisPool, sensor_specs: sensors::SafeSensorSpecs)
               -> UpdateHandler {
        UpdateHandler {
            redis_pool: redis_pool,
            sensor_specs: sensor_specs,
        }
    }

    /// Update sensor value in Redis
    fn update_sensor(&self, sensor: &str, value: &str) -> Result<(), sensors::SensorError> {
        // Validate sensor
        let sensor_specs = self.sensor_specs.lock().unwrap();
        let sensor_spec = try!(sensor_specs.iter()
                               .find(|&spec| spec.data_key == sensor)
                               .ok_or(sensors::SensorError::UnknownSensor(sensor.into())));

        // Store data
        sensor_spec.set_sensor_value(self.redis_pool.clone(), value)
    }

    /// Build an OK response with the `HTTP 204 No Content` status code.
    fn ok_response(&self) -> Response {
        Response::with((status::NoContent))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

    /// Build an error response with the specified `error_code` and the specified `reason` text.
    fn err_response(&self, error_code: status::Status, reason: &str) -> Response {
        let error = ErrorResponse { reason: reason.into() };
        Response::with((error_code, error.to_json().to_string()))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

}

impl middleware::Handler for UpdateHandler {

    /// Update the sensor, return correct status code.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        // TODO: create macro for these info! invocations.
        info!("{} /{} from {}", req.method, req.url.path()[0], req.remote_addr);

        // Get sensor name
        let sensor_name;
        {
            // TODO: Properly propagate errors
            let params = req.extensions.get::<Router>().unwrap();
            sensor_name = params.find("sensor").unwrap().to_string();
        }

        // Get sensor value
        let sensor_value;
        {
            let params = req.get_ref::<urlencoded::UrlEncodedBody>().unwrap();
            sensor_value = match params.get("value") {
                Some(ref values) =>  match values.len() {
                    1 => values[0].to_string(),
                    _ => return Ok(self.err_response(status::BadRequest, "Too many values specified")),
                },
                None => return Ok(self.err_response(status::BadRequest, "\"value\" parameter not specified")),
            }
        }

        // Update values in Redis
        if let Err(e) = self.update_sensor(&sensor_name, &sensor_value) {
            error!("Updating sensor value for sensor \"{}\" failed: {:?}", &sensor_name, e);
            let response = match e {
                sensors::SensorError::UnknownSensor(sensor) =>
                    self.err_response(status::BadRequest, &format!("Unknown sensor: {}", sensor)),
                sensors::SensorError::Redis(_) | sensors::SensorError::R2d2(_) =>
                    self.err_response(status::InternalServerError, "Updating values in datastore failed"),
            };
            return Ok(response)
        };

        // Create response
        Ok(self.ok_response())
    }

}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use super::bls::{
    AggregateSignature,
    AggregatePublicKey,
};
use super::db::ClientDB;
use super::db::stores::{
    ValidatorStore,
    StoreError,
};
use super::utils::types::Bitfield;

#[derive(Debug, PartialEq)]
pub enum SignatureVerificationError {
    BadValidatorIndex,
    PublicKeyCorrupt,
    NoPublicKeyForValidator,
    DBError(String),
}

fn verify_aggregate_signature_for_indices<T>(message: &[u8],
                                             agg_sig: &AggregateSignature,
                                             attestation_indices: &[usize],
                                             bitfield: &Bitfield,
                                             validator_store: &ValidatorStore<T>)
    -> Result<(bool, HashSet<usize>), SignatureVerificationError>
    where T: ClientDB + Sized
{
    let mut voters = HashSet::new();
    let mut agg_pub_key = AggregatePublicKey::new();

    for i in 0..attestation_indices.len() {
        let voted = bitfield.get_bit(i);
        if voted {
            let validator = attestation_indices[i];
            let pub_key = validator_store.get_public_key_by_index(i)?
                .ok_or(SignatureVerificationError::NoPublicKeyForValidator)?;
            agg_pub_key.add(&pub_key);
            voters.insert(validator);
        }
    }
    Ok((agg_sig.verify(&message, &agg_pub_key),
        voters))
}

impl From<StoreError> for SignatureVerificationError {
    fn from(error: StoreError) -> Self {
        match error {
            StoreError::DBError(s) =>
                SignatureVerificationError::DBError(s),
            StoreError::DecodeError =>
                SignatureVerificationError::PublicKeyCorrupt,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::bls::{
        Keypair,
        Signature,
    };
    use super::super::db::MemoryDB;
    use std::sync::Arc;

    #[test]
    fn test_signature_verification() {
        let message = "cats".as_bytes();
        let signing_keypairs = vec![
            Keypair::random(),
            Keypair::random(),
            Keypair::random(),
            Keypair::random(),
            Keypair::random(),
            Keypair::random(),
        ];
        let non_signing_keypairs = vec![
            Keypair::random(),
            Keypair::random(),
            Keypair::random(),
            Keypair::random(),
            Keypair::random(),
            Keypair::random(),
        ];
        /*
         * Signing keypairs first, then non-signing
         */
        let mut all_keypairs = signing_keypairs.clone();
        all_keypairs.append(&mut non_signing_keypairs.clone());

        let attestation_indices: Vec<usize> = (0..all_keypairs.len())
            .collect();
        let mut bitfield = Bitfield::new();
        for i in 0..signing_keypairs.len() {
            bitfield.set_bit(i, true);
        }

        let db = Arc::new(MemoryDB::open());
        let store = ValidatorStore::new(db);

        for (i, keypair) in all_keypairs.iter().enumerate() {
            store.put_public_key_by_index(i, &keypair.pk).unwrap();
        }

        let mut agg_sig = AggregateSignature::new();
        for keypair in &signing_keypairs {
            let sig = Signature::new(&message, &keypair.sk);
            agg_sig.add(&sig);
        }

        let (is_valid, voters) = verify_aggregate_signature_for_indices(
            &message,
            &agg_sig,
            &attestation_indices,
            &bitfield,
            &store).unwrap();

        assert_eq!(is_valid, true);
        (0..signing_keypairs.len())
            .for_each(|i| assert!(voters.contains(&i)));
        (signing_keypairs.len()..non_signing_keypairs.len())
            .for_each(|i| assert!(!voters.contains(&i)));
    }
}
<commit_msg>Extend tests for signature verification<commit_after>use std::collections::HashSet;
use super::bls::{
    AggregateSignature,
    AggregatePublicKey,
};
use super::db::ClientDB;
use super::db::stores::{
    ValidatorStore,
    StoreError,
};
use super::utils::types::Bitfield;

#[derive(Debug, PartialEq)]
pub enum SignatureVerificationError {
    BadValidatorIndex,
    PublicKeyCorrupt,
    NoPublicKeyForValidator,
    DBError(String),
}

fn verify_aggregate_signature_for_indices<T>(message: &[u8],
                                             agg_sig: &AggregateSignature,
                                             attestation_indices: &[usize],
                                             bitfield: &Bitfield,
                                             validator_store: &ValidatorStore<T>)
    -> Result<(bool, Option<HashSet<usize>>), SignatureVerificationError>
    where T: ClientDB + Sized
{
    let mut voters = HashSet::new();
    let mut agg_pub_key = AggregatePublicKey::new();

    for i in 0..attestation_indices.len() {
        let voted = bitfield.get_bit(i);
        if voted {
            let validator = attestation_indices[i];
            let pub_key = validator_store.get_public_key_by_index(i)?
                .ok_or(SignatureVerificationError::NoPublicKeyForValidator)?;
            agg_pub_key.add(&pub_key);
            voters.insert(validator);
        }
    }
    if agg_sig.verify(&message, &agg_pub_key) {
        Ok((true, Some(voters)))
    } else {
        Ok((false, None))
    }
}

impl From<StoreError> for SignatureVerificationError {
    fn from(error: StoreError) -> Self {
        match error {
            StoreError::DBError(s) =>
                SignatureVerificationError::DBError(s),
            StoreError::DecodeError =>
                SignatureVerificationError::PublicKeyCorrupt,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::bls::{
        Keypair,
        Signature,
    };
    use super::super::db::MemoryDB;
    use std::sync::Arc;

    #[test]
    fn test_signature_verification() {
        let message = "cats".as_bytes();
        let signing_keypairs = vec![
            Keypair::random(),
            Keypair::random(),
            Keypair::random(),
            Keypair::random(),
            Keypair::random(),
            Keypair::random(),
        ];
        let non_signing_keypairs = vec![
            Keypair::random(),
            Keypair::random(),
            Keypair::random(),
            Keypair::random(),
            Keypair::random(),
            Keypair::random(),
        ];
        /*
         * Signing keypairs first, then non-signing
         */
        let mut all_keypairs = signing_keypairs.clone();
        all_keypairs.append(&mut non_signing_keypairs.clone());

        let attestation_indices: Vec<usize> = (0..all_keypairs.len())
            .collect();
        let mut bitfield = Bitfield::new();
        for i in 0..signing_keypairs.len() {
            bitfield.set_bit(i, true);
        }

        let db = Arc::new(MemoryDB::open());
        let store = ValidatorStore::new(db);

        for (i, keypair) in all_keypairs.iter().enumerate() {
            store.put_public_key_by_index(i, &keypair.pk).unwrap();
        }

        let mut agg_sig = AggregateSignature::new();
        for keypair in &signing_keypairs {
            let sig = Signature::new(&message, &keypair.sk);
            agg_sig.add(&sig);
        }

        /*
         * Test using all valid parameters.
         */
        let (is_valid, voters) = verify_aggregate_signature_for_indices(
            &message,
            &agg_sig,
            &attestation_indices,
            &bitfield,
            &store).unwrap();

        let voters = voters.unwrap();
        assert_eq!(is_valid, true);
        (0..signing_keypairs.len())
            .for_each(|i| assert!(voters.contains(&i)));
        (signing_keypairs.len()..non_signing_keypairs.len())
            .for_each(|i| assert!(!voters.contains(&i)));

        /*
         * Add another validator to the bitfield, run validation will all other
         * parameters the same and assert that it fails.
         */
        bitfield.set_bit(signing_keypairs.len() + 1, true);
        let (is_valid, voters) = verify_aggregate_signature_for_indices(
            &message,
            &agg_sig,
            &attestation_indices,
            &bitfield,
            &store).unwrap();

        assert_eq!(is_valid, false);
        assert_eq!(voters, None);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 Richard Diamond & contributors.
//
// This file is part of the Rust PPApi project.
//
// 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/.

extern crate pnacl_build_helper as helper;

pub fn main() {
    let mut a = helper::Archive::new("helper");
    a.cxx("src/libhelper/helper.cpp", &["-Os".to_string()]);
    a.archive();
}
<commit_msg>Print toolchain lib paths.<commit_after>// Copyright (c) 2014 Richard Diamond & contributors.
//
// This file is part of the Rust PPApi project.
//
// 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/.

extern crate pnacl_build_helper as helper;

pub fn main() {
    let mut a = helper::Archive::new("helper");
    a.cxx("src/libhelper/helper.cpp", &["-Os".to_string()]);
    a.archive();
    helper::print_lib_paths();
}
<|endoftext|>


<commit_before>use termion::color;
use std::str::FromStr;
use std::fmt;
use rand::{Rng, thread_rng};
use std::slice::Iter;
use std::collections::HashMap;
use atty;

#[derive(Debug, Clone, Copy)]
#[repr(usize)]
pub enum ColorMode {
    Plain = 0,
    RedBlack = 1,
    Unique = 2
}

static mut SUIT_COLOR_MODE: ColorMode = ColorMode::Unique;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Color {
    Black,
    Red
}

#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Suit {
    Clubs = 0,
    Diamonds = 1,
    Hearts = 2,
    Spades = 3
}

static ALL_SUITS: [Suit; 4] = [Suit::Clubs, Suit::Diamonds, Suit::Hearts, Suit::Spades];

impl Suit {
    /// iterate through all elements of suit
    pub fn iterator() -> Iter<'static, Suit> {
        ALL_SUITS.into_iter()
    }

    pub fn color(&self) -> Color {
        match *self {
            Suit::Diamonds | Suit::Hearts => Color::Red,
            _ => Color::Black
        }
    }

    pub fn ord(&self) -> u8 {
        *self as u8
    }
}

impl Into<Suit> for u8 {
    fn into(self) -> Suit {
        ALL_SUITS[self as usize]
    }
}

#[derive(Debug)]
pub enum CardParseError {
    BadSuit,
    BadRank
}

impl FromStr for Suit {
    type Err = CardParseError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use Suit::*;
        use self::CardParseError::*;
        match s {
            "♣" => Ok(Clubs),
            "♦" => Ok(Diamonds),
            "♥" => Ok(Hearts),
            "♠" => Ok(Spades),
            _ => Err(BadSuit)
        }
    }
}

impl fmt::Display for Suit {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Suit::*;

        lazy_static! {
            static ref RED: String = format!("{}", color::Fg(color::Red));
            static ref GREEN: String = format!("{}", color::Fg(color::Green));
            static ref BLUE: String = format!("{}", color::Fg(color::Blue));
            static ref RESET: String = format!("{}", color::Fg(color::Reset));
        }

        let (begin, end) = unsafe {
            match SUIT_COLOR_MODE {
                ColorMode::Plain => ("", ""),
                ColorMode::RedBlack => match self.color() {
                    Color::Red => (RED.as_str(), RESET.as_str()),
                    _ => ("", "")
                },
                ColorMode::Unique => match *self {
                    Clubs => (GREEN.as_str(), RESET.as_str()),
                    Hearts => (RED.as_str(), RESET.as_str()),
                    Diamonds => (BLUE.as_str(), RESET.as_str()),
                    _ => ("", "")
                }
            }
        };

        write!(f, "{}{}{}", begin, match *self {
            Clubs => "♣",
            Diamonds => "♦",
            Hearts => "♥",
            Spades => "♠"
        }, end)
    }
}

#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Rank {
    Two = 0,
    Three = 1,
    Four = 2,
    Five = 3,
    Six = 4,
    Seven = 5,
    Eight = 6,
    Nine = 7,
    Ten = 8,
    Jack = 9,
    Queen = 10,
    King = 11,
    Ace = 12
}

static ALL_RANKS: [Rank;  13] = [Rank::Two, Rank::Three, Rank::Four,
                             Rank::Five, Rank::Six, Rank::Seven,
                             Rank::Eight, Rank::Nine, Rank::Ten,
                             Rank::Jack, Rank::Queen, Rank::King, Rank::Ace];

impl Rank {
    pub fn iterator() -> Iter<'static, Rank> {
        ALL_RANKS.into_iter()
    }
    /// Assign numerical values to each rank, with ace as high
    pub fn ord_ace_high(&self) -> u8 {
        *self as u8
    }

    /// Assign numerical values to each rank, with ace as low
    pub fn ord_ace_low(&self) -> u8 {
        use Rank::*;
        match *self {
            Ace => 1,
            x => x as u8
        }
    }
}

impl Into<Rank> for u8 {
    fn into(self) -> Rank {
        ALL_RANKS[self as usize]
    }
}

impl FromStr for Rank {
    type Err = CardParseError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use Rank::*;
        use self::CardParseError::*;
        match s {
            "2" => Ok(Two),
            "3" => Ok(Three),
            "4" => Ok(Four),
            "5" => Ok(Five),
            "6" => Ok(Six),
            "7" => Ok(Seven),
            "8" => Ok(Eight),
            "9" => Ok(Nine),
            "T" => Ok(Ten),
            "J" => Ok(Jack),
            "Q" => Ok(Queen),
            "K" => Ok(King),
            "A" => Ok(Ace),
            _ => Err(BadRank)
        }
    }
}

impl fmt::Display for Rank {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Rank::*;
        write!(f, "{}", match *self {
            Two => "2",
            Three => "3",
            Four => "4",
            Five => "5",
            Six => "6",
            Seven => "7",
            Eight => "8",
            Nine => "9",
            Ten => "T",
            Jack => "J",
            Queen => "Q",
            King => "K",
            Ace => "A"
        })
    }
}

/// Normal non-joker playing card
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct BasicCard {
    pub rank: Rank,
    pub suit: Suit
}

impl BasicCard {
    /// Returns a Vec of all 52 possible `BasicCard`s, in
    /// some unspecified order.
    pub fn all() -> Vec<BasicCard> {
        use Suit::*;

        let mut cards = Vec::with_capacity(52);
        for rank in Rank::iterator() {
            for suit in &[Clubs, Diamonds, Hearts, Spades] {
                cards.push(BasicCard { rank: *rank, suit: *suit })
            }
        }

        cards
    }
}

impl FromStr for BasicCard {
    type Err = CardParseError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let (rank_str, suit_str) = s.split_at(1);
        let rank = rank_str.parse()?;
        let suit = suit_str.parse()?;
        Ok(BasicCard { rank, suit })
    }
}

impl Into<u8> for BasicCard {
    fn into(self) -> u8 {
        self.rank as u8  + 13 * (self.suit as u8)
    }
}

impl fmt::Display for BasicCard {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}{}", self.rank, self.suit)
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Card {
    Basic(BasicCard),
    BigJoker,
    SmallJoker
}

impl fmt::Display for Card {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Card::*;
        match self {
            &BigJoker => write!(f, "JJ"),
            &SmallJoker => write!(f, "jj"),
            &Card::Basic(ref basic) => write!(f, "{}", basic)
        }
    }
}

pub const NUM_BASIC_CARDS: usize = 52;

/// Deck of 52 basic (non-joker) cards
#[derive(Debug)]
pub struct BasicDeck {
    cards: Vec<BasicCard>
}

impl BasicDeck {
    pub fn new() -> BasicDeck {
        BasicDeck { cards: BasicCard::all() }
    }

    /// Shuffle the remaining cards in the deck
    pub fn shuffle(&mut self) {
        let mut rng = thread_rng();
        rng.shuffle(&mut self.cards)
    }

    pub fn num_cards_left(&self) -> usize {
        self.cards.len()
    }

    /// Return the top card from the deck, if there are any cards
    pub fn draw(&mut self) -> Option<BasicCard> {
        self.cards.pop()
    }

    /// Return the top n cards from the deck, if there are n
    /// cards. Otherwise, return None.
    ///
    /// # Remarks
    ///
    /// If this function returns `Some`, there will be
    /// exactly `n` cards.
    pub fn draw_n(&mut self, n: usize) -> Option<Vec<BasicCard>> {
        let m = self.cards.len();
        if m >= n {
            Some(self.cards.split_off(m - n))
        } else {
            None
        }
    }

}

/// Print some value for each card in a hashmap.
pub fn print_card_map<T: fmt::Display>(map: &HashMap<BasicCard, T>) {
    let col_head = "+-----------".to_string().repeat(4);
    println!("{}+", &col_head);

    for rank in Rank::iterator() {
        print!("| ");

        for suit in Suit::iterator() {
            let bc = BasicCard { rank: *rank, suit: *suit };
            print!("{}{}: {:5}", rank, suit, *map.get(&bc).unwrap());
            print!(" | ");
        }
        println!("");
    }
    println!("{}+", &col_head);
}

pub fn auto_suit_colors() {
    unsafe {
        SUIT_COLOR_MODE = if atty::is(atty::Stream::Stdout) {
            ColorMode::Unique
        } else {
            ColorMode::Plain
        }
    }
}

pub mod prelude {
    pub use super::{BasicCard, Suit, Rank, auto_suit_colors, print_card_map};
}
<commit_msg>cards: Suit/Rank/BasicCard conversions<commit_after>use termion::color;
use std::str::FromStr;
use std::fmt;
use rand::{Rng, thread_rng};
use std::slice::Iter;
use std::collections::HashMap;
use atty;

#[derive(Debug, Clone, Copy)]
#[repr(usize)]
pub enum ColorMode {
    Plain = 0,
    RedBlack = 1,
    Unique = 2
}

static mut SUIT_COLOR_MODE: ColorMode = ColorMode::Unique;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Color {
    Black,
    Red
}

#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Suit {
    Clubs = 0,
    Diamonds = 1,
    Hearts = 2,
    Spades = 3
}

static ALL_SUITS: [Suit; 4] = [Suit::Clubs, Suit::Diamonds, Suit::Hearts, Suit::Spades];

impl Suit {
    /// iterate through all elements of suit
    pub fn iterator() -> Iter<'static, Suit> {
        ALL_SUITS.into_iter()
    }

    pub fn color(&self) -> Color {
        match *self {
            Suit::Diamonds | Suit::Hearts => Color::Red,
            _ => Color::Black
        }
    }

    pub fn ord(&self) -> u8 {
        *self as u8
    }
}

impl Into<Suit> for u8 {
    fn into(self) -> Suit {
        ALL_SUITS[self as usize]
    }
}

#[derive(Debug)]
pub enum CardParseError {
    BadSuit,
    BadRank
}

impl FromStr for Suit {
    type Err = CardParseError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use Suit::*;
        use self::CardParseError::*;
        match s {
            "♣" => Ok(Clubs),
            "♦" => Ok(Diamonds),
            "♥" => Ok(Hearts),
            "♠" => Ok(Spades),
            _ => Err(BadSuit)
        }
    }
}

impl fmt::Display for Suit {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Suit::*;

        lazy_static! {
            static ref RED: String = format!("{}", color::Fg(color::Red));
            static ref GREEN: String = format!("{}", color::Fg(color::Green));
            static ref BLUE: String = format!("{}", color::Fg(color::Blue));
            static ref RESET: String = format!("{}", color::Fg(color::Reset));
        }

        let (begin, end) = unsafe {
            match SUIT_COLOR_MODE {
                ColorMode::Plain => ("", ""),
                ColorMode::RedBlack => match self.color() {
                    Color::Red => (RED.as_str(), RESET.as_str()),
                    _ => ("", "")
                },
                ColorMode::Unique => match *self {
                    Clubs => (GREEN.as_str(), RESET.as_str()),
                    Hearts => (RED.as_str(), RESET.as_str()),
                    Diamonds => (BLUE.as_str(), RESET.as_str()),
                    _ => ("", "")
                }
            }
        };

        write!(f, "{}{}{}", begin, match *self {
            Clubs => "♣",
            Diamonds => "♦",
            Hearts => "♥",
            Spades => "♠"
        }, end)
    }
}

#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Rank {
    Two = 0,
    Three = 1,
    Four = 2,
    Five = 3,
    Six = 4,
    Seven = 5,
    Eight = 6,
    Nine = 7,
    Ten = 8,
    Jack = 9,
    Queen = 10,
    King = 11,
    Ace = 12
}

static ALL_RANKS: [Rank;  13] = [Rank::Two, Rank::Three, Rank::Four,
                                 Rank::Five, Rank::Six, Rank::Seven,
                                 Rank::Eight, Rank::Nine, Rank::Ten,
                                 Rank::Jack, Rank::Queen, Rank::King, Rank::Ace];

impl Rank {
    pub fn iterator() -> Iter<'static, Rank> {
        ALL_RANKS.into_iter()
    }
    /// Assign numerical values to each rank, with ace as high
    pub fn ord_ace_high(&self) -> u8 {
        *self as u8
    }

    /// Assign numerical values to each rank, with ace as low
    pub fn ord_ace_low(&self) -> u8 {
        use Rank::*;
        match *self {
            Ace => 1,
            x => x as u8
        }
    }
}

impl Into<Rank> for u8 {
    fn into(self) -> Rank {
        ALL_RANKS[self as usize]
    }
}

impl FromStr for Rank {
    type Err = CardParseError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use Rank::*;
        use self::CardParseError::*;
        match s {
            "2" => Ok(Two),
            "3" => Ok(Three),
            "4" => Ok(Four),
            "5" => Ok(Five),
            "6" => Ok(Six),
            "7" => Ok(Seven),
            "8" => Ok(Eight),
            "9" => Ok(Nine),
            "T" => Ok(Ten),
            "J" => Ok(Jack),
            "Q" => Ok(Queen),
            "K" => Ok(King),
            "A" => Ok(Ace),
            _ => Err(BadRank)
        }
    }
}

impl fmt::Display for Rank {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Rank::*;
        write!(f, "{}", match *self {
            Two => "2",
            Three => "3",
            Four => "4",
            Five => "5",
            Six => "6",
            Seven => "7",
            Eight => "8",
            Nine => "9",
            Ten => "T",
            Jack => "J",
            Queen => "Q",
            King => "K",
            Ace => "A"
        })
    }
}

/// Normal non-joker playing card
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct BasicCard {
    pub rank: Rank,
    pub suit: Suit
}

impl BasicCard {
    /// Returns a Vec of all 52 possible `BasicCard`s, in
    /// some unspecified order.
    pub fn all() -> Vec<BasicCard> {
        use Suit::*;

        let mut cards = Vec::with_capacity(52);
        for rank in Rank::iterator() {
            for suit in &[Clubs, Diamonds, Hearts, Spades] {
                cards.push(BasicCard { rank: *rank, suit: *suit })
            }
        }

        cards
    }
}

impl FromStr for BasicCard {
    type Err = CardParseError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let (rank_str, suit_str) = s.split_at(1);
        let rank = rank_str.parse()?;
        let suit = suit_str.parse()?;
        Ok(BasicCard { rank, suit })
    }
}

impl From<u8> for BasicCard {
    fn from(s: u8) -> Self {
        BasicCard{ rank: (s / 13).into(), suit: (s % 13).into() }
    }
}

impl From<BasicCard> for u8 {
    fn from(s: BasicCard) -> Self {
        s.rank as u8  + 13 * (s.suit as u8)
    }
}
impl<'a> From<&'a BasicCard> for u8 {
    fn from(s: &BasicCard) -> Self {
        s.rank as u8  + 13 * (s.suit as u8)
    }
}

impl fmt::Display for BasicCard {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}{}", self.rank, self.suit)
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Card {
    Basic(BasicCard),
    BigJoker,
    SmallJoker
}

impl fmt::Display for Card {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Card::*;
        match self {
            &BigJoker => write!(f, "JJ"),
            &SmallJoker => write!(f, "jj"),
            &Card::Basic(ref basic) => write!(f, "{}", basic)
        }
    }
}

pub const NUM_BASIC_CARDS: usize = 52;
pub const INUM_BASIC_CARDS: isize = 52;

/// Deck of 52 basic (non-joker) cards
#[derive(Debug)]
pub struct BasicDeck {
    cards: Vec<BasicCard>
}

impl BasicDeck {
    pub fn new() -> BasicDeck {
        BasicDeck { cards: BasicCard::all() }
    }

    /// Shuffle the remaining cards in the deck
    pub fn shuffle(&mut self) {
        let mut rng = thread_rng();
        rng.shuffle(&mut self.cards)
    }

    pub fn num_cards_left(&self) -> usize {
        self.cards.len()
    }

    /// Return the top card from the deck, if there are any cards
    pub fn draw(&mut self) -> Option<BasicCard> {
        self.cards.pop()
    }

    /// Return the top n cards from the deck, if there are n
    /// cards. Otherwise, return None.
    ///
    /// # Remarks
    ///
    /// If this function returns `Some`, there will be
    /// exactly `n` cards.
    pub fn draw_n(&mut self, n: usize) -> Option<Vec<BasicCard>> {
        let m = self.cards.len();
        if m >= n {
            Some(self.cards.split_off(m - n))
        } else {
            None
        }
    }
}

// #[derive(Debug, Clone)]
// pub struct BasicHand {
//     hand: u64
// }

// impl BasicHand {
//     pub fn new() -> BasicHand {
//         BasicHand { hand: 0 }
//     }

//     pub fn contains(&self, card: &BasicCard) -> bool {
//         let c: u8 = card.into();
//         (self.hand & (1u64 << c)) != 0
//     }

//     pub fn insert(&mut self, card: &BasicCard) {
//         let c: u8 = card.into();
//         self.hand |= 1u64 << c;
//     }

//     pub fn remove(&mut self, card: &BasicCard) {
//         let c: u8 = card.into();
//         self.hand &= !(1u64 << c);
//     }

//     pub fn
// }

/// Print some value for each card in a hashmap.
pub fn print_card_map<T: fmt::Display>(map: &HashMap<BasicCard, T>) {
    let col_head = "+-----------".to_string().repeat(4);
    println!("{}+", &col_head);

    for rank in Rank::iterator() {
        print!("| ");

        for suit in Suit::iterator() {
            let bc = BasicCard { rank: *rank, suit: *suit };
            print!("{}{}: {:5}", rank, suit, *map.get(&bc).unwrap());
            print!(" | ");
        }
        println!("");
    }
    println!("{}+", &col_head);
}

pub fn auto_suit_colors() {
    unsafe {
        SUIT_COLOR_MODE = if atty::is(atty::Stream::Stdout) {
            ColorMode::Unique
        } else {
            ColorMode::Plain
        }
    }
}

pub mod prelude {
    pub use super::{BasicCard, Suit, Rank, auto_suit_colors, print_card_map, NUM_BASIC_CARDS, INUM_BASIC_CARDS};
}
<|endoftext|>


<commit_before>// Working with subcommands is simple. There are a few key points to remember when working with
// subcommands in clap. First, Subcommands are really just Apps. This means they can have their own
// settings, version, authors, args, and even their own subcommands. The next thing to remember is
// that subcommands are set up in a tree like hierarchy.
//
// An ASCII art depiction may help explain this better. Using a fictional version of git as the demo
// subject. Imagine the following are all subcommands of git (note, the author is aware these aren't
// actually all subcommands in the real git interface, but it makes explanation easier)
//
//            Top Level App (git)                         TOP
//                           |
//    -----------------------------------------
//   /             |                \          \
// clone          push              add       commit      LEVEL 1
//   |           /    \            /    \       |
//  url      origin   remote    ref    name   message     LEVEL 2
//           /                  /\
//        path            remote  local                   LEVEL 3
//
// Given the above fictional subcommand hierarchy, valid runtime uses would be (not an all inclusive
// list):
//
// $ git clone url
// $ git push origin path
// $ git add ref local
// $ git commit message
//
// Notice only one command per "level" may be used. You could not, for example, do:
//
// $ git clone url push origin path
//
// It's also important to know that subcommands each have their own set of matches and may have args
// with the same name as other subcommands in a different part of the tree hierarchy (i.e. the arg
// names aren't in a flat namespace).
//
// In order to use subcommands in clap, you only need to know which subcommand you're at in your
// tree, and which args are defined on that subcommand.
//
// Let's make a quick program to illustrate. We'll be using the same example as above but for
// brevity sake we won't implement all of the subcommands, only a few.

use clap::{App, AppSettings, Arg};

fn main() {
    let matches = App::new("git")
        .about("A fictional versioning CLI")
        .version("1.0")
        .author("Me")
        .subcommand(
            App::new("clone")
                .about("clones repos")
                .arg(Arg::new("repo").about("The repo to clone").required(true)),
        )
        .subcommand(
            App::new("push")
                .about("pushes things")
                .setting(AppSettings::SubcommandRequiredElseHelp)
                .subcommand(
                    App::new("remote") // Subcommands can have their own subcommands,
                        // which in turn have their own subcommands
                        .about("pushes remote things")
                        .arg(
                            Arg::new("repo")
                                .required(true)
                                .about("The remote repo to push things to"),
                        ),
                )
                .subcommand(App::new("local").about("pushes local things")),
        )
        .subcommand(
            App::new("add")
                .about("adds things")
                .author("Someone Else") // Subcommands can list different authors
                .version("v2.0 (I'm versioned differently") // or different version from their parents
                .setting(AppSettings::ArgRequiredElseHelp) // They can even have different settings
                .arg(
                    Arg::new("stuff")
                        .long("stuff")
                        .about("Stuff to add")
                        .takes_value(true)
                        .multiple_occurrences(true),
                ),
        )
        .get_matches();

    // At this point, the matches we have point to git. Keep this in mind...

    // You can see which subcommand was used
    if let Some(subcommand) = matches.subcommand_name() {
        println!("'git {}' was used", subcommand);

        // It's important to note, this *only* check's git's DIRECT children, **NOT** it's
        // grandchildren, great grandchildren, etc.
        //
        // i.e. if the command `git push remove --stuff foo` was run, the above will only print out,
        // `git push` was used. We'd need to get push's matches to see further into the tree
    }

    // An alternative to checking the name is matching on known names. Again notice that only the
    // direct children are matched here.
    match matches.subcommand_name() {
        Some("clone") => println!("'git clone' was used"),
        Some("push") => println!("'git push' was used"),
        Some("add") => println!("'git add' was used"),
        None => println!("No subcommand was used"),
        _ => unreachable!(), // Assuming you've listed all direct children above, this is unreachable
    }

    // You could get the independent subcommand matches, although this is less common
    if let Some(clone_matches) = matches.subcommand_matches("clone") {
        // Now we have a reference to clone's matches
        println!("Cloning repo: {}", clone_matches.value_of("repo").unwrap());
    }

    // The most common way to handle subcommands is via a combined approach using
    // `ArgMatches::subcommand` which returns a tuple of both the name and matches
    match matches.subcommand() {
        Some(("clone", clone_matches)) => {
            // Now we have a reference to clone's matches
            println!("Cloning {}", clone_matches.value_of("repo").unwrap());
        }
        Some(("push", push_matches)) => {
            // Now we have a reference to push's matches
            match push_matches.subcommand() {
                Some(("remote", remote_matches)) => {
                    // Now we have a reference to remote's matches
                    println!("Pushing to {}", remote_matches.value_of("repo").unwrap());
                }
                Some(("local", _)) => {
                    println!("'git push local' was used");
                }
                _ => unreachable!(),
            }
        }
        Some(("add", add_matches)) => {
            // Now we have a reference to add's matches
            println!(
                "Adding {}",
                add_matches
                    .values_of("stuff")
                    .unwrap()
                    .collect::<Vec<_>>()
                    .join(", ")
            );
        }
        None => println!("No subcommand was used"), // If no subcommand was used it'll match the tuple ("", None)
        _ => unreachable!(), // If all subcommands are defined above, anything else is unreachabe!()
    }

    // Continued program logic goes here...
}
<commit_msg>docs(examples): De-duplicate subcommand examples<commit_after><|endoftext|>


<commit_before>//! Rusty Vangers FFI bindings.
//! Matches "lib/renderer/src/renderer/scene/rust/vange_rs.h"
//! See https://github.com/KranX/Vangers/pull/517

use futures::executor::LocalPool;
use std::{ffi::CString, os::raw, ptr};

#[repr(C)]
#[derive(Default)]
pub struct Vector3 {
    x: f32,
    y: f32,
    z: f32,
}

#[repr(C)]
#[derive(Default)]
pub struct Quaternion {
    x: f32,
    y: f32,
    z: f32,
    w: f32,
}

#[repr(C)]
#[derive(Default)]
pub struct Transform {
    position: Vector3,
    rotation: Quaternion,
}

#[repr(C)]
pub struct Rect {
    x: i32,
    y: i32,
    width: i32,
    height: i32,
}

impl Rect {
    fn to_native(&self) -> vangers::render::Rect {
        vangers::render::Rect {
            x: self.x as u16,
            y: self.y as u16,
            w: self.width as u16,
            h: self.height as u16,
        }
    }
}

#[repr(C)]
#[derive(Default)]
pub struct CameraDescription {
    fov: f32,
    aspect: f32,
    near: f32,
    far: f32,
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct MapDescription {
    width: i32,
    height: i32,
    lines: *const *const u8,
    material_begin_offsets: *const u8,
    material_end_offsets: *const u8,
    material_count: i32,
    palette: *const u8,
}

struct LevelContext {
    desc: MapDescription,
    render: vangers::render::Render,
    level: vangers::level::Level,
}

pub struct Context {
    level: Option<LevelContext>,
    render_config: vangers::config::settings::Render,
    color_format: wgpu::TextureFormat,
    color_view: wgpu::TextureView,
    depth_view: wgpu::TextureView,
    extent: wgpu::Extent3d,
    queue: wgpu::Queue,
    device: wgpu::Device,
    downlevel_caps: wgpu::DownlevelCapabilities,
    _instance: wgpu::Instance,
    camera: vangers::space::Camera,
}

pub type GlFunctionDiscovery = unsafe extern "C" fn(*const raw::c_char) -> *const raw::c_void;

#[repr(C)]
pub struct InitDescriptor {
    width: u32,
    height: u32,
    gl_functor: GlFunctionDiscovery,
}

#[no_mangle]
pub extern "C" fn rv_init(desc: InitDescriptor) -> Option<ptr::NonNull<Context>> {
    use cgmath::Zero as _;
    use vangers::config::settings as st;

    env_logger::init();
    let mut task_pool = LocalPool::new();

    let exposed = unsafe {
        <hal::api::Gles as hal::Api>::Adapter::new_external(|name| {
            let cstr = CString::new(name).unwrap();
            (desc.gl_functor)(cstr.as_ptr())
        })
    }
    .expect("GL adapter can't be initialized");

    let instance = wgpu::Instance::new(wgpu::Backends::empty());
    let adapter = unsafe { instance.create_adapter_from_hal(exposed) };

    let limits = {
        let adapter_limits = adapter.limits();
        let desired_height = 16 << 10;
        wgpu::Limits {
            max_texture_dimension_2d: if adapter_limits.max_texture_dimension_2d < desired_height {
                println!(
                    "Adapter only supports {} texutre size, main levels are not compatible",
                    adapter_limits.max_texture_dimension_2d
                );
                adapter_limits.max_texture_dimension_2d
            } else {
                desired_height
            },
            ..wgpu::Limits::downlevel_webgl2_defaults()
        }
    };

    let (device, queue) = task_pool
        .run_until(adapter.request_device(
            &wgpu::DeviceDescriptor {
                label: None,
                features: wgpu::Features::empty(),
                limits,
            },
            None,
        ))
        .ok()?;

    let extent = wgpu::Extent3d {
        width: desc.width,
        height: desc.height,
        depth_or_array_layers: 1,
    };
    let mut texture_desc = wgpu::TextureDescriptor {
        label: None,
        size: extent,
        mip_level_count: 1,
        sample_count: 1,
        dimension: wgpu::TextureDimension::D2,
        format: wgpu::TextureFormat::R8Uint, //dummy
        usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
    };
    let color_format = wgpu::TextureFormat::Rgba8UnormSrgb;

    let color_view = {
        let hal_texture_color =
            <hal::api::Gles as hal::Api>::Texture::default_framebuffer(color_format);
        texture_desc.format = color_format;
        let color_texture = unsafe {
            device.create_texture_from_hal::<hal::api::Gles>(hal_texture_color, &texture_desc)
        };
        color_texture.create_view(&wgpu::TextureViewDescriptor::default())
    };
    let depth_view = {
        let hal_texture_depth = <hal::api::Gles as hal::Api>::Texture::default_framebuffer(
            vangers::render::DEPTH_FORMAT,
        );
        texture_desc.format = vangers::render::DEPTH_FORMAT;
        let depth_texture = unsafe {
            device.create_texture_from_hal::<hal::api::Gles>(hal_texture_depth, &texture_desc)
        };
        depth_texture.create_view(&wgpu::TextureViewDescriptor::default())
    };

    let ctx = Context {
        level: None,
        render_config: st::Render {
            wgpu_trace_path: String::new(),
            light: st::Light {
                pos: [1.0, 2.0, 4.0, 0.0],
                color: [1.0, 1.0, 1.0, 1.0],
                shadow: st::Shadow {
                    size: 0,
                    terrain: st::ShadowTerrain::RayTraced,
                },
            },
            terrain: st::Terrain::RayTraced,
            fog: st::Fog {
                color: [0.1, 0.2, 0.3, 1.0],
                depth: 50.0,
            },
            debug: st::DebugRender::default(),
        },
        color_format,
        color_view,
        depth_view,
        extent,
        queue,
        device,
        downlevel_caps: adapter.get_downlevel_properties(),
        _instance: instance,
        camera: vangers::space::Camera {
            loc: cgmath::Vector3::zero(),
            rot: cgmath::Quaternion::zero(),
            proj: vangers::space::Projection::Perspective(cgmath::PerspectiveFov {
                aspect: 1.0,
                near: 1.0,
                far: 100.0,
                fovy: cgmath::Deg(45.0).into(),
            }),
        },
    };
    let ptr = Box::into_raw(Box::new(ctx));
    ptr::NonNull::new(ptr)
}

#[no_mangle]
pub unsafe extern "C" fn rv_exit(ctx: *mut Context) {
    let _ctx = Box::from_raw(ctx);
}

#[no_mangle]
pub extern "C" fn rv_camera_init(ctx: &mut Context, desc: CameraDescription) {
    ctx.camera.proj = vangers::space::Projection::Perspective(cgmath::PerspectiveFov {
        aspect: desc.aspect,
        near: desc.near,
        far: desc.far,
        fovy: cgmath::Deg(desc.fov).into(),
    });
}

#[no_mangle]
pub extern "C" fn rv_camera_set_transform(ctx: &mut Context, t: Transform) {
    ctx.camera.loc = cgmath::vec3(t.position.x, t.position.y, t.position.z);
    ctx.camera.rot =
        cgmath::Quaternion::new(t.rotation.w, t.rotation.x, t.rotation.y, t.rotation.z);
}

#[no_mangle]
pub extern "C" fn rv_map_init(ctx: &mut Context, desc: MapDescription) {
    let terrains = (0..desc.material_count)
        .map(|i| unsafe {
            let mut tc = vangers::level::TerrainConfig::default();
            tc.colors.start = *desc.material_begin_offsets.offset(i as isize);
            tc.colors.end = *desc.material_end_offsets.offset(i as isize);
            tc
        })
        .collect::<Box<[_]>>();

    let total = (desc.width * desc.height) as usize;
    let mut palette = [[0xFFu8; 4]; 0x100];
    for (i, color) in palette.iter_mut().enumerate() {
        unsafe {
            ptr::copy_nonoverlapping(desc.palette.add(i*3), color.first_mut().unwrap(), 3);
        }
    }
    let level = vangers::level::Level {
        size: (desc.width, desc.height),
        flood_map: vec![0; 128].into_boxed_slice(),
        flood_section_power: 7, //TODO
        height: vec![0; total].into_boxed_slice(),
        meta: vec![0; total].into_boxed_slice(),
        palette,
        terrains,
    };

    let render = vangers::render::Render::new(
        &ctx.device,
        &ctx.queue,
        &ctx.downlevel_caps,
        &level,
        &[[0; 4]; 0x100], //TODO: objects palette
        &ctx.render_config,
        ctx.color_format,
        // extent only matters for "scatter" style rendering
        wgpu::Extent3d {
            width: 0,
            height: 0,
            depth_or_array_layers: 0,
        },
    );
    ctx.level = Some(LevelContext {
        desc,
        render,
        level,
    });
}

#[no_mangle]
pub extern "C" fn rv_map_exit(ctx: &mut Context) {
    ctx.level = None;
}

#[no_mangle]
pub unsafe extern "C" fn rv_map_request_update(ctx: &mut Context, region: Rect) {
    let lc = ctx.level.as_mut().unwrap();
    let line_width = lc.level.size.0 as usize;

    for y in region.y..region.y + region.height {
        // In the source data, each line contains N height values followed by N meta values.
        // We copy them into separate height and meta data arrays.
        let dst_offset = y as usize * line_width + region.x as usize;
        let line = *lc.desc.lines.add(y as usize);
        ptr::copy_nonoverlapping(
            line.add(region.x as usize),
            lc.level.height[dst_offset..].as_mut_ptr(),
            region.width as usize,
        );
        ptr::copy_nonoverlapping(
            line.add(region.x as usize + line_width),
            lc.level.meta[dst_offset..].as_mut_ptr(),
            region.width as usize,
        );
    }

    lc.render.terrain.dirty_rects.push(region.to_native());
}

#[no_mangle]
pub extern "C" fn rv_render(ctx: &mut Context, viewport: Rect) {
    let lc = ctx.level.as_mut().unwrap();
    let targets = vangers::render::ScreenTargets {
        extent: ctx.extent,
        depth: &ctx.depth_view,
        color: &ctx.color_view,
    };
    let mut encoder = ctx
        .device
        .create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
    let mut batcher = vangers::render::Batcher::new();

    lc.render.custom_viewport = Some(viewport.to_native());
    lc.render.draw_world(
        &mut encoder,
        &mut batcher,
        &lc.level,
        &ctx.camera,
        targets,
        &ctx.device,
    );

    ctx.queue.submit(Some(encoder.finish()));
}
<commit_msg>ffi: pass extent to the renderer<commit_after>//! Rusty Vangers FFI bindings.
//! Matches "lib/renderer/src/renderer/scene/rust/vange_rs.h"
//! See https://github.com/KranX/Vangers/pull/517

use futures::executor::LocalPool;
use std::{ffi::CString, os::raw, ptr};

#[repr(C)]
#[derive(Default)]
pub struct Vector3 {
    x: f32,
    y: f32,
    z: f32,
}

#[repr(C)]
#[derive(Default)]
pub struct Quaternion {
    x: f32,
    y: f32,
    z: f32,
    w: f32,
}

#[repr(C)]
#[derive(Default)]
pub struct Transform {
    position: Vector3,
    rotation: Quaternion,
}

#[repr(C)]
pub struct Rect {
    x: i32,
    y: i32,
    width: i32,
    height: i32,
}

impl Rect {
    fn to_native(&self) -> vangers::render::Rect {
        vangers::render::Rect {
            x: self.x as u16,
            y: self.y as u16,
            w: self.width as u16,
            h: self.height as u16,
        }
    }
}

#[repr(C)]
#[derive(Default)]
pub struct CameraDescription {
    fov: f32,
    aspect: f32,
    near: f32,
    far: f32,
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct MapDescription {
    width: i32,
    height: i32,
    lines: *const *const u8,
    material_begin_offsets: *const u8,
    material_end_offsets: *const u8,
    material_count: i32,
    palette: *const u8,
}

struct LevelContext {
    desc: MapDescription,
    render: vangers::render::Render,
    level: vangers::level::Level,
}

pub struct Context {
    level: Option<LevelContext>,
    render_config: vangers::config::settings::Render,
    color_format: wgpu::TextureFormat,
    color_view: wgpu::TextureView,
    depth_view: wgpu::TextureView,
    extent: wgpu::Extent3d,
    queue: wgpu::Queue,
    device: wgpu::Device,
    downlevel_caps: wgpu::DownlevelCapabilities,
    _instance: wgpu::Instance,
    camera: vangers::space::Camera,
}

pub type GlFunctionDiscovery = unsafe extern "C" fn(*const raw::c_char) -> *const raw::c_void;

#[repr(C)]
pub struct InitDescriptor {
    width: u32,
    height: u32,
    gl_functor: GlFunctionDiscovery,
}

#[no_mangle]
pub extern "C" fn rv_init(desc: InitDescriptor) -> Option<ptr::NonNull<Context>> {
    use cgmath::Zero as _;
    use vangers::config::settings as st;

    env_logger::init();
    let mut task_pool = LocalPool::new();

    let exposed = unsafe {
        <hal::api::Gles as hal::Api>::Adapter::new_external(|name| {
            let cstr = CString::new(name).unwrap();
            (desc.gl_functor)(cstr.as_ptr())
        })
    }
    .expect("GL adapter can't be initialized");

    let instance = wgpu::Instance::new(wgpu::Backends::empty());
    let adapter = unsafe { instance.create_adapter_from_hal(exposed) };

    let limits = {
        let adapter_limits = adapter.limits();
        let desired_height = 16 << 10;
        wgpu::Limits {
            max_texture_dimension_2d: if adapter_limits.max_texture_dimension_2d < desired_height {
                println!(
                    "Adapter only supports {} texutre size, main levels are not compatible",
                    adapter_limits.max_texture_dimension_2d
                );
                adapter_limits.max_texture_dimension_2d
            } else {
                desired_height
            },
            ..wgpu::Limits::downlevel_webgl2_defaults()
        }
    };

    let (device, queue) = task_pool
        .run_until(adapter.request_device(
            &wgpu::DeviceDescriptor {
                label: None,
                features: wgpu::Features::empty(),
                limits,
            },
            None,
        ))
        .ok()?;

    let extent = wgpu::Extent3d {
        width: desc.width,
        height: desc.height,
        depth_or_array_layers: 1,
    };
    let mut texture_desc = wgpu::TextureDescriptor {
        label: None,
        size: extent,
        mip_level_count: 1,
        sample_count: 1,
        dimension: wgpu::TextureDimension::D2,
        format: wgpu::TextureFormat::R8Uint, //dummy
        usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
    };
    let color_format = wgpu::TextureFormat::Rgba8UnormSrgb;

    let color_view = {
        let hal_texture_color =
            <hal::api::Gles as hal::Api>::Texture::default_framebuffer(color_format);
        texture_desc.format = color_format;
        let color_texture = unsafe {
            device.create_texture_from_hal::<hal::api::Gles>(hal_texture_color, &texture_desc)
        };
        color_texture.create_view(&wgpu::TextureViewDescriptor::default())
    };
    let depth_view = {
        let hal_texture_depth = <hal::api::Gles as hal::Api>::Texture::default_framebuffer(
            vangers::render::DEPTH_FORMAT,
        );
        texture_desc.format = vangers::render::DEPTH_FORMAT;
        let depth_texture = unsafe {
            device.create_texture_from_hal::<hal::api::Gles>(hal_texture_depth, &texture_desc)
        };
        depth_texture.create_view(&wgpu::TextureViewDescriptor::default())
    };

    let ctx = Context {
        level: None,
        render_config: st::Render {
            wgpu_trace_path: String::new(),
            light: st::Light {
                pos: [1.0, 2.0, 4.0, 0.0],
                color: [1.0, 1.0, 1.0, 1.0],
                shadow: st::Shadow {
                    size: 0,
                    terrain: st::ShadowTerrain::RayTraced,
                },
            },
            terrain: st::Terrain::RayTraced,
            fog: st::Fog {
                color: [0.1, 0.2, 0.3, 1.0],
                depth: 50.0,
            },
            debug: st::DebugRender::default(),
        },
        color_format,
        color_view,
        depth_view,
        extent,
        queue,
        device,
        downlevel_caps: adapter.get_downlevel_properties(),
        _instance: instance,
        camera: vangers::space::Camera {
            loc: cgmath::Vector3::zero(),
            rot: cgmath::Quaternion::zero(),
            proj: vangers::space::Projection::Perspective(cgmath::PerspectiveFov {
                aspect: 1.0,
                near: 1.0,
                far: 100.0,
                fovy: cgmath::Deg(45.0).into(),
            }),
        },
    };
    let ptr = Box::into_raw(Box::new(ctx));
    ptr::NonNull::new(ptr)
}

#[no_mangle]
pub unsafe extern "C" fn rv_exit(ctx: *mut Context) {
    let _ctx = Box::from_raw(ctx);
}

#[no_mangle]
pub extern "C" fn rv_camera_init(ctx: &mut Context, desc: CameraDescription) {
    ctx.camera.proj = vangers::space::Projection::Perspective(cgmath::PerspectiveFov {
        aspect: desc.aspect,
        near: desc.near,
        far: desc.far,
        fovy: cgmath::Deg(desc.fov).into(),
    });
}

#[no_mangle]
pub extern "C" fn rv_camera_set_transform(ctx: &mut Context, t: Transform) {
    ctx.camera.loc = cgmath::vec3(t.position.x, t.position.y, t.position.z);
    ctx.camera.rot =
        cgmath::Quaternion::new(t.rotation.w, t.rotation.x, t.rotation.y, t.rotation.z);
}

#[no_mangle]
pub extern "C" fn rv_map_init(ctx: &mut Context, desc: MapDescription) {
    let terrains = (0..desc.material_count)
        .map(|i| unsafe {
            let mut tc = vangers::level::TerrainConfig::default();
            tc.colors.start = *desc.material_begin_offsets.offset(i as isize);
            tc.colors.end = *desc.material_end_offsets.offset(i as isize);
            tc
        })
        .collect::<Box<[_]>>();

    let total = (desc.width * desc.height) as usize;
    let mut palette = [[0xFFu8; 4]; 0x100];
    for (i, color) in palette.iter_mut().enumerate() {
        unsafe {
            ptr::copy_nonoverlapping(desc.palette.add(i*3), color.first_mut().unwrap(), 3);
        }
    }
    let level = vangers::level::Level {
        size: (desc.width, desc.height),
        flood_map: vec![0; 128].into_boxed_slice(),
        flood_section_power: 7, //TODO
        height: vec![0; total].into_boxed_slice(),
        meta: vec![0; total].into_boxed_slice(),
        palette,
        terrains,
    };

    let render = vangers::render::Render::new(
        &ctx.device,
        &ctx.queue,
        &ctx.downlevel_caps,
        &level,
        &[[0; 4]; 0x100], //TODO: objects palette
        &ctx.render_config,
        ctx.color_format,
        ctx.extent, //Note: needs update on window resize
    );
    ctx.level = Some(LevelContext {
        desc,
        render,
        level,
    });
}

#[no_mangle]
pub extern "C" fn rv_map_exit(ctx: &mut Context) {
    ctx.level = None;
}

#[no_mangle]
pub unsafe extern "C" fn rv_map_request_update(ctx: &mut Context, region: Rect) {
    let lc = ctx.level.as_mut().unwrap();
    let line_width = lc.level.size.0 as usize;

    for y in region.y..region.y + region.height {
        // In the source data, each line contains N height values followed by N meta values.
        // We copy them into separate height and meta data arrays.
        let dst_offset = y as usize * line_width + region.x as usize;
        let line = *lc.desc.lines.add(y as usize);
        ptr::copy_nonoverlapping(
            line.add(region.x as usize),
            lc.level.height[dst_offset..].as_mut_ptr(),
            region.width as usize,
        );
        ptr::copy_nonoverlapping(
            line.add(region.x as usize + line_width),
            lc.level.meta[dst_offset..].as_mut_ptr(),
            region.width as usize,
        );
    }

    lc.render.terrain.dirty_rects.push(region.to_native());
}

#[no_mangle]
pub extern "C" fn rv_render(ctx: &mut Context, viewport: Rect) {
    let lc = ctx.level.as_mut().unwrap();
    let targets = vangers::render::ScreenTargets {
        extent: ctx.extent,
        depth: &ctx.depth_view,
        color: &ctx.color_view,
    };
    let mut encoder = ctx
        .device
        .create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
    let mut batcher = vangers::render::Batcher::new();

    lc.render.custom_viewport = Some(viewport.to_native());
    lc.render.draw_world(
        &mut encoder,
        &mut batcher,
        &lc.level,
        &ctx.camera,
        targets,
        &ctx.device,
    );

    ctx.queue.submit(Some(encoder.finish()));
}
<|endoftext|>


<commit_before>use std::ops::{Add, Mul};

use cgmath::prelude::*;
use cgmath::vec3;
use image;

use math::*;

pub struct Color {
    inner: Vector,
}

impl Color {
    pub fn new(inner: Vector) -> Color {
        Color { inner: inner }
    }

    pub fn rgb(r: f32, g: f32, b: f32) -> Color {
        Color::new(vec3(r, g, b))
    }

    pub fn from_bytes(r: u8, g: u8, b: u8) -> Color {
        Color::rgb((r as f32) / 255.0, (g as f32) / 255.0, (b as f32) / 255.0)
    }

    pub fn from_u32(color: u32) -> Color {
        let r = (color >> 24) as u8;
        let g = (color >> 16) as u8;
        let b = (color >> 8) as u8;

        Color::from_bytes(r, g, b)
    }

    pub fn into_pixel(self) -> image::Rgb<u8> {
        image::Rgb([convert_component(self.inner.x),
                    convert_component(self.inner.y),
                    convert_component(self.inner.z)])
    }
}

impl Add for Color {
    type Output = Color;

    fn add(self, rhs: Self) -> Self::Output {
        Color { inner: self.inner.add_element_wise(rhs.inner) }
    }
}

impl Mul for Color {
    type Output = Color;

    fn mul(self, rhs: Self) -> Self::Output {
        Color { inner: self.inner.mul_element_wise(rhs.inner) }
    }
}

impl Mul<f32> for Color {
    type Output = Color;

    fn mul(self, rhs: f32) -> Self::Output {
        Color { inner: self.inner * rhs }
    }
}

impl From<Vector> for Color {
    fn from(vector: Vector) -> Self {
        Color::new(vector)
    }
}

impl Into<Vector> for Color {
    fn into(self) -> Vector {
        self.inner
    }
}

fn convert_component(component: f32) -> u8 {
    map_range(clamp(component, 0.0, 1.0), 0.0..1.0, 255.0..0.0) as u8
}
<commit_msg>Fix conversion of `Color`s to pixel colors<commit_after>use std::ops::{Add, Mul};

use cgmath::prelude::*;
use cgmath::vec3;
use image;

use math::*;

pub struct Color {
    inner: Vector,
}

impl Color {
    pub fn new(inner: Vector) -> Color {
        Color { inner: inner }
    }

    pub fn rgb(r: f32, g: f32, b: f32) -> Color {
        Color::new(vec3(r, g, b))
    }

    pub fn from_bytes(r: u8, g: u8, b: u8) -> Color {
        Color::rgb((r as f32) / 255.0, (g as f32) / 255.0, (b as f32) / 255.0)
    }

    pub fn from_u32(color: u32) -> Color {
        let r = (color >> 24) as u8;
        let g = (color >> 16) as u8;
        let b = (color >> 8) as u8;

        Color::from_bytes(r, g, b)
    }

    pub fn into_pixel(self) -> image::Rgb<u8> {
        image::Rgb([convert_component(self.inner.x),
                    convert_component(self.inner.y),
                    convert_component(self.inner.z)])
    }
}

impl Add for Color {
    type Output = Color;

    fn add(self, rhs: Self) -> Self::Output {
        Color { inner: self.inner.add_element_wise(rhs.inner) }
    }
}

impl Mul for Color {
    type Output = Color;

    fn mul(self, rhs: Self) -> Self::Output {
        Color { inner: self.inner.mul_element_wise(rhs.inner) }
    }
}

impl Mul<f32> for Color {
    type Output = Color;

    fn mul(self, rhs: f32) -> Self::Output {
        Color { inner: self.inner * rhs }
    }
}

impl From<Vector> for Color {
    fn from(vector: Vector) -> Self {
        Color::new(vector)
    }
}

impl Into<Vector> for Color {
    fn into(self) -> Vector {
        self.inner
    }
}

fn convert_component(component: f32) -> u8 {
    map_range(clamp(component, 0.0, 1.0), 0.0..1.0, 0.0..255.0) as u8
}
<|endoftext|>


<commit_before>use num::Integer;

/// A color's hue.
#[derive(Debug, Clone, Copy)]
pub enum Hue {
    Red,
    Yellow,
    Green,
    Cyan,
    Blue,
    Magenta,
}

impl Hue {
    /// Calculate the change in hue between two hues.
    ///
    /// # Examples
    ///
    /// ```
    /// use piet::Hue;
    /// use piet::Hue::*;
    ///
    /// assert_eq!(Hue::shift(Red, Yellow), 1);
    /// assert_eq!(Hue::shift(Red, Magenta), 5);
    /// ```
    pub fn shift(from: Hue, to: Hue) -> u8 {
        ((to as i8) - (from as i8)).mod_floor(&6) as u8
    }
}

/// A color's lightness.
#[derive(Debug, Clone, Copy)]
pub enum Lightness {
    Light,
    Normal,
    Dark,
}

impl Lightness {
    /// Calculate the change in lightness between two lightness values.
    ///
    /// # Examples
    ///
    /// ```
    /// use piet::Lightness;
    /// use piet::Lightness::*;
    ///
    /// assert_eq!(Lightness::shift(Light, Normal), 1);
    /// assert_eq!(Lightness::shift(Dark, Light), 1);
    /// ```
    pub fn shift(from: Lightness, to: Lightness) -> u8 {
        ((to as i8) - (from as i8)).mod_floor(&3) as u8
    }
}

/// A color, as interpreted by Piet.
#[derive(Debug, Clone, Copy)]
pub enum Color {
    Composite(Hue, Lightness),
    Black,
    White,
}

impl Color {
    /// Calculate the transition between two colors.
    ///
    /// # Returns
    ///
    /// `Some((u8, u8))` when comparing composite colors,
    /// `None` for black and white.
    ///
    /// # Examples
    ///
    /// ```
    /// use piet::Color;
    /// use piet::Hue::*;
    /// use piet::Lightness::*;
    ///
    /// let a = Color::Composite(Blue, Light);
    /// let b = Color::Composite(Green, Dark);
    ///
    /// assert_eq!(Color::transition(a, b), Some((4, 2)))
    /// ```
    pub fn transition(from: Color, to: Color) -> Option<(u8, u8)> {
        let (from_h, from_l) = match from {
            Color::Composite(h, l) => (h, l),
            _ => return None,
        };

        let (to_h, to_l) = match to {
            Color::Composite(h, l) => (h, l),
            _ => return None,
        };

        Some((Hue::shift(from_h, to_h), Lightness::shift(from_l, to_l)))
    }
}

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

    #[test]
    fn test_hue_shift() {
        use super::Hue::*;

        assert_eq!(Hue::shift(Red, Red), 0);
        assert_eq!(Hue::shift(Red, Yellow), 1);
        assert_eq!(Hue::shift(Red, Magenta), 5);
        assert_eq!(Hue::shift(Magenta, Red), 1);
        assert_eq!(Hue::shift(Magenta, Blue), 5);
    }

    #[test]
    fn test_lightness_shift() {
        use super::Lightness::*;

        assert_eq!(Lightness::shift(Light, Light), 0);
        assert_eq!(Lightness::shift(Light, Normal), 1);
        assert_eq!(Lightness::shift(Normal, Dark), 1);
        assert_eq!(Lightness::shift(Light, Dark), 2);
        assert_eq!(Lightness::shift(Dark, Light), 1);
        assert_eq!(Lightness::shift(Dark, Normal), 2);
    }

    #[test]
    fn test_color_transition() {
        use super::Hue::*;
        use super::Lightness::*;

        let a = Color::Composite(Red, Normal);
        let b = Color::Composite(Red, Normal);
        assert_eq!(Color::transition(a, b), Some((0, 0)));

        let a = Color::Composite(Red, Dark);
        let b = Color::Composite(Yellow, Normal);
        assert_eq!(Color::transition(a, b), Some((1, 2)));

        let a = Color::Black;
        let b = Color::Composite(Red, Normal);
        assert_eq!(Color::transition(a, b), None);

        let a = Color::Composite(Red, Normal);
        let b = Color::Black;
        assert_eq!(Color::transition(a, b), None);
    }
}
<commit_msg>Add `Color::from_rgb`<commit_after>use num::Integer;

/// A color's hue.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Hue {
    Red,
    Yellow,
    Green,
    Cyan,
    Blue,
    Magenta,
}

impl Hue {
    /// Calculate the change in hue between two hues.
    ///
    /// # Examples
    ///
    /// ```
    /// use piet::Hue;
    /// use piet::Hue::*;
    ///
    /// assert_eq!(Hue::shift(Red, Yellow), 1);
    /// assert_eq!(Hue::shift(Red, Magenta), 5);
    /// ```
    pub fn shift(from: Hue, to: Hue) -> u8 {
        ((to as i8) - (from as i8)).mod_floor(&6) as u8
    }
}

/// A color's lightness.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Lightness {
    Light,
    Normal,
    Dark,
}

impl Lightness {
    /// Calculate the change in lightness between two lightness values.
    ///
    /// # Examples
    ///
    /// ```
    /// use piet::Lightness;
    /// use piet::Lightness::*;
    ///
    /// assert_eq!(Lightness::shift(Light, Normal), 1);
    /// assert_eq!(Lightness::shift(Dark, Light), 1);
    /// ```
    pub fn shift(from: Lightness, to: Lightness) -> u8 {
        ((to as i8) - (from as i8)).mod_floor(&3) as u8
    }
}

/// A color, as interpreted by Piet.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Color {
    Composite(Hue, Lightness),
    Black,
    White,
}

impl Color {
    /// Create a color from an RGB triplet.
    ///
    /// # Examples
    ///
    /// ```
    /// use piet::Color;
    /// use piet::Hue::*;
    /// use piet::Lightness::*;
    ///
    /// let color = Color::from_rgb(0xc0, 0xc0, 0xff);
    /// assert_eq!(color, Color::Composite(Blue, Light));
    /// ```
    pub fn from_rgb(r: u8, g: u8, b: u8) -> Self {
        use Hue::*;
        use Lightness::*;
        use Color::*;

        let (r, g, b) = (r as u32, g as u32, b as u32);

        let color: u32 = (((r << 8) | g) << 8) | b;

        match color {
            0xffc0c0 => Composite(Red, Light),
            0xffffc0 => Composite(Yellow, Light),
            0xc0ffc0 => Composite(Green, Light),
            0xc0ffff => Composite(Cyan, Light),
            0xc0c0ff => Composite(Blue, Light),
            0xffc0ff => Composite(Magenta, Light),

            0xff0000 => Composite(Red, Normal),
            0xffff00 => Composite(Yellow, Normal),
            0x00ff00 => Composite(Green, Normal),
            0x00ffff => Composite(Cyan, Normal),
            0x0000ff => Composite(Blue, Normal),
            0xff00ff => Composite(Magenta, Normal),

            0xc00000 => Composite(Red, Dark),
            0xc0c000 => Composite(Yellow, Dark),
            0x00c000 => Composite(Green, Dark),
            0x00c0c0 => Composite(Cyan, Dark),
            0x0000c0 => Composite(Blue, Dark),
            0xc000c0 => Composite(Magenta, Dark),

            0xffffff => White,
            0x000000 => Black,

            _ => White,

            // TODO: maybe make the fallback color configurable? Or even find
            // the nearest color, and create a `Composite` based on that.
        }
    }

    /// Calculate the transition between two colors.
    ///
    /// # Returns
    ///
    /// `Some((u8, u8))` when comparing composite colors,
    /// `None` for black and white.
    ///
    /// # Examples
    ///
    /// ```
    /// use piet::Color;
    /// use piet::Hue::*;
    /// use piet::Lightness::*;
    ///
    /// let a = Color::Composite(Blue, Light);
    /// let b = Color::Composite(Green, Dark);
    ///
    /// assert_eq!(Color::transition(a, b), Some((4, 2)))
    /// ```
    pub fn transition(from: Color, to: Color) -> Option<(u8, u8)> {
        let (from_h, from_l) = match from {
            Color::Composite(h, l) => (h, l),
            _ => return None,
        };

        let (to_h, to_l) = match to {
            Color::Composite(h, l) => (h, l),
            _ => return None,
        };

        Some((Hue::shift(from_h, to_h), Lightness::shift(from_l, to_l)))
    }
}

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

    #[test]
    fn test_hue_shift() {
        use super::Hue::*;

        assert_eq!(Hue::shift(Red, Red), 0);
        assert_eq!(Hue::shift(Red, Yellow), 1);
        assert_eq!(Hue::shift(Red, Magenta), 5);
        assert_eq!(Hue::shift(Magenta, Red), 1);
        assert_eq!(Hue::shift(Magenta, Blue), 5);
    }

    #[test]
    fn test_lightness_shift() {
        use super::Lightness::*;

        assert_eq!(Lightness::shift(Light, Light), 0);
        assert_eq!(Lightness::shift(Light, Normal), 1);
        assert_eq!(Lightness::shift(Normal, Dark), 1);
        assert_eq!(Lightness::shift(Light, Dark), 2);
        assert_eq!(Lightness::shift(Dark, Light), 1);
        assert_eq!(Lightness::shift(Dark, Normal), 2);
    }

    #[test]
    fn test_color_from_rgb() {
        use super::Hue::*;
        use super::Lightness::*;

        let color = Color::from_rgb(0x00, 0x00, 0x00);
        assert_eq!(color, Color::Black);

        let color = Color::from_rgb(0xff, 0xff, 0xff);
        assert_eq!(color, Color::White);

        let color = Color::from_rgb(0x12, 0x34, 0x56);
        assert_eq!(color, Color::White);

        let color = Color::from_rgb(0x00, 0xff, 0x00);
        assert_eq!(color, Color::Composite(Green, Normal));
    }

    #[test]
    fn test_color_transition() {
        use super::Hue::*;
        use super::Lightness::*;

        let a = Color::Composite(Red, Normal);
        let b = Color::Composite(Red, Normal);
        assert_eq!(Color::transition(a, b), Some((0, 0)));

        let a = Color::Composite(Red, Dark);
        let b = Color::Composite(Yellow, Normal);
        assert_eq!(Color::transition(a, b), Some((1, 2)));

        let a = Color::Black;
        let b = Color::Composite(Red, Normal);
        assert_eq!(Color::transition(a, b), None);

        let a = Color::Composite(Red, Normal);
        let b = Color::Black;
        assert_eq!(Color::transition(a, b), None);
    }
}
<|endoftext|>