<commit_before>//! Various data structs that different calls might use in results.

use error;

/// Badge type!
#[derive(Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum BadgeType {
    Fixed(i32),
    Dynamic { path1: String, path2: String },
}

/// Badge color!
#[derive(Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum BadgeColor {
    Set(i32),
    Hex(String),
}

/// badge: { type, color1, color2, color3, param, flip }
#[derive(Deserialize, Debug, Clone)]
pub struct Badge {
    /// Badge type, used for different badge formats
    #[serde(rename="type")]
    pub badge_type: BadgeType,
    /// First color, use depends on badge type.
    pub color1: BadgeColor,
    /// Second color, use depends on badge type.
    pub color2: BadgeColor,
    /// Third color, use depends on badge type.
    pub color3: BadgeColor,
    /// Integer parameter to badge display, changes the shape of the badge in a different way depending on badge type.
    pub param: i32,
    /// Flips the badge either horizontally or vertically, depending on badge type.
    pub flip: bool,
}

#[derive(Deserialize, Debug, Clone)]
pub struct ApiError {
    pub error: String,
}

impl Into<error::Error> for ApiError {
    fn into(self) -> error::Error {
        if self.error == "invalid room" {
            error::ApiError::InvalidRoom.into()
        } else if self.error == "result not found" {
            error::ApiError::ResultNotFound.into()
        } else if self.error == "user not found" {
            error::ApiError::UserNotFound.into()
        } else {
            error::ApiError::GenericError(self.error).into()
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{Badge, ApiError};
    use error;
    use serde_json;

    #[test]
    fn parse_sample_parse_badge_simple_colors_simple_pattern() {
        let _: Badge = serde_json::from_value(json!({
            "type": 19,
            "color1": 37,
            "color2": 57,
            "color3": 1,
            "param": 0,
            "flip": false,
        }))
            .unwrap();
    }

    #[test]
    fn parse_sample_badge_hex_colors_simple_pattern() {
        let _: Badge = serde_json::from_value(json!({
            "type": 21,
            "color1": "#260d0d",
            "color2": "#6b2e41",
            "color3": "#ffe56d",
            "param": -100,
            "flip": false,
        }))
            .unwrap();
    }

    #[test]
    fn parse_sample_badge_custom_dissi() {
        let _: Badge = serde_json::from_value(json!({
            "type": {
                "path1": "M0,50c0,27.3,21.8,49.5,48.9,50v-9.6c-2.5-0.8-5.5-4.6-7.8-10.2c-0.9-2.3-1.7-4.7-2.4-7.4   \
                c3.3,0.3,6.7,0.5,10.2,0.5v-9.5c-4.2,0-8.2-0.3-12-0.8c-0.5-4.1-0.8-8.5-0.8-13c0-4.5,0.3-8.9,0.8-13c3.8-\
                0.5,7.9-0.8,12-0.8v-9.5   c-3.5,0-6.9,0.2-10.2,0.5c0.7-2.7,1.5-5.1,2.4-7.4c2.3-5.6,5.2-9.4,7.8-10.2V0C\
                21.8,0.5,0,22.7,0,50L0,50z M9.5,50   c0-2.7,4-6.2,10.2-8.7c2.3-0.9,4.7-1.7,7.4-2.4c-0.4,3.6-0.5,7.3-0.\
                5,11.1c0,3.8,0.2,7.5,0.5,11.1c-2.6-0.7-5.1-1.5-7.4-2.4   C13.5,56.2,9.5,52.7,9.5,50L9.5,50z \
                M12.8,66c1.1,0.5,2.2,1.1,3.4,1.5c3.7,1.5,7.9,2.8,12.5,3.7c0.9,4.6,2.2,8.8,3.7,12.5   \
                c0.5,1.2,1,2.3,1.5,3.4C24.4,83.1,16.8,75.5,12.8,66L12.8,66z \
                M33.9,12.8c-0.5,1.1-1,2.2-1.5,3.4c-1.5,3.7-2.8,8-3.7,12.5   \
                c-4.5,0.9-8.8,2.2-12.5,3.7c-1.2,0.5-2.3,1-3.4,1.5C16.8,24.5,24.4,16.9,33.9,12.8L33.9,12.8z",
                "path2": "M97,59l-6-3.4c0.3-1.8,0.4-3.7,0.4-5.6c0-1.9-0.1-3.7-0.4-5.6l6-3.4c2.8-1.6,3.8-5.2,2.2-8.1   \
                l-8.6-15.2c-0.8-1.4-2.1-2.4-3.6-2.8c-1.5-0.4-3.1-0.2-4.5,0.6l-6.1,3.5c-3.1-2.5-6.6-4.6-10.3-6v-7c0-3.3\
                -2.6-5.9-5.9-5.9h-7.7   v23.4C66.8,23.9,78.1,35.7,78.1,50c0,14.3-11.4,26.1-25.5,26.6V100h7.7c3.3,0,5.9\
                -2.7,5.9-5.9v-7c3.7-1.5,7.2-3.5,10.3-6l6.1,3.5   c0.9,0.5,1.9,0.8,2.9,0.8c0.5,0,1.1-0.1,1.6-0.2c1.5-0.\
                4,2.8-1.4,3.6-2.8l8.6-15.2C100.8,64.2,99.8,60.6,97,59L97,59z",
            },
            "color1": "#000000",
            "color2": "#028300",
            "color3": "#8b5c00",
            "param": 0,
            "flip": false,
        }))
            .unwrap();
    }

    #[test]
    fn parse_sample_standard_server_error() {
        let _: ApiError = serde_json::from_value(json!({
            "error": "any error string",
        }))
            .unwrap();
    }

    #[test]
    fn parse_sample_invalid_room_error() {
        let result: ApiError = serde_json::from_value(json!({
            "error": "invalid room",
        }))
            .unwrap();

        let error: error::Error = result.into();

        match error.err {
            error::ErrorType::Api(error::ApiError::InvalidRoom) => (),
            _ => panic!("expected invalid room error, found {}", error),
        }
    }
}
<commit_msg>Fix invalid parameter error not being parsed (yay testing!)<commit_after>//! Various data structs that different calls might use in results.

use error;

/// Badge type!
#[derive(Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum BadgeType {
    Fixed(i32),
    Dynamic { path1: String, path2: String },
}

/// Badge color!
#[derive(Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum BadgeColor {
    Set(i32),
    Hex(String),
}

/// badge: { type, color1, color2, color3, param, flip }
#[derive(Deserialize, Debug, Clone)]
pub struct Badge {
    /// Badge type, used for different badge formats
    #[serde(rename="type")]
    pub badge_type: BadgeType,
    /// First color, use depends on badge type.
    pub color1: BadgeColor,
    /// Second color, use depends on badge type.
    pub color2: BadgeColor,
    /// Third color, use depends on badge type.
    pub color3: BadgeColor,
    /// Integer parameter to badge display, changes the shape of the badge in a different way depending on badge type.
    pub param: i32,
    /// Flips the badge either horizontally or vertically, depending on badge type.
    pub flip: bool,
}

#[derive(Deserialize, Debug, Clone)]
pub struct ApiError {
    pub error: String,
}

impl Into<error::Error> for ApiError {
    fn into(self) -> error::Error {
        if self.error == "invalid room" {
            error::ApiError::InvalidRoom.into()
        } else if self.error == "result not found" {
            error::ApiError::ResultNotFound.into()
        } else if self.error == "invalid params" {
            error::ApiError::InvalidParameters.into()
        } else if self.error == "user not found" {
            error::ApiError::UserNotFound.into()
        } else {
            error::ApiError::GenericError(self.error).into()
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{Badge, ApiError};
    use error;
    use serde_json;

    #[test]
    fn parse_sample_parse_badge_simple_colors_simple_pattern() {
        let _: Badge = serde_json::from_value(json!({
            "type": 19,
            "color1": 37,
            "color2": 57,
            "color3": 1,
            "param": 0,
            "flip": false,
        }))
            .unwrap();
    }

    #[test]
    fn parse_sample_badge_hex_colors_simple_pattern() {
        let _: Badge = serde_json::from_value(json!({
            "type": 21,
            "color1": "#260d0d",
            "color2": "#6b2e41",
            "color3": "#ffe56d",
            "param": -100,
            "flip": false,
        }))
            .unwrap();
    }

    #[test]
    fn parse_sample_badge_custom_dissi() {
        let _: Badge = serde_json::from_value(json!({
            "type": {
                "path1": "M0,50c0,27.3,21.8,49.5,48.9,50v-9.6c-2.5-0.8-5.5-4.6-7.8-10.2c-0.9-2.3-1.7-4.7-2.4-7.4   \
                c3.3,0.3,6.7,0.5,10.2,0.5v-9.5c-4.2,0-8.2-0.3-12-0.8c-0.5-4.1-0.8-8.5-0.8-13c0-4.5,0.3-8.9,0.8-13c3.8-\
                0.5,7.9-0.8,12-0.8v-9.5   c-3.5,0-6.9,0.2-10.2,0.5c0.7-2.7,1.5-5.1,2.4-7.4c2.3-5.6,5.2-9.4,7.8-10.2V0C\
                21.8,0.5,0,22.7,0,50L0,50z M9.5,50   c0-2.7,4-6.2,10.2-8.7c2.3-0.9,4.7-1.7,7.4-2.4c-0.4,3.6-0.5,7.3-0.\
                5,11.1c0,3.8,0.2,7.5,0.5,11.1c-2.6-0.7-5.1-1.5-7.4-2.4   C13.5,56.2,9.5,52.7,9.5,50L9.5,50z \
                M12.8,66c1.1,0.5,2.2,1.1,3.4,1.5c3.7,1.5,7.9,2.8,12.5,3.7c0.9,4.6,2.2,8.8,3.7,12.5   \
                c0.5,1.2,1,2.3,1.5,3.4C24.4,83.1,16.8,75.5,12.8,66L12.8,66z \
                M33.9,12.8c-0.5,1.1-1,2.2-1.5,3.4c-1.5,3.7-2.8,8-3.7,12.5   \
                c-4.5,0.9-8.8,2.2-12.5,3.7c-1.2,0.5-2.3,1-3.4,1.5C16.8,24.5,24.4,16.9,33.9,12.8L33.9,12.8z",
                "path2": "M97,59l-6-3.4c0.3-1.8,0.4-3.7,0.4-5.6c0-1.9-0.1-3.7-0.4-5.6l6-3.4c2.8-1.6,3.8-5.2,2.2-8.1   \
                l-8.6-15.2c-0.8-1.4-2.1-2.4-3.6-2.8c-1.5-0.4-3.1-0.2-4.5,0.6l-6.1,3.5c-3.1-2.5-6.6-4.6-10.3-6v-7c0-3.3\
                -2.6-5.9-5.9-5.9h-7.7   v23.4C66.8,23.9,78.1,35.7,78.1,50c0,14.3-11.4,26.1-25.5,26.6V100h7.7c3.3,0,5.9\
                -2.7,5.9-5.9v-7c3.7-1.5,7.2-3.5,10.3-6l6.1,3.5   c0.9,0.5,1.9,0.8,2.9,0.8c0.5,0,1.1-0.1,1.6-0.2c1.5-0.\
                4,2.8-1.4,3.6-2.8l8.6-15.2C100.8,64.2,99.8,60.6,97,59L97,59z",
            },
            "color1": "#000000",
            "color2": "#028300",
            "color3": "#8b5c00",
            "param": 0,
            "flip": false,
        }))
            .unwrap();
    }

    #[test]
    fn parse_sample_standard_server_error() {
        let _: ApiError = serde_json::from_value(json!({
            "error": "any error string",
        }))
            .unwrap();
    }

    #[test]
    fn parse_sample_invalid_room_error() {
        let result: ApiError = serde_json::from_value(json!({
            "error": "invalid room",
        }))
            .unwrap();

        let error: error::Error = result.into();

        match error.err {
            error::ErrorType::Api(error::ApiError::InvalidRoom) => (),
            _ => panic!("expected invalid room error, found {}", error),
        }
    }
}
<|endoftext|>


<commit_before>use futures_executor::LocalPool;
use lapin::{
    CloseOnDrop,
    message::DeliveryResult, options::*, publisher_confirm::Confirmation, types::FieldTable,
    BasicProperties, Connection, ConnectionProperties,
};
use log::info;

fn main() {
    std::env::set_var("RUST_LOG", "trace");

    env_logger::init();

    let addr = std::env::var("AMQP_ADDR").unwrap_or_else(|_| "amqp://127.0.0.1:5672/%2f".into());
    let mut executor = LocalPool::new();

    executor.run_until(async {
        let conn = Connection::connect(&addr, ConnectionProperties::default())
            .await
            .map(CloseOnDrop::new)
            .expect("connection error");

        info!("CONNECTED");

        info!("creating then auto-closing channel");
        let _ = conn.create_channel().await.map(CloseOnDrop::new).expect("create_channel");

        let channel = conn.create_channel().await.expect("create_channel");

        channel
            .queue_declare(
                "hello",
                QueueDeclareOptions::default(),
                FieldTable::default(),
            )
            .await
            .expect("queue_declare");

        let chan = channel.clone();
        channel
            .basic_consume(
                "hello",
                "my_consumer",
                BasicConsumeOptions::default(),
                FieldTable::default(),
            )
            .await
            .expect("basic_consume")
            .set_delegate(Box::new(move |delivery: DeliveryResult| {
                info!("received message: {:?}", delivery);
                if let Ok(Some(delivery)) = delivery {
                    chan.basic_ack(delivery.delivery_tag, BasicAckOptions::default())
                        .wait() // await is hard to handle here
                        .expect("basic_ack");
                }
            }));

        let payload = b"Hello world!";
        let confirm = channel
            .basic_publish(
                "",
                "hello",
                BasicPublishOptions::default(),
                payload.to_vec(),
                BasicProperties::default(),
            )
            .await
            .expect("basic_publish")
            .await;
        assert_eq!(confirm, Confirmation::NotRequested);

        std::thread::sleep(std::time::Duration::from_millis(2000));

        info!("Connection will be automatically closed on drop");
    })
}
<commit_msg>rustfmt<commit_after>use futures_executor::LocalPool;
use lapin::{
    message::DeliveryResult, options::*, publisher_confirm::Confirmation, types::FieldTable,
    BasicProperties, CloseOnDrop, Connection, ConnectionProperties,
};
use log::info;

fn main() {
    std::env::set_var("RUST_LOG", "trace");

    env_logger::init();

    let addr = std::env::var("AMQP_ADDR").unwrap_or_else(|_| "amqp://127.0.0.1:5672/%2f".into());
    let mut executor = LocalPool::new();

    executor.run_until(async {
        let conn = Connection::connect(&addr, ConnectionProperties::default())
            .await
            .map(CloseOnDrop::new)
            .expect("connection error");

        info!("CONNECTED");

        info!("creating then auto-closing channel");
        let _ = conn
            .create_channel()
            .await
            .map(CloseOnDrop::new)
            .expect("create_channel");

        let channel = conn.create_channel().await.expect("create_channel");

        channel
            .queue_declare(
                "hello",
                QueueDeclareOptions::default(),
                FieldTable::default(),
            )
            .await
            .expect("queue_declare");

        let chan = channel.clone();
        channel
            .basic_consume(
                "hello",
                "my_consumer",
                BasicConsumeOptions::default(),
                FieldTable::default(),
            )
            .await
            .expect("basic_consume")
            .set_delegate(Box::new(move |delivery: DeliveryResult| {
                info!("received message: {:?}", delivery);
                if let Ok(Some(delivery)) = delivery {
                    chan.basic_ack(delivery.delivery_tag, BasicAckOptions::default())
                        .wait() // await is hard to handle here
                        .expect("basic_ack");
                }
            }));

        let payload = b"Hello world!";
        let confirm = channel
            .basic_publish(
                "",
                "hello",
                BasicPublishOptions::default(),
                payload.to_vec(),
                BasicProperties::default(),
            )
            .await
            .expect("basic_publish")
            .await;
        assert_eq!(confirm, Confirmation::NotRequested);

        std::thread::sleep(std::time::Duration::from_millis(2000));

        info!("Connection will be automatically closed on drop");
    })
}
<|endoftext|>


<commit_before>//! The main entry point for the Space API server.
//!
//! Running this code starts a HTTP server instance. The default port is 3000, but you can set your
//! own favorite port by exporting the `PORT` environment variable.

extern crate rustc_serialize;
extern crate iron;
extern crate spaceapi;

pub mod datastore;
pub mod redis_store;

use std::net::Ipv4Addr;
use std::sync::Mutex;
use std::sync::Arc;

use rustc_serialize::json::ToJson;
use iron::{Request, Response, IronResult, Iron, Set};
use iron::{status, headers, middleware};
use iron::modifiers::Header;

pub use datastore::DataStore;
use spaceapi::Optional::{Value, Absent};

fn build_response_json(people_present: Option<u32>, raspi_temperature: Option<f32>) -> String {
    let people_present_sensor = match people_present {
        Some(count) => Value(vec![
            spaceapi::PeopleNowPresentSensor {
                value: count,
                location: Value("Hackerspace".to_string()),
                name: Absent,
                description: Absent,
                names: Absent,
            }
        ]),
        None => Absent,
    };

    let temperature_sensor = match raspi_temperature {
        Some(degrees) => Value(vec![
            spaceapi::TemperatureSensor {
                value: degrees,
                unit: "°C".to_string(),
                location: "Hackerspace".to_string(),
                name: Value("Raspberry CPU".to_string()),
                description: Absent,
            }
        ]),
        None => Absent,
    };

    let status = spaceapi::Status {

        // Hackerspace properties
        api: "0.13".to_string(),
        space: "coredump".to_string(),
        logo: "https://www.coredump.ch/logo.png".to_string(),
        url: "https://www.coredump.ch/".to_string(),
        location: spaceapi::Location {
            address: Value("Spinnereistrasse 2, 8640 Rapperswil, Switzerland".to_string()),
            lat: 47.22936,
            lon: 8.82949,
        },
        contact: spaceapi::Contact {
            irc: Value("irc://freenode.net/#coredump".to_string()),
            twitter: Value("@coredump_ch".to_string()),
            foursquare: Value("525c20e5498e875d8231b1e5".to_string()),
            email: Value("danilo@coredump.ch".to_string()),
        },

        // Hackerspace features / projects
        spacefed: Value(spaceapi::Spacefed {
            spacenet: false,
            spacesaml: false,
            spacephone: false,
        }),
        projects: Value(vec![
            "https://www.coredump.ch/projekte/".to_string(),
            "https://discourse.coredump.ch/c/projects".to_string(),
            "https://github.com/coredump-ch/".to_string(),
        ]),
        cam: Absent,
        feeds: Value(spaceapi::Feeds {
            blog: Value(spaceapi::Feed {
                _type: Value("rss".to_string()),
                url: "https://www.coredump.ch/feed/".to_string(),
            }),
            wiki: Absent,
            calendar: Absent,
            flickr: Absent,
        }),
        events: Absent,
        radio_show: Absent,

        // SpaceAPI internal usage
        cache: Value(spaceapi::Cache {
            schedule: "m.02".to_string(),
        }),
        issue_report_channels: vec![
            "email".to_string(),
            "twitter".to_string(),
        ],

        // Mutable data
        state: spaceapi::State {
            open: Some(false),
            message: Value("Open every Monday from 20:00".to_string()),
            lastchange: Absent,
            trigger_person: Absent,
            icon: Absent,
        },
        sensors: Value(spaceapi::Sensors {
            people_now_present: people_present_sensor,
            temperature: temperature_sensor,
        }),

    };
    status.to_json().to_string()
}

/// A Space API server instance.
///
/// You can create a new instance using the ``new`` constructor method by
/// passing it the host, the port, the ``Status`` object and a datastore.
///
/// The ``SpaceapiServer`` includes a web server through
/// [Hyper](http://hyper.rs/hyper/hyper/server/index.html). Simply call the ``serve`` method.
pub struct SpaceapiServer {
    host: Ipv4Addr,
    port: u16,
    status: spaceapi::Status,
    datastore: Arc<Mutex<Box<DataStore>>>,
}

impl SpaceapiServer {

    pub fn new(host: Ipv4Addr, port: u16, status: spaceapi::Status, datastore: Arc<Mutex<Box<DataStore>>>) -> SpaceapiServer{
        SpaceapiServer {
            host: host,
            port: port,
            status: status,
            datastore: datastore,
        }
    }

    pub fn serve(self) {
        let host = self.host;
        let port = self.port;
        println!("Starting HTTP server on {}:{}...", host, port);
        Iron::new(self).http((host, port)).unwrap();
    }

}

impl middleware::Handler for SpaceapiServer {

    fn handle(&self, _: &mut Request) -> IronResult<Response> {

        // Fetch data from datastore
        let datastore_clone= self.datastore.clone();
        let datastore_lock = datastore_clone.lock().unwrap();
        let people_present: Option<u32> = match datastore_lock.retrieve("people_present") {
            Ok(v) => match v.parse::<u32>() {
                Ok(i) => Some(i),
                Err(_) => None,
            },
            Err(_) => None,
        };
        let raspi_temperature: Option<f32> = match datastore_lock.retrieve("raspi_temperature") {
            Ok(v) => match v.parse::<f32>() {
                Ok(i) => Some(i),
                Err(_) => None,
            },
            Err(_) => None,
        };

        // Get response body
        let body = build_response_json(people_present, raspi_temperature);

        // Create response
        let mut response = Response::with((status::Ok, body));

        // Set headers
        response.set_mut(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())));
        response.set_mut(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])));
        response.set_mut(Header(headers::AccessControlAllowOrigin::Any));

        Ok(response)
    }
}

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

    #[test]
    /// Verify that the response JSON looks OK.
    fn verify_response_json() {
        let people_present = Some(23);
        let temperature = Some(42.5);
        let json = build_response_json(people_present, temperature);
        assert_eq!(json, "{\
            \"api\":\"0.13\",\
            \"cache\":{\"schedule\":\"m.02\"},\
            \"contact\":{\
                \"email\":\"danilo@coredump.ch\",\
                \"foursquare\":\"525c20e5498e875d8231b1e5\",\
                \"irc\":\"irc://freenode.net/#coredump\",\
                \"twitter\":\"@coredump_ch\"\
            },\
            \"feeds\":{\
                \"blog\":{\"type\":\"rss\",\"url\":\"https://www.coredump.ch/feed/\"}\
            },\
            \"issue_report_channels\":[\"email\",\"twitter\"],\
            \"location\":{\
                \"address\":\"Spinnereistrasse 2, 8640 Rapperswil, Switzerland\",\
                \"lat\":47.22936,\"lon\":8.82949\
            },\
            \"logo\":\"https://www.coredump.ch/logo.png\",\
            \"projects\":[\
                \"https://www.coredump.ch/projekte/\",\
                \"https://discourse.coredump.ch/c/projects\",\
                \"https://github.com/coredump-ch/\"\
            ],\
            \"sensors\":{\
                \"people_now_present\":[{\
                    \"location\":\"Hackerspace\",\"value\":23\
                }],\
                \"temperature\":[{\
                    \"location\":\"Hackerspace\",\"name\":\"Raspberry CPU\",\
                    \"unit\":\"°C\",\"value\":42.5\
                }]\
            },\
            \"space\":\"coredump\",\
            \"spacefed\":{\"spacenet\":false,\"spacephone\":false,\"spacesaml\":false},\
            \"state\":{\"message\":\"Open every Monday from 20:00\",\"open\":false},\
            \"url\":\"https://www.coredump.ch/\"\
        }");
    }
}
<commit_msg>Actually use Status object passed into SpaceapiServer<commit_after>//! The main entry point for the Space API server.
//!
//! Running this code starts a HTTP server instance. The default port is 3000, but you can set your
//! own favorite port by exporting the `PORT` environment variable.

extern crate rustc_serialize;
extern crate iron;
extern crate spaceapi;

pub mod datastore;
pub mod redis_store;

use std::net::Ipv4Addr;
use std::sync::Mutex;
use std::sync::Arc;

use rustc_serialize::json::ToJson;
use iron::{Request, Response, IronResult, Iron, Set};
use iron::{status, headers, middleware};
use iron::modifiers::Header;

pub use datastore::DataStore;
use spaceapi::Optional::{Value, Absent};

fn build_response_json(status: &spaceapi::Status, people_present: Option<u32>, raspi_temperature: Option<f32>) -> String {
    let people_present_sensor = match people_present {
        Some(count) => Value(vec![
            spaceapi::PeopleNowPresentSensor {
                value: count,
                location: Value("Hackerspace".to_string()),
                name: Absent,
                description: Absent,
                names: Absent,
            }
        ]),
        None => Absent,
    };

    let temperature_sensor = match raspi_temperature {
        Some(degrees) => Value(vec![
            spaceapi::TemperatureSensor {
                value: degrees,
                unit: "°C".to_string(),
                location: "Hackerspace".to_string(),
                name: Value("Raspberry CPU".to_string()),
                description: Absent,
            }
        ]),
        None => Absent,
    };

    // Create a mutable copy of the status struct and add sensor data.
    let mut status_copy = (*status).clone();
    status_copy.sensors = Value(spaceapi::Sensors {
        people_now_present: people_present_sensor,
        temperature: temperature_sensor,
    });

    // Serialize to JSON string
    status_copy.to_json().to_string()
}

/// A Space API server instance.
///
/// You can create a new instance using the ``new`` constructor method by
/// passing it the host, the port, the ``Status`` object and a datastore.
///
/// The ``SpaceapiServer`` includes a web server through
/// [Hyper](http://hyper.rs/hyper/hyper/server/index.html). Simply call the ``serve`` method.
pub struct SpaceapiServer {
    host: Ipv4Addr,
    port: u16,
    status: spaceapi::Status,
    datastore: Arc<Mutex<Box<DataStore>>>,
}

impl SpaceapiServer {

    pub fn new(host: Ipv4Addr, port: u16, status: spaceapi::Status, datastore: Arc<Mutex<Box<DataStore>>>) -> SpaceapiServer{
        SpaceapiServer {
            host: host,
            port: port,
            status: status,
            datastore: datastore,
        }
    }

    pub fn serve(self) {
        let host = self.host;
        let port = self.port;
        println!("Starting HTTP server on {}:{}...", host, port);
        Iron::new(self).http((host, port)).unwrap();
    }

}

impl middleware::Handler for SpaceapiServer {

    fn handle(&self, _: &mut Request) -> IronResult<Response> {

        // Fetch data from datastore
        let datastore_clone = self.datastore.clone();
        let datastore_lock = datastore_clone.lock().unwrap();
        let people_present: Option<u32> = match datastore_lock.retrieve("people_present") {
            Ok(v) => match v.parse::<u32>() {
                Ok(i) => Some(i),
                Err(_) => None,
            },
            Err(_) => None,
        };
        let raspi_temperature: Option<f32> = match datastore_lock.retrieve("raspi_temperature") {
            Ok(v) => match v.parse::<f32>() {
                Ok(i) => Some(i),
                Err(_) => None,
            },
            Err(_) => None,
        };

        // Get response body
        let body = build_response_json(&self.status, people_present, raspi_temperature);

        // Create response
        let mut response = Response::with((status::Ok, body));

        // Set headers
        response.set_mut(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())));
        response.set_mut(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])));
        response.set_mut(Header(headers::AccessControlAllowOrigin::Any));

        Ok(response)
    }
}

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

    #[test]
    /// Verify that the response JSON looks OK.
    fn verify_response_json() {
        let people_present = Some(23);
        let temperature = Some(42.5);
        let json = build_response_json(people_present, temperature);
        assert_eq!(json, "{\
            \"api\":\"0.13\",\
            \"cache\":{\"schedule\":\"m.02\"},\
            \"contact\":{\
                \"email\":\"danilo@coredump.ch\",\
                \"foursquare\":\"525c20e5498e875d8231b1e5\",\
                \"irc\":\"irc://freenode.net/#coredump\",\
                \"twitter\":\"@coredump_ch\"\
            },\
            \"feeds\":{\
                \"blog\":{\"type\":\"rss\",\"url\":\"https://www.coredump.ch/feed/\"}\
            },\
            \"issue_report_channels\":[\"email\",\"twitter\"],\
            \"location\":{\
                \"address\":\"Spinnereistrasse 2, 8640 Rapperswil, Switzerland\",\
                \"lat\":47.22936,\"lon\":8.82949\
            },\
            \"logo\":\"https://www.coredump.ch/logo.png\",\
            \"projects\":[\
                \"https://www.coredump.ch/projekte/\",\
                \"https://discourse.coredump.ch/c/projects\",\
                \"https://github.com/coredump-ch/\"\
            ],\
            \"sensors\":{\
                \"people_now_present\":[{\
                    \"location\":\"Hackerspace\",\"value\":23\
                }],\
                \"temperature\":[{\
                    \"location\":\"Hackerspace\",\"name\":\"Raspberry CPU\",\
                    \"unit\":\"°C\",\"value\":42.5\
                }]\
            },\
            \"space\":\"coredump\",\
            \"spacefed\":{\"spacenet\":false,\"spacephone\":false,\"spacesaml\":false},\
            \"state\":{\"message\":\"Open every Monday from 20:00\",\"open\":false},\
            \"url\":\"https://www.coredump.ch/\"\
        }");
    }
}
<|endoftext|>


<commit_before>use std::io::{Read, Seek};
use std::mem;

use postscript;
use postscript::compact::FontSet;
use truetype::{self, Tag, q32};
use truetype::{
    CharMapping,
    FontHeader,
    GlyphData,
    GlyphMapping,
    HorizontalHeader,
    HorizontalMetrics,
    MaximumProfile,
    NamingTable,
    OffsetTable,
    PostScript,
    WindowsMetrics,
};

use Result;

/// A font.
pub struct Font {
    /// The offset table.
    pub offset_table: OffsetTable,

    /// The char-to-glyph mapping (`cmap`).
    pub char_mapping: Option<CharMapping>,
    /// The compact font set (`CFF `).
    pub compact_font_set: Option<FontSet>,
    /// The font header (`head`).
    pub font_header: Option<FontHeader>,
    /// The glyph data (`glyf`).
    pub glyph_data: Option<GlyphData>,
    /// The glyph-to-location mapping (`loca`).
    pub glyph_mapping: Option<GlyphMapping>,
    /// The horizontal header (`hhea`).
    pub horizontal_header: Option<HorizontalHeader>,
    /// The horizontal metrics (`hmtx`).
    pub horizontal_metrics: Option<HorizontalMetrics>,
    /// The maximum profile (`maxp`).
    pub maximum_profile: Option<MaximumProfile>,
    /// The naming table (`name`).
    pub naming_table: Option<NamingTable>,
    /// The PostScript information (`post`).
    pub postscript: Option<PostScript>,
    /// The OS/2 and Windows information (`OS/2`).
    pub windows_metrics: Option<WindowsMetrics>,
}

macro_rules! check_jump(
    ($record:ident, $tape:ident, $process:expr) => ({
        if !try!($record.checksum($tape, $process)) {
            raise!("found a malformed font table");
        }
        try!(truetype::Tape::jump($tape, $record.offset as u64));
    });
    ($record:ident, $tape:ident) => (
        check_jump!($record, $tape, |_, word| word);
    );
);

impl Font {
    /// Read a font.
    pub fn read<T: Read + Seek>(tape: &mut T) -> Result<Font> {
        macro_rules! sort(
            ($records:expr) => ({
                let mut records = $records.iter().collect::<Vec<_>>();
                records.sort_by(|one, another| priority(one.tag).cmp(&priority(another.tag)));
                records
            });
        );

        match try!(truetype::Tape::peek::<q32>(tape)) {
            q32(0x00010000) => {},
            version => match &*Tag::from(version) {
                b"OTTO" => {},
                b"ttcf" => raise!("TrueType collections are not supported yet"),
                _ => raise!("found an unknown font format"),
            },
        }

        let mut font = Font {
            offset_table: try!(truetype::Value::read(tape)),

            char_mapping: None,
            compact_font_set: None,
            font_header: None,
            glyph_data: None,
            glyph_mapping: None,
            horizontal_header: None,
            horizontal_metrics: None,
            maximum_profile: None,
            naming_table: None,
            postscript: None,
            windows_metrics: None,
        };
        for record in sort!(font.offset_table.records) {
            macro_rules! set(
                ($field:ident, $value:expr) => ({
                    check_jump!(record, tape);
                    font.$field = Some(try!($value));
                });
                ($field:ident) => (set!($field, truetype::Value::read(tape)));
            );
            macro_rules! get(
                ($field:ident) => ({
                    match font.$field {
                        Some(ref table) => table,
                        _ => continue,
                    }
                });
            );
            match &*record.tag {
                b"CFF " => set!(compact_font_set, postscript::Value::read(tape)),
                b"OS/2" => set!(windows_metrics),
                b"cmap" => set!(char_mapping),
                b"glyf" => {
                    let mapping = get!(glyph_mapping);
                    set!(glyph_data, truetype::Walue::read(tape, mapping));
                },
                b"head" => {
                    check_jump!(record, tape, |i, word| if i == 2 { 0 } else { word });
                    font.font_header = Some(try!(truetype::Value::read(tape)));
                },
                b"hhea" => set!(horizontal_header),
                b"hmtx" => {
                    let header = get!(horizontal_header);
                    let profile = get!(maximum_profile);
                    set!(horizontal_metrics, truetype::Walue::read(tape, (header, profile)));
                },
                b"loca" => {
                    let header = get!(font_header);
                    let profile = get!(maximum_profile);
                    set!(glyph_mapping, truetype::Walue::read(tape, (header, profile)));
                },
                b"maxp" => set!(maximum_profile),
                b"name" => set!(naming_table),
                b"post" => set!(postscript),
                _ => {},
            }
        }

        Ok(font)
    }
}

fn priority(tag: Tag) -> usize {
    use std::collections::HashMap;
    use std::sync::{Once, ONCE_INIT};

    unsafe {
        static mut PRIORITY: *const HashMap<Tag, usize> = 0 as *const _;
        static ONCE: Once = ONCE_INIT;
        ONCE.call_once(|| {
            let mut map: HashMap<Tag, usize> = HashMap::new();
            map.insert(Tag(*b"glyf"), 43);
            map.insert(Tag(*b"hmtx"), 42);
            map.insert(Tag(*b"loca"), 41);
            PRIORITY = mem::transmute(Box::new(map));
        });
        *(&*PRIORITY).get(&tag).unwrap_or(&0)
    }
}

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

    const CFF: &'static str = "tests/fixtures/SourceSerifPro-Regular.otf";
    const TTF: &'static str = "tests/fixtures/OpenSans-Italic.ttf";

    #[test]
    fn cff() {
        let file = File::open(CFF).unwrap();
        assert!(file[0].compact_font_set.is_some());
    }

    #[test]
    fn ttf() {
        let file = File::open(TTF).unwrap();
        assert!(file[0].glyph_data.is_some());
    }
}
<commit_msg>Add GPOS and GSUB to Font<commit_after>use std::io::{Read, Seek};
use std::mem;

use postscript;
use postscript::compact::FontSet;
use truetype::{self, Tag, q32};
use truetype::{
    CharMapping,
    FontHeader,
    GlyphData,
    GlyphMapping,
    HorizontalHeader,
    HorizontalMetrics,
    MaximumProfile,
    NamingTable,
    OffsetTable,
    PostScript,
    WindowsMetrics,
};

use Result;
use glyph_positioning::GlyphPositioning;
use glyph_substitution::GlyphSubstitution;

/// A font.
pub struct Font {
    /// The offset table.
    pub offset_table: OffsetTable,

    /// The char-to-glyph mapping (`cmap`).
    pub char_mapping: Option<CharMapping>,
    /// The compact font set (`CFF `).
    pub compact_font_set: Option<FontSet>,
    /// The font header (`head`).
    pub font_header: Option<FontHeader>,
    /// The glyph data (`glyf`).
    pub glyph_data: Option<GlyphData>,
    /// The glyph-to-location mapping (`loca`).
    pub glyph_mapping: Option<GlyphMapping>,
    /// The glyph-positioning table (`GPOS`).
    pub glyph_positioning: Option<GlyphPositioning>,
    /// The glyph-substitution table (`GSUB`).
    pub glyph_substitution: Option<GlyphSubstitution>,
    /// The horizontal header (`hhea`).
    pub horizontal_header: Option<HorizontalHeader>,
    /// The horizontal metrics (`hmtx`).
    pub horizontal_metrics: Option<HorizontalMetrics>,
    /// The maximum profile (`maxp`).
    pub maximum_profile: Option<MaximumProfile>,
    /// The naming table (`name`).
    pub naming_table: Option<NamingTable>,
    /// The PostScript information (`post`).
    pub postscript: Option<PostScript>,
    /// The OS/2 and Windows information (`OS/2`).
    pub windows_metrics: Option<WindowsMetrics>,
}

macro_rules! check_jump(
    ($record:ident, $tape:ident, $process:expr) => ({
        if !try!($record.checksum($tape, $process)) {
            raise!("found a malformed font table");
        }
        try!(truetype::Tape::jump($tape, $record.offset as u64));
    });
    ($record:ident, $tape:ident) => (
        check_jump!($record, $tape, |_, word| word);
    );
);

impl Font {
    /// Read a font.
    pub fn read<T: Read + Seek>(tape: &mut T) -> Result<Font> {
        macro_rules! sort(
            ($records:expr) => ({
                let mut records = $records.iter().collect::<Vec<_>>();
                records.sort_by(|one, another| priority(one.tag).cmp(&priority(another.tag)));
                records
            });
        );

        match try!(truetype::Tape::peek::<q32>(tape)) {
            q32(0x00010000) => {},
            version => match &*Tag::from(version) {
                b"OTTO" => {},
                b"ttcf" => raise!("TrueType collections are not supported yet"),
                _ => raise!("found an unknown font format"),
            },
        }

        let mut font = Font {
            offset_table: try!(truetype::Value::read(tape)),

            char_mapping: None,
            compact_font_set: None,
            font_header: None,
            glyph_data: None,
            glyph_mapping: None,
            glyph_positioning: None,
            glyph_substitution: None,
            horizontal_header: None,
            horizontal_metrics: None,
            maximum_profile: None,
            naming_table: None,
            postscript: None,
            windows_metrics: None,
        };
        for record in sort!(font.offset_table.records) {
            macro_rules! set(
                ($field:ident, $value:expr) => ({
                    check_jump!(record, tape);
                    font.$field = Some(try!($value));
                });
                ($field:ident) => (set!($field, truetype::Value::read(tape)));
            );
            macro_rules! get(
                ($field:ident) => ({
                    match font.$field {
                        Some(ref table) => table,
                        _ => continue,
                    }
                });
            );
            match &*record.tag {
                b"CFF " => set!(compact_font_set, postscript::Value::read(tape)),
                b"GPOS" => set!(glyph_positioning),
                b"GSUB" => set!(glyph_substitution),
                b"OS/2" => set!(windows_metrics),
                b"cmap" => set!(char_mapping),
                b"glyf" => {
                    let mapping = get!(glyph_mapping);
                    set!(glyph_data, truetype::Walue::read(tape, mapping));
                },
                b"head" => {
                    check_jump!(record, tape, |i, word| if i == 2 { 0 } else { word });
                    font.font_header = Some(try!(truetype::Value::read(tape)));
                },
                b"hhea" => set!(horizontal_header),
                b"hmtx" => {
                    let header = get!(horizontal_header);
                    let profile = get!(maximum_profile);
                    set!(horizontal_metrics, truetype::Walue::read(tape, (header, profile)));
                },
                b"loca" => {
                    let header = get!(font_header);
                    let profile = get!(maximum_profile);
                    set!(glyph_mapping, truetype::Walue::read(tape, (header, profile)));
                },
                b"maxp" => set!(maximum_profile),
                b"name" => set!(naming_table),
                b"post" => set!(postscript),
                _ => {},
            }
        }

        Ok(font)
    }
}

fn priority(tag: Tag) -> usize {
    use std::collections::HashMap;
    use std::sync::{Once, ONCE_INIT};

    unsafe {
        static mut PRIORITY: *const HashMap<Tag, usize> = 0 as *const _;
        static ONCE: Once = ONCE_INIT;
        ONCE.call_once(|| {
            let mut map: HashMap<Tag, usize> = HashMap::new();
            map.insert(Tag(*b"glyf"), 43);
            map.insert(Tag(*b"hmtx"), 42);
            map.insert(Tag(*b"loca"), 41);
            PRIORITY = mem::transmute(Box::new(map));
        });
        *(&*PRIORITY).get(&tag).unwrap_or(&0)
    }
}

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

    const CFF: &'static str = "tests/fixtures/SourceSerifPro-Regular.otf";
    const TTF: &'static str = "tests/fixtures/OpenSans-Italic.ttf";

    #[test]
    fn cff() {
        let file = File::open(CFF).unwrap();
        assert!(file[0].compact_font_set.is_some());
    }

    #[test]
    fn ttf() {
        let file = File::open(TTF).unwrap();
        assert!(file[0].glyph_data.is_some());
    }
}
<|endoftext|>


<commit_before>//! Concrete error types for all operations which may be invalid in a certain const context.

use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_session::config::nightly_options;
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
use rustc_span::{Span, Symbol};

use super::ConstCx;

/// Emits an error if `op` is not allowed in the given const context.
pub fn non_const<O: NonConstOp>(ccx: &ConstCx<'_, '_>, op: O, span: Span) {
    debug!("illegal_op: op={:?}", op);

    let gate = match op.status_in_item(ccx) {
        Status::Allowed => return,

        Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => {
            let unstable_in_stable = ccx.const_kind() == hir::ConstContext::ConstFn
                && ccx.tcx.features().enabled(sym::staged_api)
                && !ccx.tcx.has_attr(ccx.def_id.to_def_id(), sym::rustc_const_unstable)
                && !super::allow_internal_unstable(ccx.tcx, ccx.def_id.to_def_id(), gate);

            if unstable_in_stable {
                ccx.tcx.sess
                    .struct_span_err(span, &format!("`#[feature({})]` cannot be depended on in a const-stable function", gate.as_str()))
                    .span_suggestion(
                        ccx.body.span,
                        "if it is not part of the public API, make this function unstably const",
                        concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n').to_owned(),
                        Applicability::HasPlaceholders,
                    )
                    .help("otherwise `#[allow_internal_unstable]` can be used to bypass stability checks")
                    .emit();
            }

            return;
        }

        Status::Unstable(gate) => Some(gate),
        Status::Forbidden => None,
    };

    if ccx.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
        ccx.tcx.sess.miri_unleashed_feature(span, gate);
        return;
    }

    op.emit_error(ccx, span);
}

pub enum Status {
    Allowed,
    Unstable(Symbol),
    Forbidden,
}

/// An operation that is not *always* allowed in a const context.
pub trait NonConstOp: std::fmt::Debug {
    /// Returns an enum indicating whether this operation is allowed within the given item.
    fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
        Status::Forbidden
    }

    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        let mut err = struct_span_err!(
            ccx.tcx.sess,
            span,
            E0019,
            "{} contains unimplemented expression type",
            ccx.const_kind()
        );

        if let Status::Unstable(gate) = self.status_in_item(ccx) {
            if !ccx.tcx.features().enabled(gate) && nightly_options::is_nightly_build() {
                err.help(&format!("add `#![feature({})]` to the crate attributes to enable", gate));
            }
        }

        if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
            err.note(
                "A function call isn't allowed in the const's initialization expression \
                      because the expression's value must be known at compile-time.",
            );
            err.note(
                "Remember: you can't use a function call inside a const's initialization \
                      expression! However, you can use it anywhere else.",
            );
        }
        err.emit();
    }
}

/// A function call where the callee is a pointer.
#[derive(Debug)]
pub struct FnCallIndirect;
impl NonConstOp for FnCallIndirect {
    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        let mut err =
            ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn");
        err.emit();
    }
}

/// A function call where the callee is not marked as `const`.
#[derive(Debug)]
pub struct FnCallNonConst(pub DefId);
impl NonConstOp for FnCallNonConst {
    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        let mut err = struct_span_err!(
            ccx.tcx.sess,
            span,
            E0015,
            "calls in {}s are limited to constant functions, \
             tuple structs and tuple variants",
            ccx.const_kind(),
        );
        err.emit();
    }
}

/// A call to a `#[unstable]` const fn or `#[rustc_const_unstable]` function.
///
/// Contains the name of the feature that would allow the use of this function.
#[derive(Debug)]
pub struct FnCallUnstable(pub DefId, pub Symbol);
impl NonConstOp for FnCallUnstable {
    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        let FnCallUnstable(def_id, feature) = *self;

        let mut err = ccx.tcx.sess.struct_span_err(
            span,
            &format!("`{}` is not yet stable as a const fn", ccx.tcx.def_path_str(def_id)),
        );
        if nightly_options::is_nightly_build() {
            err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature));
        }
        err.emit();
    }
}

#[derive(Debug)]
pub struct HeapAllocation;
impl NonConstOp for HeapAllocation {
    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        let mut err = struct_span_err!(
            ccx.tcx.sess,
            span,
            E0010,
            "allocations are not allowed in {}s",
            ccx.const_kind()
        );
        err.span_label(span, format!("allocation not allowed in {}s", ccx.const_kind()));
        if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
            err.note(
                "The value of statics and constants must be known at compile time, \
                 and they live for the entire lifetime of a program. Creating a boxed \
                 value allocates memory on the heap at runtime, and therefore cannot \
                 be done at compile time.",
            );
        }
        err.emit();
    }
}

#[derive(Debug)]
pub struct InlineAsm;
impl NonConstOp for InlineAsm {}

#[derive(Debug)]
pub struct LiveDrop {
    pub dropped_at: Option<Span>,
}
impl NonConstOp for LiveDrop {
    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        let mut diagnostic = struct_span_err!(
            ccx.tcx.sess,
            span,
            E0493,
            "destructors cannot be evaluated at compile-time"
        );
        diagnostic.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind()));
        if let Some(span) = self.dropped_at {
            diagnostic.span_label(span, "value is dropped here");
        }
        diagnostic.emit();
    }
}

#[derive(Debug)]
pub struct CellBorrow;
impl NonConstOp for CellBorrow {
    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        struct_span_err!(
            ccx.tcx.sess,
            span,
            E0492,
            "cannot borrow a constant which may contain \
            interior mutability, create a static instead"
        )
        .emit();
    }
}

#[derive(Debug)]
pub struct MutBorrow;
impl NonConstOp for MutBorrow {
    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
        // Forbid everywhere except in const fn with a feature gate
        if ccx.const_kind() == hir::ConstContext::ConstFn {
            Status::Unstable(sym::const_mut_refs)
        } else {
            Status::Forbidden
        }
    }

    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        let mut err = if ccx.const_kind() == hir::ConstContext::ConstFn {
            feature_err(
                &ccx.tcx.sess.parse_sess,
                sym::const_mut_refs,
                span,
                &format!("mutable references are not allowed in {}s", ccx.const_kind()),
            )
        } else {
            let mut err = struct_span_err!(
                ccx.tcx.sess,
                span,
                E0764,
                "mutable references are not allowed in {}s",
                ccx.const_kind(),
            );
            err.span_label(span, format!("`&mut` is only allowed in `const fn`"));
            err
        };
        if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
            err.note(
                "References in statics and constants may only refer \
                      to immutable values.\n\n\
                      Statics are shared everywhere, and if they refer to \
                      mutable data one might violate memory safety since \
                      holding multiple mutable references to shared data \
                      is not allowed.\n\n\
                      If you really want global mutable state, try using \
                      static mut or a global UnsafeCell.",
            );
        }
        err.emit();
    }
}

// FIXME(ecstaticmorse): Unify this with `MutBorrow`. It has basically the same issues.
#[derive(Debug)]
pub struct MutAddressOf;
impl NonConstOp for MutAddressOf {
    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
        // Forbid everywhere except in const fn with a feature gate
        if ccx.const_kind() == hir::ConstContext::ConstFn {
            Status::Unstable(sym::const_mut_refs)
        } else {
            Status::Forbidden
        }
    }

    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        feature_err(
            &ccx.tcx.sess.parse_sess,
            sym::const_mut_refs,
            span,
            &format!("`&raw mut` is not allowed in {}s", ccx.const_kind()),
        )
        .emit();
    }
}

#[derive(Debug)]
pub struct MutDeref;
impl NonConstOp for MutDeref {
    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
        Status::Unstable(sym::const_mut_refs)
    }
}

#[derive(Debug)]
pub struct Panic;
impl NonConstOp for Panic {
    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
        Status::Unstable(sym::const_panic)
    }

    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        feature_err(
            &ccx.tcx.sess.parse_sess,
            sym::const_panic,
            span,
            &format!("panicking in {}s is unstable", ccx.const_kind()),
        )
        .emit();
    }
}

#[derive(Debug)]
pub struct RawPtrComparison;
impl NonConstOp for RawPtrComparison {
    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        let mut err = ccx
            .tcx
            .sess
            .struct_span_err(span, "pointers cannot be reliably compared during const eval.");
        err.note(
            "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> \
            for more information",
        );
        err.emit();
    }
}

#[derive(Debug)]
pub struct RawPtrDeref;
impl NonConstOp for RawPtrDeref {
    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
        Status::Unstable(sym::const_raw_ptr_deref)
    }

    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        feature_err(
            &ccx.tcx.sess.parse_sess,
            sym::const_raw_ptr_deref,
            span,
            &format!("dereferencing raw pointers in {}s is unstable", ccx.const_kind(),),
        )
        .emit();
    }
}

#[derive(Debug)]
pub struct RawPtrToIntCast;
impl NonConstOp for RawPtrToIntCast {
    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
        Status::Unstable(sym::const_raw_ptr_to_usize_cast)
    }

    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        feature_err(
            &ccx.tcx.sess.parse_sess,
            sym::const_raw_ptr_to_usize_cast,
            span,
            &format!("casting pointers to integers in {}s is unstable", ccx.const_kind(),),
        )
        .emit();
    }
}

/// An access to a (non-thread-local) `static`.
#[derive(Debug)]
pub struct StaticAccess;
impl NonConstOp for StaticAccess {
    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
        if let hir::ConstContext::Static(_) = ccx.const_kind() {
            Status::Allowed
        } else {
            Status::Forbidden
        }
    }

    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        let mut err = struct_span_err!(
            ccx.tcx.sess,
            span,
            E0013,
            "{}s cannot refer to statics",
            ccx.const_kind()
        );
        err.help(
            "consider extracting the value of the `static` to a `const`, and referring to that",
        );
        if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
            err.note(
                "`static` and `const` variables can refer to other `const` variables. \
                    A `const` variable, however, cannot refer to a `static` variable.",
            );
            err.help("To fix this, the value can be extracted to a `const` and then used.");
        }
        err.emit();
    }
}

/// An access to a thread-local `static`.
#[derive(Debug)]
pub struct ThreadLocalAccess;
impl NonConstOp for ThreadLocalAccess {
    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        struct_span_err!(
            ccx.tcx.sess,
            span,
            E0625,
            "thread-local statics cannot be \
            accessed at compile-time"
        )
        .emit();
    }
}

#[derive(Debug)]
pub struct UnionAccess;
impl NonConstOp for UnionAccess {
    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
        // Union accesses are stable in all contexts except `const fn`.
        if ccx.const_kind() != hir::ConstContext::ConstFn {
            Status::Allowed
        } else {
            Status::Unstable(sym::const_fn_union)
        }
    }

    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        feature_err(
            &ccx.tcx.sess.parse_sess,
            sym::const_fn_union,
            span,
            "unions in const fn are unstable",
        )
        .emit();
    }
}
<commit_msg>Useful derives on `ops::Status`<commit_after>//! Concrete error types for all operations which may be invalid in a certain const context.

use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_session::config::nightly_options;
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
use rustc_span::{Span, Symbol};

use super::ConstCx;

/// Emits an error if `op` is not allowed in the given const context.
pub fn non_const<O: NonConstOp>(ccx: &ConstCx<'_, '_>, op: O, span: Span) {
    debug!("illegal_op: op={:?}", op);

    let gate = match op.status_in_item(ccx) {
        Status::Allowed => return,

        Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => {
            let unstable_in_stable = ccx.const_kind() == hir::ConstContext::ConstFn
                && ccx.tcx.features().enabled(sym::staged_api)
                && !ccx.tcx.has_attr(ccx.def_id.to_def_id(), sym::rustc_const_unstable)
                && !super::allow_internal_unstable(ccx.tcx, ccx.def_id.to_def_id(), gate);

            if unstable_in_stable {
                ccx.tcx.sess
                    .struct_span_err(span, &format!("`#[feature({})]` cannot be depended on in a const-stable function", gate.as_str()))
                    .span_suggestion(
                        ccx.body.span,
                        "if it is not part of the public API, make this function unstably const",
                        concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n').to_owned(),
                        Applicability::HasPlaceholders,
                    )
                    .help("otherwise `#[allow_internal_unstable]` can be used to bypass stability checks")
                    .emit();
            }

            return;
        }

        Status::Unstable(gate) => Some(gate),
        Status::Forbidden => None,
    };

    if ccx.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
        ccx.tcx.sess.miri_unleashed_feature(span, gate);
        return;
    }

    op.emit_error(ccx, span);
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Status {
    Allowed,
    Unstable(Symbol),
    Forbidden,
}

/// An operation that is not *always* allowed in a const context.
pub trait NonConstOp: std::fmt::Debug {
    /// Returns an enum indicating whether this operation is allowed within the given item.
    fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
        Status::Forbidden
    }

    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        let mut err = struct_span_err!(
            ccx.tcx.sess,
            span,
            E0019,
            "{} contains unimplemented expression type",
            ccx.const_kind()
        );

        if let Status::Unstable(gate) = self.status_in_item(ccx) {
            if !ccx.tcx.features().enabled(gate) && nightly_options::is_nightly_build() {
                err.help(&format!("add `#![feature({})]` to the crate attributes to enable", gate));
            }
        }

        if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
            err.note(
                "A function call isn't allowed in the const's initialization expression \
                      because the expression's value must be known at compile-time.",
            );
            err.note(
                "Remember: you can't use a function call inside a const's initialization \
                      expression! However, you can use it anywhere else.",
            );
        }
        err.emit();
    }
}

/// A function call where the callee is a pointer.
#[derive(Debug)]
pub struct FnCallIndirect;
impl NonConstOp for FnCallIndirect {
    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        let mut err =
            ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn");
        err.emit();
    }
}

/// A function call where the callee is not marked as `const`.
#[derive(Debug)]
pub struct FnCallNonConst(pub DefId);
impl NonConstOp for FnCallNonConst {
    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        let mut err = struct_span_err!(
            ccx.tcx.sess,
            span,
            E0015,
            "calls in {}s are limited to constant functions, \
             tuple structs and tuple variants",
            ccx.const_kind(),
        );
        err.emit();
    }
}

/// A call to a `#[unstable]` const fn or `#[rustc_const_unstable]` function.
///
/// Contains the name of the feature that would allow the use of this function.
#[derive(Debug)]
pub struct FnCallUnstable(pub DefId, pub Symbol);
impl NonConstOp for FnCallUnstable {
    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        let FnCallUnstable(def_id, feature) = *self;

        let mut err = ccx.tcx.sess.struct_span_err(
            span,
            &format!("`{}` is not yet stable as a const fn", ccx.tcx.def_path_str(def_id)),
        );
        if nightly_options::is_nightly_build() {
            err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature));
        }
        err.emit();
    }
}

#[derive(Debug)]
pub struct HeapAllocation;
impl NonConstOp for HeapAllocation {
    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        let mut err = struct_span_err!(
            ccx.tcx.sess,
            span,
            E0010,
            "allocations are not allowed in {}s",
            ccx.const_kind()
        );
        err.span_label(span, format!("allocation not allowed in {}s", ccx.const_kind()));
        if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
            err.note(
                "The value of statics and constants must be known at compile time, \
                 and they live for the entire lifetime of a program. Creating a boxed \
                 value allocates memory on the heap at runtime, and therefore cannot \
                 be done at compile time.",
            );
        }
        err.emit();
    }
}

#[derive(Debug)]
pub struct InlineAsm;
impl NonConstOp for InlineAsm {}

#[derive(Debug)]
pub struct LiveDrop {
    pub dropped_at: Option<Span>,
}
impl NonConstOp for LiveDrop {
    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        let mut diagnostic = struct_span_err!(
            ccx.tcx.sess,
            span,
            E0493,
            "destructors cannot be evaluated at compile-time"
        );
        diagnostic.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind()));
        if let Some(span) = self.dropped_at {
            diagnostic.span_label(span, "value is dropped here");
        }
        diagnostic.emit();
    }
}

#[derive(Debug)]
pub struct CellBorrow;
impl NonConstOp for CellBorrow {
    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        struct_span_err!(
            ccx.tcx.sess,
            span,
            E0492,
            "cannot borrow a constant which may contain \
            interior mutability, create a static instead"
        )
        .emit();
    }
}

#[derive(Debug)]
pub struct MutBorrow;
impl NonConstOp for MutBorrow {
    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
        // Forbid everywhere except in const fn with a feature gate
        if ccx.const_kind() == hir::ConstContext::ConstFn {
            Status::Unstable(sym::const_mut_refs)
        } else {
            Status::Forbidden
        }
    }

    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        let mut err = if ccx.const_kind() == hir::ConstContext::ConstFn {
            feature_err(
                &ccx.tcx.sess.parse_sess,
                sym::const_mut_refs,
                span,
                &format!("mutable references are not allowed in {}s", ccx.const_kind()),
            )
        } else {
            let mut err = struct_span_err!(
                ccx.tcx.sess,
                span,
                E0764,
                "mutable references are not allowed in {}s",
                ccx.const_kind(),
            );
            err.span_label(span, format!("`&mut` is only allowed in `const fn`"));
            err
        };
        if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
            err.note(
                "References in statics and constants may only refer \
                      to immutable values.\n\n\
                      Statics are shared everywhere, and if they refer to \
                      mutable data one might violate memory safety since \
                      holding multiple mutable references to shared data \
                      is not allowed.\n\n\
                      If you really want global mutable state, try using \
                      static mut or a global UnsafeCell.",
            );
        }
        err.emit();
    }
}

// FIXME(ecstaticmorse): Unify this with `MutBorrow`. It has basically the same issues.
#[derive(Debug)]
pub struct MutAddressOf;
impl NonConstOp for MutAddressOf {
    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
        // Forbid everywhere except in const fn with a feature gate
        if ccx.const_kind() == hir::ConstContext::ConstFn {
            Status::Unstable(sym::const_mut_refs)
        } else {
            Status::Forbidden
        }
    }

    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        feature_err(
            &ccx.tcx.sess.parse_sess,
            sym::const_mut_refs,
            span,
            &format!("`&raw mut` is not allowed in {}s", ccx.const_kind()),
        )
        .emit();
    }
}

#[derive(Debug)]
pub struct MutDeref;
impl NonConstOp for MutDeref {
    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
        Status::Unstable(sym::const_mut_refs)
    }
}

#[derive(Debug)]
pub struct Panic;
impl NonConstOp for Panic {
    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
        Status::Unstable(sym::const_panic)
    }

    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        feature_err(
            &ccx.tcx.sess.parse_sess,
            sym::const_panic,
            span,
            &format!("panicking in {}s is unstable", ccx.const_kind()),
        )
        .emit();
    }
}

#[derive(Debug)]
pub struct RawPtrComparison;
impl NonConstOp for RawPtrComparison {
    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        let mut err = ccx
            .tcx
            .sess
            .struct_span_err(span, "pointers cannot be reliably compared during const eval.");
        err.note(
            "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> \
            for more information",
        );
        err.emit();
    }
}

#[derive(Debug)]
pub struct RawPtrDeref;
impl NonConstOp for RawPtrDeref {
    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
        Status::Unstable(sym::const_raw_ptr_deref)
    }

    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        feature_err(
            &ccx.tcx.sess.parse_sess,
            sym::const_raw_ptr_deref,
            span,
            &format!("dereferencing raw pointers in {}s is unstable", ccx.const_kind(),),
        )
        .emit();
    }
}

#[derive(Debug)]
pub struct RawPtrToIntCast;
impl NonConstOp for RawPtrToIntCast {
    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
        Status::Unstable(sym::const_raw_ptr_to_usize_cast)
    }

    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        feature_err(
            &ccx.tcx.sess.parse_sess,
            sym::const_raw_ptr_to_usize_cast,
            span,
            &format!("casting pointers to integers in {}s is unstable", ccx.const_kind(),),
        )
        .emit();
    }
}

/// An access to a (non-thread-local) `static`.
#[derive(Debug)]
pub struct StaticAccess;
impl NonConstOp for StaticAccess {
    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
        if let hir::ConstContext::Static(_) = ccx.const_kind() {
            Status::Allowed
        } else {
            Status::Forbidden
        }
    }

    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        let mut err = struct_span_err!(
            ccx.tcx.sess,
            span,
            E0013,
            "{}s cannot refer to statics",
            ccx.const_kind()
        );
        err.help(
            "consider extracting the value of the `static` to a `const`, and referring to that",
        );
        if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
            err.note(
                "`static` and `const` variables can refer to other `const` variables. \
                    A `const` variable, however, cannot refer to a `static` variable.",
            );
            err.help("To fix this, the value can be extracted to a `const` and then used.");
        }
        err.emit();
    }
}

/// An access to a thread-local `static`.
#[derive(Debug)]
pub struct ThreadLocalAccess;
impl NonConstOp for ThreadLocalAccess {
    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        struct_span_err!(
            ccx.tcx.sess,
            span,
            E0625,
            "thread-local statics cannot be \
            accessed at compile-time"
        )
        .emit();
    }
}

#[derive(Debug)]
pub struct UnionAccess;
impl NonConstOp for UnionAccess {
    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
        // Union accesses are stable in all contexts except `const fn`.
        if ccx.const_kind() != hir::ConstContext::ConstFn {
            Status::Allowed
        } else {
            Status::Unstable(sym::const_fn_union)
        }
    }

    fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
        feature_err(
            &ccx.tcx.sess.parse_sess,
            sym::const_fn_union,
            span,
            "unions in const fn are unstable",
        )
        .emit();
    }
}
<|endoftext|>


<commit_before>//! Implements two-state "pinger" task that drives sending pings to the server to check liveness of
//! the connection.

use futures::{select, stream::StreamExt};
use std::time::Duration;
use tokio::sync::mpsc;
use tokio::timer::delay_for;

pub(crate) struct Pinger {
    snd_rst: mpsc::Sender<()>,
}

#[derive(Debug)]
pub(crate) enum Event {
    SendPing,
    Disconnect,
}

enum PingerState {
    /// Signal a "ping" on timeout. State moves to `ExpectPong`.
    SendPing,
    /// Signal a "disconnect" on timeout.
    ExpectPong,
}

async fn pinger_task(rcv_rst: mpsc::Receiver<()>, mut snd_ev: mpsc::Sender<Event>) {
    let mut rcv_rst_fused = rcv_rst.fuse();
    let mut state = PingerState::SendPing;
    loop {
        let mut delay = delay_for(Duration::from_secs(30));
        eprintln!("pinger: select");
        select! {
            () = delay => {
                eprintln!("pinger: delay yielded");
                match state {
                    PingerState::SendPing => {
                        state = PingerState::ExpectPong;
                        eprintln!("pinger: SendPing");
                        snd_ev.try_send(Event::SendPing).unwrap();
                    }
                    PingerState::ExpectPong => {
                        eprintln!("pinger: Disconnect");
                        snd_ev.try_send(Event::Disconnect).unwrap();
                        return;
                    }
                }
            }
            cmd = rcv_rst_fused.next() => {
                eprintln!("pinger: rcv_rst yielded");
                match cmd {
                    None => {
                        eprintln!("pinger: Return");
                        return;
                    }
                    Some(()) => {
                        eprintln!("pinger: Reset");
                        state = PingerState::SendPing;
                    }
                }
            }
        }
    }
}

impl Pinger {
    pub(crate) fn new() -> (Pinger, mpsc::Receiver<Event>) {
        let (snd_ev, rcv_ev) = mpsc::channel(1);
        // No need for sending another "reset" when there's already one waiting to be processed
        let (snd_rst, rcv_rst) = mpsc::channel(1);
        tokio::runtime::current_thread::spawn(pinger_task(rcv_rst, snd_ev));
        (Pinger { snd_rst }, rcv_ev)
    }

    pub(crate) fn reset(&mut self) {
        // Ignore errors: no need to send another "reset" when there's already one waiting to be
        // processed
        let _ = self.snd_rst.try_send(());
    }
}
<commit_msg>Fix delay in future in pinger<commit_after>//! Implements two-state "pinger" task that drives sending pings to the server to check liveness of
//! the connection.

use futures::FutureExt;
use futures::{pin_mut, select, stream::StreamExt};
use std::time::Duration;
use tokio::sync::mpsc;
use tokio::timer::delay_for;

pub(crate) struct Pinger {
    snd_rst: mpsc::Sender<()>,
}

#[derive(Debug)]
pub(crate) enum Event {
    SendPing,
    Disconnect,
}

enum PingerState {
    /// Signal a "ping" on timeout. State moves to `ExpectPong`.
    SendPing,
    /// Signal a "disconnect" on timeout.
    ExpectPong,
}

async fn pinger_task(rcv_rst: mpsc::Receiver<()>, mut snd_ev: mpsc::Sender<Event>) {
    let mut rcv_rst_fused = rcv_rst.fuse();
    let mut state = PingerState::SendPing;
    loop {
        // NOTE: The code about does not work:
        // let mut delay = delay_for(Duration::from_secs(30));
        // Instead I need this weird code below. Not sure if this is a bug or not.
        let delay = async {
            delay_for(Duration::from_secs(30)).await;
        }
            .fuse();
        pin_mut!(delay);

        eprintln!("pinger: select");
        select! {
            () = delay => {
                eprintln!("pinger: delay yielded");
                match state {
                    PingerState::SendPing => {
                        state = PingerState::ExpectPong;
                        eprintln!("pinger: SendPing");
                        snd_ev.try_send(Event::SendPing).unwrap();
                    }
                    PingerState::ExpectPong => {
                        eprintln!("pinger: Disconnect");
                        snd_ev.try_send(Event::Disconnect).unwrap();
                        return;
                    }
                }
            }
            cmd = rcv_rst_fused.next() => {
                eprintln!("pinger: rcv_rst yielded");
                match cmd {
                    None => {
                        eprintln!("pinger: Return");
                        return;
                    }
                    Some(()) => {
                        eprintln!("pinger: Reset");
                        state = PingerState::SendPing;
                    }
                }
            }
        }
    }
}

impl Pinger {
    pub(crate) fn new() -> (Pinger, mpsc::Receiver<Event>) {
        let (snd_ev, rcv_ev) = mpsc::channel(1);
        // No need for sending another "reset" when there's already one waiting to be processed
        let (snd_rst, rcv_rst) = mpsc::channel(1);
        tokio::runtime::current_thread::spawn(pinger_task(rcv_rst, snd_ev));
        (Pinger { snd_rst }, rcv_ev)
    }

    pub(crate) fn reset(&mut self) {
        // Ignore errors: no need to send another "reset" when there's already one waiting to be
        // processed
        let _ = self.snd_rst.try_send(());
    }
}
<|endoftext|>


<commit_before>extern crate futures;
extern crate hyper;
extern crate log;
extern crate serde;
extern crate tokio_core;

use super::config;
use futures::{Future, Stream};
use hyper::{Client, Method, Request, Uri};
use hyper::header::{ContentLength, ContentType};
use std::io::{Error, ErrorKind};
use std::str;
use std::str::FromStr;
use tokio_core::reactor::Core;

pub struct Response {
    pub status: u16,
    pub body: String,
}

pub fn request(path: &str, request_body: Option<String>) -> Result<Response, Error> {
    let mut request = Request::new(Method::Post, try!(uri(path)));
    match request_body {
        Some(json) => {
            debug!("Request body: {}", json);
            request.headers_mut().set(ContentType::json());
            request.headers_mut().set(ContentLength(json.len() as u64));
            request.set_body(json);
        }
        _ => {
            debug!("Empty request body...");
        }
    }

    let mut status: u16 = 0;
    let mut body = String::new();
    {
        let mut core = Core::new().unwrap();
        let client = Client::new(&core.handle());
        let work = client
            .request(request)
            .and_then(|res| {
                status = res.status().clone().into();
                res.body().for_each(|chunk| {
                    body.push_str(str::from_utf8(&*chunk).unwrap());
                    futures::future::ok(())
                })
            })
            .map_err(|err| Error::new(ErrorKind::Other, err));
        try!(core.run(work));
    }

    debug!("Response status: {}", status);
    debug!("Response body: {}", body);
    Ok(Response { status, body })
}

fn uri(path: &str) -> Result<Uri, Error> {
    let mut addr = config::base_url().clone();
    addr.push_str(path);
    debug!("Request URL: {}", addr);

    Uri::from_str(&addr).map_err(|err| Error::new(ErrorKind::Other, err))
}
<commit_msg>add tests for mod http<commit_after>extern crate futures;
extern crate hyper;
extern crate log;
extern crate serde;
extern crate tokio_core;

use super::config;
use futures::{Future, Stream};
use hyper::{Client, Method, Request, Uri};
use hyper::header::{ContentLength, ContentType};
use std::io::{Error, ErrorKind};
use std::str::{self, FromStr};
use tokio_core::reactor::Core;

pub struct Response {
    pub status: u16,
    pub body: String,
}

pub fn request(path: &str, request_body: Option<String>) -> Result<Response, Error> {
    let mut request = Request::new(Method::Post, try!(uri(path)));
    match request_body {
        Some(json) => {
            debug!("Request body: {}", json);
            request.headers_mut().set(ContentType::json());
            request.headers_mut().set(ContentLength(json.len() as u64));
            request.set_body(json);
        }
        _ => {
            debug!("Empty request body...");
        }
    }

    let mut status: u16 = 0;
    let mut body = String::new();
    {
        let mut core = Core::new().unwrap();
        let client = Client::new(&core.handle());
        let work = client
            .request(request)
            .and_then(|res| {
                status = res.status().clone().into();
                res.body().for_each(|chunk| {
                    body.push_str(str::from_utf8(&*chunk).unwrap());
                    futures::future::ok(())
                })
            })
            .map_err(|err| Error::new(ErrorKind::Other, err));
        try!(core.run(work));
    }

    debug!("Response status: {}", status);
    debug!("Response body: {}", body);
    Ok(Response { status, body })
}

fn uri(path: &str) -> Result<Uri, Error> {
    let mut addr = config::base_url().clone();
    addr.push_str(path);
    debug!("Request URL: {}", addr);

    Uri::from_str(&addr).map_err(|err| Error::new(ErrorKind::Other, err))
}

#[cfg(test)]
mod tests {

    use super::{request, Response};
    use antidote::Mutex;
    use rand;
    use std::io::Read;

    #[test]
    fn request_with_body_is_content_type_json() {
        let mut body = String::new();
        for _ in 0..10 {
            body.push(rand::random::<u8>() as char);
        }

        let shutdown =
            test_server!((request: &Request) {
            let header = request.header("Content-Type");
            assert!(header.unwrap().starts_with("application/json"));

            ::rouille::Response::empty_404()
        });

        let _r = request("", Some(body));

        // kill server thread
        let _ = shutdown.send(());
    }

    #[test]
    fn send_request_body_if_given() {
        let mut body = String::new();
        for _ in 0..10 {
            body.push(rand::random::<u8>() as char);
        }

        let holder = Mutex::new(hashmap!["body" => body.clone()]);

        let shutdown =
            test_server!((request: &Request) {
            let mut body = String::new();
            let data = request.data();
            let _ = data.unwrap().read_to_string(&mut body);

            assert_eq!(&body, holder.lock().get("body").unwrap());

            ::rouille::Response::empty_404()
        });

        let _r = request("", Some(body));

        // kill server thread
        let _ = shutdown.send(());
    }

    #[test]
    fn if_no_json_is_given_send_empty_request_body() {
        let shutdown =
            test_server!((request: &Request) {
            let mut body = String::new();
            let data = request.data();
            let _ = data.unwrap().read_to_string(&mut body);

            assert_eq!(&body, "");

            ::rouille::Response::empty_404()
        });

        let _r = request("", None);

        // kill server thread
        let _ = shutdown.send(());
    }

    #[test]
    fn response_contains_status_and_body() {
        let shutdown =
            test_server!((request: &Request) {
            ::rouille::Response::text("hello world").with_status_code(500)
        });

        let response: Response = request("", None).unwrap();
        assert_eq!(response.status, 500);
        assert_eq!(response.body, "hello world");

        // kill server thread
        let _ = shutdown.send(());
    }
}
<|endoftext|>


<commit_before>use std::fmt;
// use std::iter;
use std::slice;
use std::ops;
use std::collections::HashMap;
use error::*;

#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub enum Operator {
    Add,
    Sub,
    Mul,
    Div,
}

#[cfg_attr(rustfmt, rustfmt_skip)]
impl fmt::Display for Operator {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Operator::*;
        write!(f, "{}", match *self {
            Add => "+",
            Sub => "-",
            Mul => "*",
            Div => "/",
        })
    }
}

#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub enum Arity {
    Nullary,
    Unary,
    Binary,
    Ternary,
    Multiary,  // 2+ arguments
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Atom {
    Op(Operator),
    // Bool(bool),
    Int(i64),
    // Float(f64),
    // Str(String),
}

impl fmt::Display for Atom {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Atom::*;
        match *self {
            Op(ref t) => write!(f, "{}", t),
            // Bool(ref t) => write!(f, "{}", t),
            Int(ref t) => write!(f, "{}", t),
            // Float(ref t) => write!(f, "{}", t),
            // Str(ref t) => write!(f, "{}", t),
        }
    }
}

impl From<Operator> for Atom {
    fn from(x: Operator) -> Self {
        Atom::Op(x)
    }
}

impl From<i64> for Atom {
    fn from(x: i64) -> Self {
        Atom::Int(x)
    }
}

impl ops::Add<Atom> for Atom {
    type Output = Atom;
    fn add(self, rhs: Atom) -> Self::Output {
        use self::Atom::*;
        match (self, rhs) {
            (Int(i), Int(j)) => Int(i + j),
            _ => panic!(),
        }
    }
}

impl ops::Sub<Atom> for Atom {
    type Output = Atom;
    fn sub(self, rhs: Atom) -> Self::Output {
        use self::Atom::*;
        match (self, rhs) {
            (Int(i), Int(j)) => Int(i - j),
            _ => panic!(),
        }
    }
}

impl ops::Mul<Atom> for Atom {
    type Output = Atom;
    fn mul(self, rhs: Atom) -> Self::Output {
        use self::Atom::*;
        match (self, rhs) {
            (Int(i), Int(j)) => Int(i * j),
            _ => panic!(),
        }
    }
}

impl ops::Div<Atom> for Atom {
    type Output = Atom;
    fn div(self, rhs: Atom) -> Self::Output {
        use self::Atom::*;
        match (self, rhs) {
            (Int(i), Int(j)) => Int(i / j),
            _ => panic!(),
        }
    }
}

// impl iter::Sum<Atom> for Atom {
//     fn sum<I>(iter: I) -> Self where I: Iterator<Item=Atom> {
//         unimplemented!();
//     }
// }

#[derive(Clone, Debug, PartialEq)]
pub enum Value {
    Atom(Atom),
    List(List),
}

impl fmt::Display for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Value::*;
        match *self {
            Atom(ref t) => write!(f, "{}", t),
            List(ref t) => write!(f, "{}", t),
        }
    }
}

impl<T> From<T> for Value where T: Into<Atom> {
    fn from(v: T) -> Self {
        Value::Atom(v.into())
    }
}

impl ops::Add<Value> for Value {
    type Output = Value;
    fn add(self, rhs: Value) -> Self::Output {
        use self::Value::*;
        match (self, rhs) {
            (Atom(i), Atom(j)) => Atom(i + j),
            _ => panic!(),
        }
    }
}

impl ops::Sub<Value> for Value {
    type Output = Value;
    fn sub(self, rhs: Value) -> Self::Output {
        use self::Value::*;
        match (self, rhs) {
            (Atom(i), Atom(j)) => Atom(i - j),
            _ => panic!(),
        }
    }
}

impl ops::Mul<Value> for Value {
    type Output = Value;
    fn mul(self, rhs: Value) -> Self::Output {
        use self::Value::*;
        match (self, rhs) {
            (Atom(i), Atom(j)) => Atom(i * j),
            _ => panic!(),
        }
    }
}

impl ops::Div<Value> for Value {
    type Output = Value;
    fn div(self, rhs: Value) -> Self::Output {
        use self::Value::*;
        match (self, rhs) {
            (Atom(i), Atom(j)) => Atom(i / j),
            _ => panic!(),
        }
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum Node {
    Atom (Atom),
    List (List),
    Expr (Expr),
}

impl Node {
    fn eval(&self) -> Result<Value> {
        use self::Node::*;
        match *self {
            Atom(a) => Ok(Value::Atom(a)),
            List(ref l) => Ok(Value::List(l.clone())),
            Expr(ref e) => e.eval(),
        }
    }
}

impl<T> From<T> for Node where T: Into<Atom> {
    fn from(v: T) -> Self {
        Node::Atom(v.into())
    }
}

// impl<T> From<T> for Node where T: Into<List> {
//     fn from(l: T) -> Self {
//         Node::List(l.into())
//     }
// }
//
// impl<T> From<T> for Node where T: Into<Expr> {
//     fn from(e: T) -> Self {
//         Node::Expr(e.into())
//     }
// }

impl fmt::Display for Node {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Node::*;
        match *self {
            Atom(ref a) => write!(f, "{}", a),
            List(ref l) => write!(f, "{}", l),
            Expr(ref e) => write!(f, "{}", e),
        }
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct List {
    inner: Vec<Node>
}

impl List {
    pub fn new() -> Self {
        List { inner: Vec::new() }
    }
}

impl From<Vec<Node>> for List {
    fn from(v: Vec<Node>) -> Self {
        List { inner: v }
    }
}

impl fmt::Display for List {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let elements = self.inner.iter()
            .map(ToString::to_string)
            .collect::<Vec<_>>()
            .join(" ");
        write!(f, "( {} )", elements)
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct Expr {
    op: Operator,
    args: Vec<Node>
}

impl Expr {
    pub fn new(op: Operator, args: Vec<Node>) -> Self {
        Expr { op: op, args: args }
    }

    pub fn op(&self) -> Operator {
        self.op
    }

    pub fn args(&self) -> slice::Iter<Node> {
        self.args.iter()
    }

    pub fn eval(&self) -> Result<Value> {
        // use self::Node::*;
        // use self::Atom::*;
        use self::Operator::*;
        use self::Arity::*;

        // Arity = number of arguments accepted
        let mut arity = HashMap::new();

        arity.insert(Add, Multiary);
        arity.insert(Sub, Binary);
        arity.insert(Mul, Multiary);
        arity.insert(Div, Binary);

        let op = self.op();
        let args = self.args();
        let num_args = args.len();

        // Check arity
        match arity.get(&op) {
            Some(&Nullary)  => assert_eq!(num_args, 0),
            Some(&Unary)    => assert_eq!(num_args, 1),
            Some(&Binary)   => assert_eq!(num_args, 2),
            Some(&Ternary)  => assert_eq!(num_args, 3),
            Some(&Multiary) => assert!(num_args >= 1),
            None            => unreachable!(),
        };

        match op {
            Add => args.fold(Ok(0.into()), |acc, ref x| {
                let e = try!(x.eval());
                acc.map(|a| a + e)
            }),
            Sub => {
                let mut args = args;
                let a = args.next().unwrap().eval();
                let b = args.next().unwrap().eval();
                a.and_then(|x| b.map(|y| x - y))
                // let a = try!(l[1].eval());
                // let b = try!(l[2].eval());
                // Ok(a - b)
            },
            Mul => args.fold(Ok(1.into()), |acc, ref x| {
                let e = try!(x.eval());
                acc.map(|a| a * e)
            }),
            Div => {
                let mut args = args;
                let a = args.next().unwrap().eval();
                let b = args.next().unwrap().eval();
                a.and_then(|x| b.map(|y| x / y))
            }
        }
    }
}

impl fmt::Display for Expr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let elements = self.args.iter()
            .map(ToString::to_string)
            .collect::<Vec<_>>()
            .join(" ");
        write!(f, "( {} {} )", self.op, elements)
    }
}
<commit_msg>Cleanup, but fail rust borrowck rules<commit_after>use std::fmt;
// use std::iter;
use std::slice;
use std::ops;
use std::collections::HashMap;
use error::*;

#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub enum Operator {
    Add,
    Sub,
    Mul,
    Div,
}

#[cfg_attr(rustfmt, rustfmt_skip)]
impl fmt::Display for Operator {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Operator::*;
        write!(f, "{}", match *self {
            Add => "+",
            Sub => "-",
            Mul => "*",
            Div => "/",
        })
    }
}

#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub enum Arity {
    Nullary,
    Unary,
    Binary,
    Ternary,
    Multiary,  // 2+ arguments
}

impl fmt::Display for Arity {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Arity::*;
        let text = match *self {
            Nullary => "0",
            Unary   => "1",
            Binary  => "2",
            Ternary => "3",
            Multiary => "at least 2",
        };

        write!(f, "{} args", text)
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Atom {
    Op(Operator),
    // Bool(bool),
    Int(i64),
    // Float(f64),
    // Str(String),
}

impl fmt::Display for Atom {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Atom::*;
        match *self {
            Op(ref t) => write!(f, "{}", t),
            // Bool(ref t) => write!(f, "{}", t),
            Int(ref t) => write!(f, "{}", t),
            // Float(ref t) => write!(f, "{}", t),
            // Str(ref t) => write!(f, "{}", t),
        }
    }
}

impl From<Operator> for Atom {
    fn from(x: Operator) -> Self {
        Atom::Op(x)
    }
}

impl From<i64> for Atom {
    fn from(x: i64) -> Self {
        Atom::Int(x)
    }
}

impl ops::Add<Atom> for Atom {
    type Output = Atom;
    fn add(self, rhs: Atom) -> Self::Output {
        use self::Atom::*;
        match (self, rhs) {
            (Int(i), Int(j)) => Int(i + j),
            _ => panic!(),
        }
    }
}

impl ops::Sub<Atom> for Atom {
    type Output = Atom;
    fn sub(self, rhs: Atom) -> Self::Output {
        use self::Atom::*;
        match (self, rhs) {
            (Int(i), Int(j)) => Int(i - j),
            _ => panic!(),
        }
    }
}

impl ops::Mul<Atom> for Atom {
    type Output = Atom;
    fn mul(self, rhs: Atom) -> Self::Output {
        use self::Atom::*;
        match (self, rhs) {
            (Int(i), Int(j)) => Int(i * j),
            _ => panic!(),
        }
    }
}

impl ops::Div<Atom> for Atom {
    type Output = Atom;
    fn div(self, rhs: Atom) -> Self::Output {
        use self::Atom::*;
        match (self, rhs) {
            (Int(i), Int(j)) => Int(i / j),
            _ => panic!(),
        }
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum Value {
    Atom(Atom),
    List(List),
}

impl fmt::Display for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Value::*;
        match *self {
            Atom(ref t) => write!(f, "{}", t),
            List(ref t) => write!(f, "{}", t),
        }
    }
}

impl<T> From<T> for Value where T: Into<Atom> {
    fn from(v: T) -> Self {
        Value::Atom(v.into())
    }
}

impl ops::Add<Value> for Value {
    type Output = Value;
    fn add(self, rhs: Value) -> Self::Output {
        use self::Value::*;
        match (self, rhs) {
            (Atom(i), Atom(j)) => Atom(i + j),
            _ => panic!(),
        }
    }
}

impl ops::Sub<Value> for Value {
    type Output = Value;
    fn sub(self, rhs: Value) -> Self::Output {
        use self::Value::*;
        match (self, rhs) {
            (Atom(i), Atom(j)) => Atom(i - j),
            _ => panic!(),
        }
    }
}

impl ops::Mul<Value> for Value {
    type Output = Value;
    fn mul(self, rhs: Value) -> Self::Output {
        use self::Value::*;
        match (self, rhs) {
            (Atom(i), Atom(j)) => Atom(i * j),
            _ => panic!(),
        }
    }
}

impl ops::Div<Value> for Value {
    type Output = Value;
    fn div(self, rhs: Value) -> Self::Output {
        use self::Value::*;
        match (self, rhs) {
            (Atom(i), Atom(j)) => Atom(i / j),
            _ => panic!(),
        }
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum Node {
    Atom (Atom),
    List (List),
    Expr (Expr),
}

impl Node {
    fn eval(&self) -> Result<Value> {
        use self::Node::*;
        match *self {
            Atom(a) => Ok(Value::Atom(a)),
            List(ref l) => Ok(Value::List(l.clone())),
            Expr(ref e) => e.eval(),
        }
    }
}

impl<T> From<T> for Node where T: Into<Atom> {
    fn from(v: T) -> Self {
        Node::Atom(v.into())
    }
}

// impl<T> From<T> for Node where T: Into<List> {
//     fn from(l: T) -> Self {
//         Node::List(l.into())
//     }
// }
//
// impl<T> From<T> for Node where T: Into<Expr> {
//     fn from(e: T) -> Self {
//         Node::Expr(e.into())
//     }
// }

impl fmt::Display for Node {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Node::*;
        match *self {
            Atom(ref a) => write!(f, "{}", a),
            List(ref l) => write!(f, "{}", l),
            Expr(ref e) => write!(f, "{}", e),
        }
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct List {
    inner: Vec<Node>
}

impl List {
    pub fn new() -> Self {
        List { inner: Vec::new() }
    }
}

impl From<Vec<Node>> for List {
    fn from(v: Vec<Node>) -> Self {
        List { inner: v }
    }
}

impl fmt::Display for List {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let elements = self.inner.iter()
            .map(ToString::to_string)
            .collect::<Vec<_>>()
            .join(" ");
        write!(f, "( {} )", elements)
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct Expr {
    op: Operator,
    args: Vec<Node>
}

impl Expr {
    pub fn new(op: Operator, args: Vec<Node>) -> Self {
        Expr { op: op, args: args }
    }

    pub fn op(&self) -> Operator {
        self.op
    }

    pub fn args(&self) -> slice::Iter<Node> {
        self.args.iter()
    }

    pub fn num_args(&self) -> usize {
        self.args.len()
    }

    pub fn expect_arity(&self, arity: Arity) -> bool {
        use self::Arity::*;
        let num_args = self.num_args();
        match arity {
            Nullary  => num_args == 0,
            Unary    => num_args == 1,
            Binary   => num_args == 2,
            Ternary  => num_args == 3,
            Multiary => num_args >= 2,
        }
    }

    pub fn eval(&self) -> Result<Value> {
        // use self::Node::*;
        // use self::Atom::*;
        use self::Operator::*;
        use self::Arity::*;

        // Arity = number of arguments accepted
        let mut arity = HashMap::new();

        arity.insert(Add, Multiary);
        arity.insert(Sub, Binary);
        arity.insert(Mul, Multiary);
        arity.insert(Div, Binary);

        let op = self.op();

        // Evaluate all arguments
        println!("{:#?}", self.args());
        let mut args: Vec<_> = self.args().map(|x| x.eval()).collect();

        // Check if operator is found
        if let Some(expected_arity) = arity.get(&op) {
            // Return the first expr that cannot eval correctly
            if let &Some(ref err) = args.iter().find(|&x| x.is_err()) {
                (*err).clone()
            }
            // Check if number of arguments match expected number
            else if !self.expect_arity(*expected_arity) {
                Err(format!(
                    "{} operator expected {} arguments, but received {}",
                    op, expected_arity, self.num_args()
                ).into())
            }
            // Perform actual operation
            else {
                let mut eval_args = args.into_iter().map(Result::unwrap);
                match op {
                    Add => Ok(eval_args.fold(0.into(), |acc, x| acc + x)),
                    Sub => {
                        let a = eval_args.next().unwrap();
                        let b = eval_args.next().unwrap();
                        Ok(a - b)
                    },
                    Mul => Ok(eval_args.fold(1.into(), |acc, x| acc * x)),
                    Div => {
                        let a = eval_args.next().unwrap();
                        let b = eval_args.next().unwrap();
                        Ok(a / b)
                    }
                }
            }
        }
        else {
            Err(format!("operator {} not found", op).into())
        }
    }
}

impl fmt::Display for Expr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let elements = self.args.iter()
            .map(ToString::to_string)
            .collect::<Vec<_>>()
            .join(" ");
        write!(f, "( {} {} )", self.op, elements)
    }
}
<|endoftext|>


<commit_before>use ssz_derive::Encode;
use ssz::Encodable;

#[derive(Debug, PartialEq, Encode)]
pub struct Foo {
    a: u16,
    b: Vec<u8>,
    c: u16,
}

#[test]
fn encode() {
    let foo = Foo {
        a: 42,
        b: vec![0, 1, 2, 3],
        c: 11,
    };

    let bytes = vec![42, 0, 8, 0, 0, 0, 11, 0, 0, 1, 2, 3];

    assert_eq!(foo.as_ssz_bytes(), bytes);
}
<commit_msg>Run cargofmt --all<commit_after>use ssz::Encodable;
use ssz_derive::Encode;

#[derive(Debug, PartialEq, Encode)]
pub struct Foo {
    a: u16,
    b: Vec<u8>,
    c: u16,
}

#[test]
fn encode() {
    let foo = Foo {
        a: 42,
        b: vec![0, 1, 2, 3],
        c: 11,
    };

    let bytes = vec![42, 0, 8, 0, 0, 0, 11, 0, 0, 1, 2, 3];

    assert_eq!(foo.as_ssz_bytes(), bytes);
}
<|endoftext|>