<commit_before>//! Simple badge generator

extern crate base64;
extern crate rusttype;

use base64::display::Base64Display;
use rusttype::{Font, FontCollection, Scale, point, Point, PositionedGlyph};

const FONT_DATA: &'static [u8] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"),
                                                        "/DejaVuSans.ttf"));
const FONT_SIZE: f32 = 11.;

pub struct BadgeOptions {
    /// Subject will be displayed on the left side of badge
    pub subject: String,
    /// Status will be displayed on the right side of badge
    pub status: String,
    /// HTML color of badge
    pub color: String,
}

impl Default for BadgeOptions {
    fn default() -> BadgeOptions {
        BadgeOptions {
            subject: "build".to_owned(),
            status: "passing".to_owned(),
            color: "#4c1".to_owned(),
        }
    }
}

pub struct Badge {
    options: BadgeOptions,
    font: Font<'static>,
    scale: Scale,
    offset: Point<f32>,
}

impl Badge {
    pub fn new(options: BadgeOptions) -> Result<Badge, String> {
        let collection = FontCollection::from_bytes(FONT_DATA).expect("Failed to parse FONT_DATA");
        // this should never fail in practice
        let font = try!(collection.into_font().map_err(|_| "Failed to load font data".to_owned()));
        let scale = Scale {
            x: FONT_SIZE,
            y: FONT_SIZE,
        };
        let v_metrics = font.v_metrics(scale);
        let offset = point(0.0, v_metrics.ascent);
        Ok(Badge {
            options: options,
            font: font,
            scale: scale,
            offset: offset,
        })
    }

    pub fn to_svg_data_uri(&self) -> String {
        format!("data:image/svg+xml;base64,{}",
            Base64Display::standard(self.to_svg().as_bytes()))
    }

    pub fn to_svg(&self) -> String {
        let left_width = self.calculate_width(&self.options.subject) + 6;
        let right_width = self.calculate_width(&self.options.status) + 6;

        let svg = format!(r###"<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{}" height="20">
  <linearGradient id="smooth" x2="0" y2="100%">
    <stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
    <stop offset="1" stop-opacity=".1"/>
  </linearGradient>

  <mask id="round">
    <rect width="{}" height="20" rx="3" fill="#fff"/>
  </mask>

  <g mask="url(#round)">
    <rect width="{}" height="20" fill="#555"/>
    <rect x="{}" width="{}" height="20" fill="{}"/>
    <rect width="{}" height="20" fill="url(#smooth)"/>
  </g>

  <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
    <text x="{}" y="15" fill="#010101" fill-opacity=".3">{}</text>
    <text x="{}" y="14">{}</text>
    <text x="{}" y="15" fill="#010101" fill-opacity=".3">{}</text>
    <text x="{}" y="14">{}</text>
  </g>
</svg>"###,
            left_width + right_width,
            left_width + right_width,
            left_width,
            left_width,
            right_width,
            self.options.color,
            left_width + right_width,
            (left_width) / 2,
            self.options.subject,
            (left_width) / 2,
            self.options.subject,
            left_width + (right_width / 2),
            self.options.status,
            left_width + (right_width / 2),
            self.options.status);

        svg
    }

    fn calculate_width(&self, text: &str) -> u32 {
        let glyphs: Vec<PositionedGlyph> =
            self.font.layout(text, self.scale, self.offset).collect();
        let width: u32 = glyphs.iter()
            .rev()
            .filter_map(|g| {
                g.pixel_bounding_box()
                    .map(|b| b.min.x as f32 + g.unpositioned().h_metrics().advance_width)
            })
            .next()
            .unwrap_or(0.0)
            .ceil() as u32;
        width + ((text.len() as u32 - 1) * 2)
    }
}

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

    fn options() -> BadgeOptions {
        BadgeOptions::default()
    }

    #[test]
    fn test_new() {
        assert!(Badge::new(options()).is_ok());
    }

    #[test]
    fn test_calculate_width() {
        let badge = Badge::new(options()).unwrap();
        assert_eq!(badge.calculate_width("build"), 31);
        assert_eq!(badge.calculate_width("passing"), 48);
    }

    #[test]
    #[ignore]
    fn test_to_svg() {
        use std::fs::File;
        use std::io::Write;
        let mut file = File::create("test.svg").unwrap();
        let options = BadgeOptions {
            subject: "build".to_owned(),
            status: "passing".to_owned(),
            ..BadgeOptions::default()
        };
        let badge = Badge::new(options).unwrap();
        file.write_all(badge.to_svg().as_bytes()).unwrap();
    }
}
<commit_msg>Check if status and subject in badge generator is not empty<commit_after>//! Simple badge generator

extern crate base64;
extern crate rusttype;

use base64::display::Base64Display;
use rusttype::{Font, FontCollection, Scale, point, Point, PositionedGlyph};

const FONT_DATA: &'static [u8] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"),
                                                        "/DejaVuSans.ttf"));
const FONT_SIZE: f32 = 11.;

pub struct BadgeOptions {
    /// Subject will be displayed on the left side of badge
    pub subject: String,
    /// Status will be displayed on the right side of badge
    pub status: String,
    /// HTML color of badge
    pub color: String,
}

impl Default for BadgeOptions {
    fn default() -> BadgeOptions {
        BadgeOptions {
            subject: "build".to_owned(),
            status: "passing".to_owned(),
            color: "#4c1".to_owned(),
        }
    }
}

pub struct Badge {
    options: BadgeOptions,
    font: Font<'static>,
    scale: Scale,
    offset: Point<f32>,
}

impl Badge {
    pub fn new(options: BadgeOptions) -> Result<Badge, String> {
        let collection = FontCollection::from_bytes(FONT_DATA).expect("Failed to parse FONT_DATA");
        // this should never fail in practice
        let font = try!(collection.into_font().map_err(|_| "Failed to load font data".to_owned()));
        let scale = Scale {
            x: FONT_SIZE,
            y: FONT_SIZE,
        };
        let v_metrics = font.v_metrics(scale);
        let offset = point(0.0, v_metrics.ascent);
        if options.status.is_empty() || options.subject.is_empty() {
            return Err(String::from("status and subject must not be empty"));
        }
        Ok(Badge {
            options: options,
            font: font,
            scale: scale,
            offset: offset,
        })
    }

    pub fn to_svg_data_uri(&self) -> String {
        format!("data:image/svg+xml;base64,{}",
            Base64Display::standard(self.to_svg().as_bytes()))
    }

    pub fn to_svg(&self) -> String {
        let left_width = self.calculate_width(&self.options.subject) + 6;
        let right_width = self.calculate_width(&self.options.status) + 6;

        let svg = format!(r###"<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{}" height="20">
  <linearGradient id="smooth" x2="0" y2="100%">
    <stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
    <stop offset="1" stop-opacity=".1"/>
  </linearGradient>

  <mask id="round">
    <rect width="{}" height="20" rx="3" fill="#fff"/>
  </mask>

  <g mask="url(#round)">
    <rect width="{}" height="20" fill="#555"/>
    <rect x="{}" width="{}" height="20" fill="{}"/>
    <rect width="{}" height="20" fill="url(#smooth)"/>
  </g>

  <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
    <text x="{}" y="15" fill="#010101" fill-opacity=".3">{}</text>
    <text x="{}" y="14">{}</text>
    <text x="{}" y="15" fill="#010101" fill-opacity=".3">{}</text>
    <text x="{}" y="14">{}</text>
  </g>
</svg>"###,
            left_width + right_width,
            left_width + right_width,
            left_width,
            left_width,
            right_width,
            self.options.color,
            left_width + right_width,
            (left_width) / 2,
            self.options.subject,
            (left_width) / 2,
            self.options.subject,
            left_width + (right_width / 2),
            self.options.status,
            left_width + (right_width / 2),
            self.options.status);

        svg
    }

    fn calculate_width(&self, text: &str) -> u32 {
        let glyphs: Vec<PositionedGlyph> =
            self.font.layout(text, self.scale, self.offset).collect();
        let width: u32 = glyphs.iter()
            .rev()
            .filter_map(|g| {
                g.pixel_bounding_box()
                    .map(|b| b.min.x as f32 + g.unpositioned().h_metrics().advance_width)
            })
            .next()
            .unwrap_or(0.0)
            .ceil() as u32;
        width + ((text.len() as u32 - 1) * 2)
    }
}

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

    fn options() -> BadgeOptions {
        BadgeOptions::default()
    }

    #[test]
    fn test_new() {
        assert!(Badge::new(options()).is_ok());

        let mut bad_options_status = options();
        bad_options_status.status = "".to_owned();
        assert!(Badge::new(bad_options_status).is_err());

        let mut bad_options_subject = options();
        bad_options_subject.subject = "".to_owned();
        assert!(Badge::new(bad_options_subject).is_err());
    }

    #[test]
    fn test_calculate_width() {
        let badge = Badge::new(options()).unwrap();
        assert_eq!(badge.calculate_width("build"), 31);
        assert_eq!(badge.calculate_width("passing"), 48);
    }

    #[test]
    #[ignore]
    fn test_to_svg() {
        use std::fs::File;
        use std::io::Write;
        let mut file = File::create("test.svg").unwrap();
        let options = BadgeOptions {
            subject: "build".to_owned(),
            status: "passing".to_owned(),
            ..BadgeOptions::default()
        };
        let badge = Badge::new(options).unwrap();
        file.write_all(badge.to_svg().as_bytes()).unwrap();
    }
}
<|endoftext|>


<commit_before>//! Endpoints for creating events.

use std::convert::{TryFrom, TryInto};

use bodyparser;
use diesel::{Connection, ExecuteDsl, FindDsl, LoadDsl, insert};
use iron::{Chain, Handler, IronError, IronResult, Plugin, Request, Response, status};
use router::Router;
use ruma_identifiers::{EventId, RoomId, UserId};
use ruma_events::{CustomRoomEvent, EventType};
use ruma_events::call::answer::AnswerEvent;
use ruma_events::call::candidates::CandidatesEvent;
use ruma_events::call::hangup::HangupEvent;
use ruma_events::call::invite::InviteEvent;
use ruma_events::room::message::MessageEvent;
use serde_json::from_value;

use db::DB;
use config::Config;
use error::ApiError;
use event::NewEvent;
use middleware::{AccessTokenAuth, JsonRequest};
use modifier::SerializableResponse;
use room::Room;
use schema::{events, rooms};
use user::User;

#[derive(Debug, Serialize)]
struct SendMessageEventResponse {
    event_id: String,
}

/// The /rooms/:room_id/send/:event_type/:transaction_id endpoint.
pub struct SendMessageEvent;

impl SendMessageEvent {
    /// Create a `SendMessageEvent` with all necessary middleware.
    pub fn chain() -> Chain {
        let mut chain = Chain::new(SendMessageEvent);

        chain.link_before(JsonRequest);
        chain.link_before(AccessTokenAuth);

        chain
    }
}

impl Handler for SendMessageEvent {
    fn handle(&self, request: &mut Request) -> IronResult<Response> {
        let params = request.extensions.get::<Router>().expect("Params object is missing").clone();

        let room_id = match params.find("room_id") {
            Some(room_id) => RoomId::try_from(room_id).map_err(ApiError::from)?,
            None => {
                let error = ApiError::missing_param("room_id");

                return Err(IronError::new(error.clone(), error));
            }
        };

        let event_type = params
            .find("event_type")
            .ok_or(ApiError::missing_param("event_type"))
            .map(EventType::from)?;

        let transaction_id = params
            .find("transaction_id")
            .ok_or(ApiError::missing_param("transaction_id"));

        let user = request.extensions.get::<User>()
            .expect("AccessTokenAuth should ensure a user").clone();

        let event_content = request
            .get::<bodyparser::Json>()
            .expect("JsonRequest verifies the Result is Ok")
            .expect("JsonRequest verifies the Option is Some");
        let config = Config::from_request(request)?;
        let event_id = EventId::new(&config.domain).map_err(ApiError::from)?;
        let user_id = UserId::try_from(&format!("@{}:{}", user.id, config.domain))
            .map_err(ApiError::from)?;

        let room_event: NewEvent = match event_type {
            EventType::CallAnswer => {
                AnswerEvent {
                    content: from_value(event_content).map_err(ApiError::from)?,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: event_type.clone(),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user_id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            EventType::CallCandidates => {
                CandidatesEvent {
                    content: from_value(event_content).map_err(ApiError::from)?,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: event_type.clone(),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user_id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            EventType::CallHangup => {
                HangupEvent {
                    content: from_value(event_content).map_err(ApiError::from)?,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: event_type.clone(),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user_id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            EventType::CallInvite => {
                InviteEvent {
                    content: from_value(event_content).map_err(ApiError::from)?,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: event_type.clone(),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user_id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            EventType::RoomMessage => {
                MessageEvent {
                    content: from_value(event_content).map_err(ApiError::from)?,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: event_type.clone(),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user_id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            EventType::Custom(ref custom_event_type) => {
                CustomRoomEvent {
                    content: event_content,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: EventType::Custom(custom_event_type.clone()),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user_id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            _ => {
                let error = ApiError::bad_event(None);

                return Err(IronError::new(error.clone(), error));
            }
        };

        let connection = DB::from_request(request)?;

        connection.transaction(|| {
            let room = rooms::table.find(room_id.to_string()).first::<Room>(&*connection)?;
            let power_levels = room.current_power_levels(&*connection)?;
            let user_power_level = power_levels
                .users
                .get(&user_id)
                .unwrap_or(&power_levels.users_default);
            let required_power_level = power_levels
                .events
                .get(&event_type)
                .unwrap_or(&power_levels.events_default);

            if required_power_level > user_power_level {
                return Err(ApiError::unauthorized(None));
            }

            insert(&room_event)
                .into(events::table)
                .execute(&*connection)
                .map_err(ApiError::from)
        }).map_err(ApiError::from)?;

        let response = SendMessageEventResponse {
            event_id: event_id.opaque_id().to_string(),
        };

        Ok(Response::with((status::Ok, SerializableResponse(response))))
    }
}
<commit_msg>Add tests for message event creation and fix bugs in the implementation.<commit_after>//! Endpoints for creating events.

use std::convert::{TryFrom, TryInto};

use bodyparser;
use diesel::{Connection, ExecuteDsl, FindDsl, LoadDsl, insert};
use iron::{Chain, Handler, IronError, IronResult, Plugin, Request, Response, status};
use router::Router;
use ruma_identifiers::{EventId, RoomId};
use ruma_events::{CustomRoomEvent, EventType};
use ruma_events::call::answer::AnswerEvent;
use ruma_events::call::candidates::CandidatesEvent;
use ruma_events::call::hangup::HangupEvent;
use ruma_events::call::invite::InviteEvent;
use ruma_events::room::message::MessageEvent;
use serde::Deserialize;
use serde_json::{Value, from_value};

use db::DB;
use config::Config;
use error::{ApiError, MapApiError};
use event::NewEvent;
use middleware::{AccessTokenAuth, JsonRequest};
use modifier::SerializableResponse;
use room::Room;
use schema::{events, rooms};
use user::User;

#[derive(Debug, Serialize)]
struct SendMessageEventResponse {
    event_id: String,
}

/// The /rooms/:room_id/send/:event_type/:transaction_id endpoint.
pub struct SendMessageEvent;

impl SendMessageEvent {
    /// Create a `SendMessageEvent` with all necessary middleware.
    pub fn chain() -> Chain {
        let mut chain = Chain::new(SendMessageEvent);

        chain.link_before(JsonRequest);
        chain.link_before(AccessTokenAuth);

        chain
    }
}

impl Handler for SendMessageEvent {
    fn handle(&self, request: &mut Request) -> IronResult<Response> {
        let params = request.extensions.get::<Router>().expect("Params object is missing").clone();

        let room_id = match params.find("room_id") {
            Some(room_id) => RoomId::try_from(room_id).map_api_err(|_| {
                ApiError::not_found(Some(&format!("No room found with ID {}", room_id)))
            })?,
            None => {
                let error = ApiError::missing_param("room_id");

                return Err(IronError::new(error.clone(), error));
            }
        };

        let event_type = params
            .find("event_type")
            .ok_or(ApiError::missing_param("event_type"))
            .map(EventType::from)?;

        let transaction_id = params
            .find("transaction_id")
            .ok_or(ApiError::missing_param("transaction_id"));

        let user = request.extensions.get::<User>()
            .expect("AccessTokenAuth should ensure a user").clone();

        let event_content = request
            .get::<bodyparser::Json>()
            .expect("JsonRequest verifies the Result is Ok")
            .expect("JsonRequest verifies the Option is Some");
        let config = Config::from_request(request)?;
        let event_id = EventId::new(&config.domain).map_api_err(|_| {
            ApiError::unknown(Some("Failed to generated event ID for the new event."))
        })?;

        let room_event: NewEvent = match event_type {
            EventType::CallAnswer => {
                AnswerEvent {
                    content: extract_event_content(event_content, &event_type)?,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: event_type.clone(),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user.id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            EventType::CallCandidates => {
                CandidatesEvent {
                    content: extract_event_content(event_content, &event_type)?,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: event_type.clone(),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user.id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            EventType::CallHangup => {
                HangupEvent {
                    content: extract_event_content(event_content, &event_type)?,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: event_type.clone(),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user.id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            EventType::CallInvite => {
                InviteEvent {
                    content: extract_event_content(event_content, &event_type)?,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: event_type.clone(),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user.id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            EventType::RoomMessage => {
                MessageEvent {
                    content: extract_event_content(event_content, &event_type)?,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: event_type.clone(),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user.id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            EventType::Custom(ref custom_event_type) => {
                CustomRoomEvent {
                    content: event_content,
                    event_id: event_id.clone(),
                    extra_content: (),
                    event_type: EventType::Custom(custom_event_type.clone()),
                    room_id: room_id.clone(),
                    unsigned: None,
                    user_id: user.id.clone(),
                }.try_into().map_err(ApiError::from)?
            }
            _ => {
                let error = ApiError::bad_event(
                    Some(&format!("Events of type {} cannot be created with this API.", event_type))
                );

                return Err(IronError::new(error.clone(), error));
            }
        };

        let connection = DB::from_request(request)?;

        connection.transaction(|| {
            let room = rooms::table.find(room_id.to_string()).first::<Room>(&*connection)?;
            let power_levels = room.current_power_levels(&*connection)?;
            let user_power_level = power_levels
                .users
                .get(&user.id)
                .unwrap_or(&power_levels.users_default);
            let required_power_level = power_levels
                .events
                .get(&event_type)
                .unwrap_or(&power_levels.events_default);

            if required_power_level > user_power_level {
                return Err(ApiError::unauthorized(None));
            }

            insert(&room_event)
                .into(events::table)
                .execute(&*connection)
                .map_err(ApiError::from)
        }).map_err(ApiError::from)?;

        let response = SendMessageEventResponse {
            event_id: event_id.opaque_id().to_string(),
        };

        Ok(Response::with((status::Ok, SerializableResponse(response))))
    }
}

fn extract_event_content<T: Deserialize>(event_content: Value, event_type: &EventType)
-> Result<T, ApiError> {
    from_value(event_content).map_api_err(|_| {
        ApiError::bad_event(
            Some(
                &format!(
                    "Event content did not match expected structure for event of type {}.",
                    event_type
                )
            )
        )
    })
}

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

    #[test]
    fn create_message_event() {
        let test = Test::new();
        let access_token = test.create_access_token();

        let create_room_path = format!(
            "/_matrix/client/r0/createRoom?access_token={}",
            access_token
        );

        let create_room_response = test.post(&create_room_path, "{}");

        let room_id = create_room_response.json().find("room_id").unwrap().as_str().unwrap();

        let create_event_path = format!(
            "/_matrix/client/r0/rooms/{}/send/m.room.message/1?access_token={}",
            room_id,
            access_token
        );

        let response = test.put(&create_event_path, r#"{"body":"Hi","msgtype":"m.text"}"#);

        assert!(response.json().find("event_id").unwrap().as_str().is_some());
    }

    #[test]
    fn event_content_does_not_match_event_type() {
        let test = Test::new();
        let access_token = test.create_access_token();

        let create_room_path = format!(
            "/_matrix/client/r0/createRoom?access_token={}",
            access_token
        );

        let create_room_response = test.post(&create_room_path, "{}");

        let room_id = create_room_response.json().find("room_id").unwrap().as_str().unwrap();

        let create_event_path = format!(
            "/_matrix/client/r0/rooms/{}/send/m.call.answer/1?access_token={}",
            room_id,
            access_token
        );

        let response = test.put(&create_event_path, r#"{"body":"Hi","msgtype":"m.text"}"#);

        let json = response.json();

        assert_eq!(json.find("errcode").unwrap().as_str().unwrap(), "IO.RUMA_BAD_EVENT");
        assert_eq!(
            json.find("error").unwrap().as_str().unwrap(),
            "Event content did not match expected structure for event of type m.call.answer."
        );
    }

    #[test]
    fn non_message_event_type() {
        let test = Test::new();
        let access_token = test.create_access_token();

        let create_room_path = format!(
            "/_matrix/client/r0/createRoom?access_token={}",
            access_token
        );

        let create_room_response = test.post(&create_room_path, "{}");

        let room_id = create_room_response.json().find("room_id").unwrap().as_str().unwrap();

        let create_event_path = format!(
            "/_matrix/client/r0/rooms/{}/send/m.room.topic/1?access_token={}",
            room_id,
            access_token
        );

        let response = test.put(&create_event_path, r#"{"topic":"fail"}"#);

        let json = response.json();

        assert_eq!(json.find("errcode").unwrap().as_str().unwrap(), "IO.RUMA_BAD_EVENT");
        assert_eq!(
            json.find("error").unwrap().as_str().unwrap(),
            "Events of type m.room.topic cannot be created with this API."
        );
    }

    #[test]
    fn custom_message_event() {
        let test = Test::new();
        let access_token = test.create_access_token();

        let create_room_path = format!(
            "/_matrix/client/r0/createRoom?access_token={}",
            access_token
        );

        let create_room_response = test.post(&create_room_path, "{}");

        let room_id = create_room_response.json().find("room_id").unwrap().as_str().unwrap();

        let create_event_path = format!(
            "/_matrix/client/r0/rooms/{}/send/io.ruma.test/1?access_token={}",
            room_id,
            access_token
        );

        let response = test.put(&create_event_path, r#"{"foo":"bar"}"#);

        assert!(response.json().find("event_id").unwrap().as_str().is_some());
    }
}
<|endoftext|>


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

use std::f32::consts::{FRAC_1_SQRT_2};
use euclid::{Point2D, Rect, Size2D};
use euclid::{TypedRect, TypedPoint2D, TypedSize2D, TypedMatrix4D};
use webrender_traits::{DeviceIntRect, DeviceIntPoint, DeviceIntSize};
use webrender_traits::{LayerRect, WorldPoint4D, LayerPoint4D, LayerToWorldTransform};
use webrender_traits::{BorderRadius, ComplexClipRegion, LayoutRect};
use num_traits::Zero;

// Matches the definition of SK_ScalarNearlyZero in Skia.
const NEARLY_ZERO: f32 = 1.0 / 4096.0;

// TODO: Implement these in euclid!
pub trait MatrixHelpers<Src, Dst> {
    fn transform_rect(&self, rect: &TypedRect<f32, Src>) -> TypedRect<f32, Dst>;
    fn is_identity(&self) -> bool;
    fn preserves_2d_axis_alignment(&self) -> bool;
}

impl<Src, Dst> MatrixHelpers<Src, Dst> for TypedMatrix4D<f32, Src, Dst> {
    fn transform_rect(&self, rect: &TypedRect<f32, Src>) -> TypedRect<f32, Dst> {
        let top_left = self.transform_point(&rect.origin);
        let top_right = self.transform_point(&rect.top_right());
        let bottom_left = self.transform_point(&rect.bottom_left());
        let bottom_right = self.transform_point(&rect.bottom_right());
        TypedRect::from_points(&[top_left, top_right, bottom_right, bottom_left])
    }

    fn is_identity(&self) -> bool {
        *self == TypedMatrix4D::identity()
    }

    // A port of the preserves2dAxisAlignment function in Skia.
    // Defined in the SkMatrix44 class.
    fn preserves_2d_axis_alignment(&self) -> bool {
        if self.m14 != 0.0 || self.m24 != 0.0 {
            return false;
        }

        let mut col0 = 0;
        let mut col1 = 0;
        let mut row0 = 0;
        let mut row1 = 0;

        if self.m11.abs() > NEARLY_ZERO {
            col0 += 1;
            row0 += 1;
        }
        if self.m12.abs() > NEARLY_ZERO {
            col1 += 1;
            row0 += 1;
        }
        if self.m21.abs() > NEARLY_ZERO {
            col0 += 1;
            row1 += 1;
        }
        if self.m22.abs() > NEARLY_ZERO {
            col1 += 1;
            row1 += 1;
        }

        col0 < 2 && col1 < 2 && row0 < 2 && row1 < 2
    }
}

pub trait RectHelpers<U> where Self: Sized {
    fn contains_rect(&self, other: &Self) -> bool;
    fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self;
    fn is_well_formed_and_nonempty(&self) -> bool;
}

impl<U> RectHelpers<U> for TypedRect<f32, U> {

    fn contains_rect(&self, other: &Self) -> bool {
        self.origin.x <= other.origin.x &&
        self.origin.y <= other.origin.y &&
        self.max_x() >= other.max_x() &&
        self.max_y() >= other.max_y()
    }

    fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self {
        TypedRect::new(TypedPoint2D::new(x0, y0),
                       TypedSize2D::new(x1 - x0, y1 - y0))
    }

    fn is_well_formed_and_nonempty(&self) -> bool {
        self.size.width > 0.0 && self.size.height > 0.0
    }
}

// Don't use `euclid`'s `is_empty` because that has effectively has an "and" in the conditional
// below instead of an "or".
pub fn rect_is_empty<N:PartialEq + Zero, U>(rect: &TypedRect<N, U>) -> bool {
    rect.size.width == Zero::zero() || rect.size.height == Zero::zero()
}

#[inline]
pub fn rect_from_points_f(x0: f32,
                          y0: f32,
                          x1: f32,
                          y1: f32) -> Rect<f32> {
    Rect::new(Point2D::new(x0, y0),
              Size2D::new(x1 - x0, y1 - y0))
}

pub fn lerp(a: f32, b: f32, t: f32) -> f32 {
    (b - a) * t + a
}

pub fn subtract_rect<U>(rect: &TypedRect<f32, U>,
                        other: &TypedRect<f32, U>,
                        results: &mut Vec<TypedRect<f32, U>>) {
    results.clear();

    let int = rect.intersection(other);
    match int {
        Some(int) => {
            let rx0 = rect.origin.x;
            let ry0 = rect.origin.y;
            let rx1 = rx0 + rect.size.width;
            let ry1 = ry0 + rect.size.height;

            let ox0 = int.origin.x;
            let oy0 = int.origin.y;
            let ox1 = ox0 + int.size.width;
            let oy1 = oy0 + int.size.height;

            let r = TypedRect::from_untyped(&rect_from_points_f(rx0, ry0, ox0, ry1));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
            let r = TypedRect::from_untyped(&rect_from_points_f(ox0, ry0, ox1, oy0));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
            let r = TypedRect::from_untyped(&rect_from_points_f(ox0, oy1, ox1, ry1));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
            let r = TypedRect::from_untyped(&rect_from_points_f(ox1, ry0, rx1, ry1));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
        }
        None => {
            results.push(*rect);
        }
    }
}

pub fn get_normal(x: f32) -> Option<f32> {
    if x.is_normal() {
        Some(x)
    } else {
        None
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[repr(u8)]
pub enum TransformedRectKind {
    AxisAligned = 0,
    Complex = 1,
}

#[derive(Debug, Clone)]
pub struct TransformedRect {
    pub local_rect: LayerRect,
    pub bounding_rect: DeviceIntRect,
    pub inner_rect: DeviceIntRect,
    pub vertices: [WorldPoint4D; 4],
    pub kind: TransformedRectKind,
}

impl TransformedRect {
    pub fn new(rect: &LayerRect,
               transform: &LayerToWorldTransform,
               device_pixel_ratio: f32) -> TransformedRect {

        let kind = if transform.preserves_2d_axis_alignment() {
            TransformedRectKind::AxisAligned
        } else {
            TransformedRectKind::Complex
        };

        // FIXME(gw): This code is meant to be a fast path for simple transforms.
        // However, it fails on transforms that translate Z but result in an
        // axis aligned rect.

/*
        match kind {
            TransformedRectKind::AxisAligned => {
                let v0 = transform.transform_point(&rect.origin);
                let v1 = transform.transform_point(&rect.top_right());
                let v2 = transform.transform_point(&rect.bottom_left());
                let v3 = transform.transform_point(&rect.bottom_right());

                let screen_min_dp = Point2D::new(DevicePixel((v0.x * device_pixel_ratio).floor() as i32),
                                                 DevicePixel((v0.y * device_pixel_ratio).floor() as i32));
                let screen_max_dp = Point2D::new(DevicePixel((v3.x * device_pixel_ratio).ceil() as i32),
                                                 DevicePixel((v3.y * device_pixel_ratio).ceil() as i32));

                let screen_rect_dp = Rect::new(screen_min_dp, Size2D::new(screen_max_dp.x - screen_min_dp.x,
                                                                          screen_max_dp.y - screen_min_dp.y));

                TransformedRect {
                    local_rect: *rect,
                    vertices: [
                        Point4D::new(v0.x, v0.y, 0.0, 1.0),
                        Point4D::new(v1.x, v1.y, 0.0, 1.0),
                        Point4D::new(v2.x, v2.y, 0.0, 1.0),
                        Point4D::new(v3.x, v3.y, 0.0, 1.0),
                    ],
                    bounding_rect: screen_rect_dp,
                    kind: kind,
                }
            }
            TransformedRectKind::Complex => {
                */
                let vertices = [
                    transform.transform_point4d(&LayerPoint4D::new(rect.origin.x,
                                                                   rect.origin.y,
                                                                   0.0,
                                                                   1.0)),
                    transform.transform_point4d(&LayerPoint4D::new(rect.bottom_left().x,
                                                                   rect.bottom_left().y,
                                                                   0.0,
                                                                   1.0)),
                    transform.transform_point4d(&LayerPoint4D::new(rect.bottom_right().x,
                                                                   rect.bottom_right().y,
                                                                   0.0,
                                                                   1.0)),
                    transform.transform_point4d(&LayerPoint4D::new(rect.top_right().x,
                                                                   rect.top_right().y,
                                                                   0.0,
                                                                   1.0)),
                ];

                let (mut xs, mut ys) = ([0.0; 4], [0.0; 4]);

                for (vertex, (x, y)) in vertices.iter().zip(xs.iter_mut().zip(ys.iter_mut())) {
                    let inv_w = 1.0 / vertex.w;
                    *x = get_normal(vertex.x * inv_w).unwrap_or(0.0);
                    *y = get_normal(vertex.y * inv_w).unwrap_or(0.0);
                }

                xs.sort_by(|a, b| a.partial_cmp(b).unwrap());
                ys.sort_by(|a, b| a.partial_cmp(b).unwrap());

                let outer_min_dp = DeviceIntPoint::new((xs[0] * device_pixel_ratio).floor() as i32,
                                                       (ys[0] * device_pixel_ratio).floor() as i32);
                let outer_max_dp = DeviceIntPoint::new((xs[3] * device_pixel_ratio).ceil() as i32,
                                                       (ys[3] * device_pixel_ratio).ceil() as i32);
                let inner_min_dp = DeviceIntPoint::new((xs[1] * device_pixel_ratio).ceil() as i32,
                                                       (ys[1] * device_pixel_ratio).ceil() as i32);
                let inner_max_dp = DeviceIntPoint::new((xs[2] * device_pixel_ratio).floor() as i32,
                                                       (ys[2] * device_pixel_ratio).floor() as i32);

                TransformedRect {
                    local_rect: *rect,
                    vertices: vertices,
                    bounding_rect: DeviceIntRect::new(outer_min_dp,
                                                      DeviceIntSize::new(outer_max_dp.x - outer_min_dp.x,
                                                                         outer_max_dp.y - outer_min_dp.y)),
                    inner_rect: DeviceIntRect::new(inner_min_dp,
                                                   DeviceIntSize::new(inner_max_dp.x - inner_min_dp.x,
                                                                      inner_max_dp.y - inner_min_dp.y)),
                    kind: kind,
                }
                /*
            }
        }*/
    }
}

#[inline(always)]
pub fn pack_as_float(value: u32) -> f32 {
    value as f32 + 0.5
}

pub trait ComplexClipRegionHelpers {
    /// Return an aligned rectangle that is inside the clip region and doesn't intersect
    /// any of the bounding rectangles of the rounded corners.
    fn get_inner_rect_safe(&self) -> Option<LayoutRect>;
    /// Return the approximately largest aligned rectangle that is fully inside
    /// the provided clip region.
    fn get_inner_rect_full(&self) -> Option<LayoutRect>;
}

impl ComplexClipRegionHelpers for ComplexClipRegion {
    fn get_inner_rect_safe(&self) -> Option<LayoutRect> {
        // value of `k==1.0` is used for extraction of the corner rectangles
        // see `SEGMENT_CORNER_*` in `clip_shared.glsl`
        extract_inner_rect_impl(&self.rect, &self.radii, 1.0)
    }

    fn get_inner_rect_full(&self) -> Option<LayoutRect> {
        // this `k` optimal for a simple case of all border radii being equal
        let k = 1.0 - 0.5 * FRAC_1_SQRT_2; // could be nicely approximated to `0.3`
        extract_inner_rect_impl(&self.rect, &self.radii, k)
    }
}

#[inline]
fn extract_inner_rect_impl<U>(rect: &TypedRect<f32, U>,
                              radii: &BorderRadius,
                              k: f32) -> Option<TypedRect<f32, U>> {
    // `k` defines how much border is taken into account
    // We enforce the offsets to be rounded to pixel boundaries
    // by `ceil`-ing and `floor`-ing them

    let xl = (k * radii.top_left.width.max(radii.bottom_left.width)).ceil();
    let xr = (rect.size.width - k * radii.top_right.width.max(radii.bottom_right.width)).floor();
    let yt = (k * radii.top_left.height.max(radii.top_right.height)).ceil();
    let yb = (rect.size.height - k * radii.bottom_left.height.max(radii.bottom_right.height)).floor();

    if xl <= xr && yt <= yb {
        Some(TypedRect::new(TypedPoint2D::new(rect.origin.x + xl, rect.origin.y + yt),
             TypedSize2D::new(xr-xl, yb-yt)))
    } else {
        None
    }
}

/// Consumes the old vector and returns a new one that may reuse the old vector's allocated
/// memory.
pub fn recycle_vec<T>(mut old_vec: Vec<T>) -> Vec<T> {
    if old_vec.capacity() > 2 * old_vec.len() {
        // Avoid reusing the buffer if it is a lot larger than it needs to be. This prevents
        // a frame with exceptionally large allocations to cause subsequent frames to retain
        // more memory than they need.
        return Vec::with_capacity(old_vec.len());
    }

    old_vec.clear();

    return old_vec;
}
<commit_msg>Auto merge of #1302 - kvark:trect, r=glennw<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::f32::consts::{FRAC_1_SQRT_2};
use euclid::{Point2D, Rect, Size2D};
use euclid::{TypedRect, TypedPoint2D, TypedSize2D, TypedMatrix4D};
use webrender_traits::{DeviceIntRect, DeviceIntPoint, DeviceIntSize};
use webrender_traits::{LayerRect, WorldPoint4D, LayerPoint4D, LayerToWorldTransform};
use webrender_traits::{BorderRadius, ComplexClipRegion, LayoutRect};
use num_traits::Zero;

// Matches the definition of SK_ScalarNearlyZero in Skia.
const NEARLY_ZERO: f32 = 1.0 / 4096.0;

// TODO: Implement these in euclid!
pub trait MatrixHelpers<Src, Dst> {
    fn transform_rect(&self, rect: &TypedRect<f32, Src>) -> TypedRect<f32, Dst>;
    fn is_identity(&self) -> bool;
    fn preserves_2d_axis_alignment(&self) -> bool;
}

impl<Src, Dst> MatrixHelpers<Src, Dst> for TypedMatrix4D<f32, Src, Dst> {
    fn transform_rect(&self, rect: &TypedRect<f32, Src>) -> TypedRect<f32, Dst> {
        let top_left = self.transform_point(&rect.origin);
        let top_right = self.transform_point(&rect.top_right());
        let bottom_left = self.transform_point(&rect.bottom_left());
        let bottom_right = self.transform_point(&rect.bottom_right());
        TypedRect::from_points(&[top_left, top_right, bottom_right, bottom_left])
    }

    fn is_identity(&self) -> bool {
        *self == TypedMatrix4D::identity()
    }

    // A port of the preserves2dAxisAlignment function in Skia.
    // Defined in the SkMatrix44 class.
    fn preserves_2d_axis_alignment(&self) -> bool {
        if self.m14 != 0.0 || self.m24 != 0.0 {
            return false;
        }

        let mut col0 = 0;
        let mut col1 = 0;
        let mut row0 = 0;
        let mut row1 = 0;

        if self.m11.abs() > NEARLY_ZERO {
            col0 += 1;
            row0 += 1;
        }
        if self.m12.abs() > NEARLY_ZERO {
            col1 += 1;
            row0 += 1;
        }
        if self.m21.abs() > NEARLY_ZERO {
            col0 += 1;
            row1 += 1;
        }
        if self.m22.abs() > NEARLY_ZERO {
            col1 += 1;
            row1 += 1;
        }

        col0 < 2 && col1 < 2 && row0 < 2 && row1 < 2
    }
}

pub trait RectHelpers<U> where Self: Sized {
    fn contains_rect(&self, other: &Self) -> bool;
    fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self;
    fn is_well_formed_and_nonempty(&self) -> bool;
}

impl<U> RectHelpers<U> for TypedRect<f32, U> {

    fn contains_rect(&self, other: &Self) -> bool {
        self.origin.x <= other.origin.x &&
        self.origin.y <= other.origin.y &&
        self.max_x() >= other.max_x() &&
        self.max_y() >= other.max_y()
    }

    fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self {
        TypedRect::new(TypedPoint2D::new(x0, y0),
                       TypedSize2D::new(x1 - x0, y1 - y0))
    }

    fn is_well_formed_and_nonempty(&self) -> bool {
        self.size.width > 0.0 && self.size.height > 0.0
    }
}

// Don't use `euclid`'s `is_empty` because that has effectively has an "and" in the conditional
// below instead of an "or".
pub fn rect_is_empty<N:PartialEq + Zero, U>(rect: &TypedRect<N, U>) -> bool {
    rect.size.width == Zero::zero() || rect.size.height == Zero::zero()
}

#[inline]
pub fn rect_from_points_f(x0: f32,
                          y0: f32,
                          x1: f32,
                          y1: f32) -> Rect<f32> {
    Rect::new(Point2D::new(x0, y0),
              Size2D::new(x1 - x0, y1 - y0))
}

pub fn lerp(a: f32, b: f32, t: f32) -> f32 {
    (b - a) * t + a
}

pub fn subtract_rect<U>(rect: &TypedRect<f32, U>,
                        other: &TypedRect<f32, U>,
                        results: &mut Vec<TypedRect<f32, U>>) {
    results.clear();

    let int = rect.intersection(other);
    match int {
        Some(int) => {
            let rx0 = rect.origin.x;
            let ry0 = rect.origin.y;
            let rx1 = rx0 + rect.size.width;
            let ry1 = ry0 + rect.size.height;

            let ox0 = int.origin.x;
            let oy0 = int.origin.y;
            let ox1 = ox0 + int.size.width;
            let oy1 = oy0 + int.size.height;

            let r = TypedRect::from_untyped(&rect_from_points_f(rx0, ry0, ox0, ry1));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
            let r = TypedRect::from_untyped(&rect_from_points_f(ox0, ry0, ox1, oy0));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
            let r = TypedRect::from_untyped(&rect_from_points_f(ox0, oy1, ox1, ry1));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
            let r = TypedRect::from_untyped(&rect_from_points_f(ox1, ry0, rx1, ry1));
            if r.size.width > 0.0 && r.size.height > 0.0 {
                results.push(r);
            }
        }
        None => {
            results.push(*rect);
        }
    }
}

pub fn get_normal(x: f32) -> Option<f32> {
    if x.is_normal() {
        Some(x)
    } else {
        None
    }
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[repr(u8)]
pub enum TransformedRectKind {
    AxisAligned = 0,
    Complex = 1,
}

#[derive(Debug, Clone)]
pub struct TransformedRect {
    pub local_rect: LayerRect,
    pub bounding_rect: DeviceIntRect,
    pub inner_rect: DeviceIntRect,
    pub vertices: [WorldPoint4D; 4],
    pub kind: TransformedRectKind,
}

impl TransformedRect {
    pub fn new(rect: &LayerRect,
               transform: &LayerToWorldTransform,
               device_pixel_ratio: f32) -> TransformedRect {

        let kind = if transform.preserves_2d_axis_alignment() {
            TransformedRectKind::AxisAligned
        } else {
            TransformedRectKind::Complex
        };

        // FIXME(gw): This code is meant to be a fast path for simple transforms.
        // However, it fails on transforms that translate Z but result in an
        // axis aligned rect.

/*
        match kind {
            TransformedRectKind::AxisAligned => {
                let v0 = transform.transform_point(&rect.origin);
                let v1 = transform.transform_point(&rect.top_right());
                let v2 = transform.transform_point(&rect.bottom_left());
                let v3 = transform.transform_point(&rect.bottom_right());

                let screen_min_dp = Point2D::new(DevicePixel((v0.x * device_pixel_ratio).floor() as i32),
                                                 DevicePixel((v0.y * device_pixel_ratio).floor() as i32));
                let screen_max_dp = Point2D::new(DevicePixel((v3.x * device_pixel_ratio).ceil() as i32),
                                                 DevicePixel((v3.y * device_pixel_ratio).ceil() as i32));

                let screen_rect_dp = Rect::new(screen_min_dp, Size2D::new(screen_max_dp.x - screen_min_dp.x,
                                                                          screen_max_dp.y - screen_min_dp.y));

                TransformedRect {
                    local_rect: *rect,
                    vertices: [
                        Point4D::new(v0.x, v0.y, 0.0, 1.0),
                        Point4D::new(v1.x, v1.y, 0.0, 1.0),
                        Point4D::new(v2.x, v2.y, 0.0, 1.0),
                        Point4D::new(v3.x, v3.y, 0.0, 1.0),
                    ],
                    bounding_rect: screen_rect_dp,
                    kind: kind,
                }
            }
            TransformedRectKind::Complex => {
                */
                let vertices = [
                    transform.transform_point4d(&LayerPoint4D::new(rect.origin.x,
                                                                   rect.origin.y,
                                                                   0.0,
                                                                   1.0)),
                    transform.transform_point4d(&LayerPoint4D::new(rect.bottom_left().x,
                                                                   rect.bottom_left().y,
                                                                   0.0,
                                                                   1.0)),
                    transform.transform_point4d(&LayerPoint4D::new(rect.bottom_right().x,
                                                                   rect.bottom_right().y,
                                                                   0.0,
                                                                   1.0)),
                    transform.transform_point4d(&LayerPoint4D::new(rect.top_right().x,
                                                                   rect.top_right().y,
                                                                   0.0,
                                                                   1.0)),
                ];

                let (mut xs, mut ys) = ([0.0; 4], [0.0; 4]);

                for (vertex, (x, y)) in vertices.iter().zip(xs.iter_mut().zip(ys.iter_mut())) {
                    let inv_w = 1.0 / vertex.w;
                    *x = get_normal(vertex.x * inv_w).unwrap_or(0.0);
                    *y = get_normal(vertex.y * inv_w).unwrap_or(0.0);
                }

                xs.sort_by(|a, b| a.partial_cmp(b).unwrap());
                ys.sort_by(|a, b| a.partial_cmp(b).unwrap());

                let outer_min_dp = DeviceIntPoint::new((xs[0] * device_pixel_ratio).floor() as i32,
                                                       (ys[0] * device_pixel_ratio).floor() as i32);
                let outer_max_dp = DeviceIntPoint::new((xs[3] * device_pixel_ratio).ceil() as i32,
                                                       (ys[3] * device_pixel_ratio).ceil() as i32);
                let inner_min_dp = DeviceIntPoint::new((xs[1] * device_pixel_ratio).ceil() as i32,
                                                       (ys[1] * device_pixel_ratio).ceil() as i32);
                let inner_max_dp = DeviceIntPoint::new((xs[2] * device_pixel_ratio).floor() as i32,
                                                       (ys[2] * device_pixel_ratio).floor() as i32);

                TransformedRect {
                    local_rect: *rect,
                    vertices: vertices,
                    bounding_rect: DeviceIntRect::new(outer_min_dp,
                                                      DeviceIntSize::new(outer_max_dp.x.saturating_sub(outer_min_dp.x),
                                                                         outer_max_dp.y.saturating_sub(outer_min_dp.y))),
                    inner_rect: DeviceIntRect::new(inner_min_dp,
                                                   DeviceIntSize::new(inner_max_dp.x.saturating_sub(inner_min_dp.x),
                                                                      inner_max_dp.y.saturating_sub(inner_min_dp.y))),
                    kind: kind,
                }
                /*
            }
        }*/
    }
}

#[inline(always)]
pub fn pack_as_float(value: u32) -> f32 {
    value as f32 + 0.5
}

pub trait ComplexClipRegionHelpers {
    /// Return an aligned rectangle that is inside the clip region and doesn't intersect
    /// any of the bounding rectangles of the rounded corners.
    fn get_inner_rect_safe(&self) -> Option<LayoutRect>;
    /// Return the approximately largest aligned rectangle that is fully inside
    /// the provided clip region.
    fn get_inner_rect_full(&self) -> Option<LayoutRect>;
}

impl ComplexClipRegionHelpers for ComplexClipRegion {
    fn get_inner_rect_safe(&self) -> Option<LayoutRect> {
        // value of `k==1.0` is used for extraction of the corner rectangles
        // see `SEGMENT_CORNER_*` in `clip_shared.glsl`
        extract_inner_rect_impl(&self.rect, &self.radii, 1.0)
    }

    fn get_inner_rect_full(&self) -> Option<LayoutRect> {
        // this `k` optimal for a simple case of all border radii being equal
        let k = 1.0 - 0.5 * FRAC_1_SQRT_2; // could be nicely approximated to `0.3`
        extract_inner_rect_impl(&self.rect, &self.radii, k)
    }
}

#[inline]
fn extract_inner_rect_impl<U>(rect: &TypedRect<f32, U>,
                              radii: &BorderRadius,
                              k: f32) -> Option<TypedRect<f32, U>> {
    // `k` defines how much border is taken into account
    // We enforce the offsets to be rounded to pixel boundaries
    // by `ceil`-ing and `floor`-ing them

    let xl = (k * radii.top_left.width.max(radii.bottom_left.width)).ceil();
    let xr = (rect.size.width - k * radii.top_right.width.max(radii.bottom_right.width)).floor();
    let yt = (k * radii.top_left.height.max(radii.top_right.height)).ceil();
    let yb = (rect.size.height - k * radii.bottom_left.height.max(radii.bottom_right.height)).floor();

    if xl <= xr && yt <= yb {
        Some(TypedRect::new(TypedPoint2D::new(rect.origin.x + xl, rect.origin.y + yt),
             TypedSize2D::new(xr-xl, yb-yt)))
    } else {
        None
    }
}

/// Consumes the old vector and returns a new one that may reuse the old vector's allocated
/// memory.
pub fn recycle_vec<T>(mut old_vec: Vec<T>) -> Vec<T> {
    if old_vec.capacity() > 2 * old_vec.len() {
        // Avoid reusing the buffer if it is a lot larger than it needs to be. This prevents
        // a frame with exceptionally large allocations to cause subsequent frames to retain
        // more memory than they need.
        return Vec::with_capacity(old_vec.len());
    }

    old_vec.clear();

    return old_vec;
}
<|endoftext|>


<commit_before>// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.

use std::{fmt, mem, result};

use super::get_fdt_addr;
use kvm_bindings::{
    kvm_regs, user_pt_regs, KVM_REG_ARM64, KVM_REG_ARM64_SYSREG, KVM_REG_ARM64_SYSREG_CRM_MASK,
    KVM_REG_ARM64_SYSREG_CRM_SHIFT, KVM_REG_ARM64_SYSREG_CRN_MASK, KVM_REG_ARM64_SYSREG_CRN_SHIFT,
    KVM_REG_ARM64_SYSREG_OP0_MASK, KVM_REG_ARM64_SYSREG_OP0_SHIFT, KVM_REG_ARM64_SYSREG_OP1_MASK,
    KVM_REG_ARM64_SYSREG_OP1_SHIFT, KVM_REG_ARM64_SYSREG_OP2_MASK, KVM_REG_ARM64_SYSREG_OP2_SHIFT,
    KVM_REG_ARM_CORE, KVM_REG_SIZE_U64,
};
use kvm_ioctls::VcpuFd;
use vm_memory::GuestMemoryMmap;

/// Errors thrown while setting aarch64 registers.
#[derive(Debug)]
pub enum Error {
    /// Failed to set core register (PC, PSTATE or general purpose ones).
    SetCoreRegister(kvm_ioctls::Error),
    /// Failed to get a system register.
    GetSysRegister(kvm_ioctls::Error),
}
type Result<T> = result::Result<T, Error>;

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            self::Error::SetCoreRegister(ref e) => write!(f, "Failed to set core register: {}", e),
            self::Error::GetSysRegister(ref e) => write!(f, "Failed to get system register: {}", e),
        }
    }
}

#[allow(non_upper_case_globals)]
// PSR (Processor State Register) bits.
// Taken from arch/arm64/include/uapi/asm/ptrace.h.
const PSR_MODE_EL1h: u64 = 0x0000_0005;
const PSR_F_BIT: u64 = 0x0000_0040;
const PSR_I_BIT: u64 = 0x0000_0080;
const PSR_A_BIT: u64 = 0x0000_0100;
const PSR_D_BIT: u64 = 0x0000_0200;
// Taken from arch/arm64/kvm/inject_fault.c.
const PSTATE_FAULT_BITS_64: u64 = PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | PSR_I_BIT | PSR_D_BIT;

// Following are macros that help with getting the ID of a aarch64 core register.
// The core register are represented by the user_pt_regs structure. Look for it in
// arch/arm64/include/uapi/asm/ptrace.h.

// This macro gets the offset of a structure (i.e `str`) member (i.e `field`) without having
// an instance of that structure.
// It uses a null pointer to retrieve the offset to the field.
// Inspired by C solution: `#define offsetof(str, f) ((size_t)(&((str *)0)->f))`.
// Doing `offset__of!(user_pt_regs, pstate)` in our rust code will trigger the following:
// unsafe { &(*(0 as *const user_pt_regs)).pstate as *const _ as usize }
// The dereference expression produces an lvalue, but that lvalue is not actually read from,
// we're just doing pointer math on it, so in theory, it should safe.
macro_rules! offset__of {
    ($str:ty, $field:ident) => {
        unsafe { &(*(std::ptr::null::<$str>())).$field as *const _ as usize }
    };
}

macro_rules! arm64_core_reg_id {
    ($size: tt, $offset: tt) => {
        // The core registers of an arm64 machine are represented
        // in kernel by the `kvm_regs` structure. This structure is a
        // mix of 32, 64 and 128 bit fields:
        // struct kvm_regs {
        //     struct user_pt_regs      regs;
        //
        //     __u64                    sp_el1;
        //     __u64                    elr_el1;
        //
        //     __u64                    spsr[KVM_NR_SPSR];
        //
        //     struct user_fpsimd_state fp_regs;
        // };
        // struct user_pt_regs {
        //     __u64 regs[31];
        //     __u64 sp;
        //     __u64 pc;
        //     __u64 pstate;
        // };
        // The id of a core register can be obtained like this:
        // offset = id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE). Thus,
        // id = KVM_REG_ARM64 | KVM_REG_SIZE_U64/KVM_REG_SIZE_U32/KVM_REG_SIZE_U128 | KVM_REG_ARM_CORE | offset
        KVM_REG_ARM64 as u64
            | u64::from(KVM_REG_ARM_CORE)
            | $size
            | (($offset / mem::size_of::<u32>()) as u64)
    };
}

// This macro computes the ID of a specific ARM64 system register similar to how
// the kernel C macro does.
// https://elixir.bootlin.com/linux/v4.20.17/source/arch/arm64/include/uapi/asm/kvm.h#L203
macro_rules! arm64_sys_reg {
    ($name: tt, $op0: tt, $op1: tt, $crn: tt, $crm: tt, $op2: tt) => {
        const $name: u64 = KVM_REG_ARM64 as u64
            | KVM_REG_SIZE_U64 as u64
            | KVM_REG_ARM64_SYSREG as u64
            | ((($op0 as u64) << KVM_REG_ARM64_SYSREG_OP0_SHIFT)
                & KVM_REG_ARM64_SYSREG_OP0_MASK as u64)
            | ((($op1 as u64) << KVM_REG_ARM64_SYSREG_OP1_SHIFT)
                & KVM_REG_ARM64_SYSREG_OP1_MASK as u64)
            | ((($crn as u64) << KVM_REG_ARM64_SYSREG_CRN_SHIFT)
                & KVM_REG_ARM64_SYSREG_CRN_MASK as u64)
            | ((($crm as u64) << KVM_REG_ARM64_SYSREG_CRM_SHIFT)
                & KVM_REG_ARM64_SYSREG_CRM_MASK as u64)
            | ((($op2 as u64) << KVM_REG_ARM64_SYSREG_OP2_SHIFT)
                & KVM_REG_ARM64_SYSREG_OP2_MASK as u64);
    };
}

// Constant imported from the Linux kernel:
// https://elixir.bootlin.com/linux/v4.20.17/source/arch/arm64/include/asm/sysreg.h#L135
arm64_sys_reg!(MPIDR_EL1, 3, 0, 0, 0, 5);

/// Configure relevant boot registers for a given vCPU.
///
/// # Arguments
///
/// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
/// * `cpu_id` - Index of current vcpu.
/// * `boot_ip` - Starting instruction pointer.
/// * `mem` - Reserved DRAM for current VM.
pub fn setup_boot_regs(
    vcpu: &VcpuFd,
    cpu_id: u8,
    boot_ip: u64,
    mem: &GuestMemoryMmap,
) -> Result<()> {
    let kreg_off = offset__of!(kvm_regs, regs);

    // Get the register index of the PSTATE (Processor State) register.
    let pstate = offset__of!(user_pt_regs, pstate) + kreg_off;
    vcpu.set_one_reg(
        arm64_core_reg_id!(KVM_REG_SIZE_U64, pstate),
        PSTATE_FAULT_BITS_64,
    )
    .map_err(Error::SetCoreRegister)?;

    // Other vCPUs are powered off initially awaiting PSCI wakeup.
    if cpu_id == 0 {
        // Setting the PC (Processor Counter) to the current program address (kernel address).
        let pc = offset__of!(user_pt_regs, pc) + kreg_off;
        vcpu.set_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, pc), boot_ip as u64)
            .map_err(Error::SetCoreRegister)?;

        // Last mandatory thing to set -> the address pointing to the FDT (also called DTB).
        // "The device tree blob (dtb) must be placed on an 8-byte boundary and must
        // not exceed 2 megabytes in size." -> https://www.kernel.org/doc/Documentation/arm64/booting.txt.
        // We are choosing to place it the end of DRAM. See `get_fdt_addr`.
        let regs0 = offset__of!(user_pt_regs, regs) + kreg_off;
        vcpu.set_one_reg(
            arm64_core_reg_id!(KVM_REG_SIZE_U64, regs0),
            get_fdt_addr(mem) as u64,
        )
        .map_err(Error::SetCoreRegister)?;
    }
    Ok(())
}

/// Read the MPIDR - Multiprocessor Affinity Register.
///
/// # Arguments
///
/// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
pub fn read_mpidr(vcpu: &VcpuFd) -> Result<u64> {
    vcpu.get_one_reg(MPIDR_EL1).map_err(Error::GetSysRegister)
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::aarch64::{arch_memory_regions, layout};
    use kvm_ioctls::Kvm;

    #[test]
    fn test_setup_regs() {
        let kvm = Kvm::new().unwrap();
        let vm = kvm.create_vm().unwrap();
        let vcpu = vm.create_vcpu(0).unwrap();
        let regions = arch_memory_regions(layout::FDT_MAX_SIZE + 0x1000);
        let mem = GuestMemoryMmap::from_ranges(&regions).expect("Cannot initialize memory");

        let res = setup_boot_regs(&vcpu, 0, 0x0, &mem);
        assert!(res.is_err());
        assert_eq!(
            format!("{}", res.unwrap_err()),
            "Failed to set core register: Exec format error (os error 8)"
        );

        let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default();
        vm.get_preferred_target(&mut kvi).unwrap();
        vcpu.vcpu_init(&kvi).unwrap();

        assert!(setup_boot_regs(&vcpu, 0, 0x0, &mem).is_ok());
    }
    #[test]
    fn test_read_mpidr() {
        let kvm = Kvm::new().unwrap();
        let vm = kvm.create_vm().unwrap();
        let vcpu = vm.create_vcpu(0).unwrap();
        let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default();
        vm.get_preferred_target(&mut kvi).unwrap();

        // Must fail when vcpu is not initialized yet.
        let res = read_mpidr(&vcpu);
        assert!(res.is_err());
        assert_eq!(
            format!("{}", res.unwrap_err()),
            "Failed to get system register: Exec format error (os error 8)"
        );

        vcpu.vcpu_init(&kvi).unwrap();
        assert_eq!(read_mpidr(&vcpu).unwrap(), 0x8000_0000);
    }
}
<commit_msg>aarch64: function for filtering system registers<commit_after>// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.

use std::{fmt, mem, result};

use super::get_fdt_addr;
use kvm_bindings::{
    kvm_regs, user_pt_regs, KVM_REG_ARM64, KVM_REG_ARM64_SYSREG, KVM_REG_ARM64_SYSREG_CRM_MASK,
    KVM_REG_ARM64_SYSREG_CRM_SHIFT, KVM_REG_ARM64_SYSREG_CRN_MASK, KVM_REG_ARM64_SYSREG_CRN_SHIFT,
    KVM_REG_ARM64_SYSREG_OP0_MASK, KVM_REG_ARM64_SYSREG_OP0_SHIFT, KVM_REG_ARM64_SYSREG_OP1_MASK,
    KVM_REG_ARM64_SYSREG_OP1_SHIFT, KVM_REG_ARM64_SYSREG_OP2_MASK, KVM_REG_ARM64_SYSREG_OP2_SHIFT,
    KVM_REG_ARM_COPROC_MASK, KVM_REG_ARM_CORE, KVM_REG_SIZE_MASK, KVM_REG_SIZE_U32,
    KVM_REG_SIZE_U64,
};
use kvm_ioctls::VcpuFd;
use vm_memory::GuestMemoryMmap;

/// Errors thrown while setting aarch64 registers.
#[derive(Debug)]
pub enum Error {
    /// Failed to set core register (PC, PSTATE or general purpose ones).
    SetCoreRegister(kvm_ioctls::Error),
    /// Failed to get a system register.
    GetSysRegister(kvm_ioctls::Error),
}
type Result<T> = result::Result<T, Error>;

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            self::Error::SetCoreRegister(ref e) => write!(f, "Failed to set core register: {}", e),
            self::Error::GetSysRegister(ref e) => write!(f, "Failed to get system register: {}", e),
        }
    }
}

#[allow(non_upper_case_globals)]
// PSR (Processor State Register) bits.
// Taken from arch/arm64/include/uapi/asm/ptrace.h.
const PSR_MODE_EL1h: u64 = 0x0000_0005;
const PSR_F_BIT: u64 = 0x0000_0040;
const PSR_I_BIT: u64 = 0x0000_0080;
const PSR_A_BIT: u64 = 0x0000_0100;
const PSR_D_BIT: u64 = 0x0000_0200;
// Taken from arch/arm64/kvm/inject_fault.c.
const PSTATE_FAULT_BITS_64: u64 = PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | PSR_I_BIT | PSR_D_BIT;

// Following are macros that help with getting the ID of a aarch64 core register.
// The core register are represented by the user_pt_regs structure. Look for it in
// arch/arm64/include/uapi/asm/ptrace.h.

// This macro gets the offset of a structure (i.e `str`) member (i.e `field`) without having
// an instance of that structure.
// It uses a null pointer to retrieve the offset to the field.
// Inspired by C solution: `#define offsetof(str, f) ((size_t)(&((str *)0)->f))`.
// Doing `offset__of!(user_pt_regs, pstate)` in our rust code will trigger the following:
// unsafe { &(*(0 as *const user_pt_regs)).pstate as *const _ as usize }
// The dereference expression produces an lvalue, but that lvalue is not actually read from,
// we're just doing pointer math on it, so in theory, it should safe.
macro_rules! offset__of {
    ($str:ty, $field:ident) => {
        unsafe { &(*(std::ptr::null::<$str>())).$field as *const _ as usize }
    };
}

macro_rules! arm64_core_reg_id {
    ($size: tt, $offset: tt) => {
        // The core registers of an arm64 machine are represented
        // in kernel by the `kvm_regs` structure. This structure is a
        // mix of 32, 64 and 128 bit fields:
        // struct kvm_regs {
        //     struct user_pt_regs      regs;
        //
        //     __u64                    sp_el1;
        //     __u64                    elr_el1;
        //
        //     __u64                    spsr[KVM_NR_SPSR];
        //
        //     struct user_fpsimd_state fp_regs;
        // };
        // struct user_pt_regs {
        //     __u64 regs[31];
        //     __u64 sp;
        //     __u64 pc;
        //     __u64 pstate;
        // };
        // The id of a core register can be obtained like this:
        // offset = id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE). Thus,
        // id = KVM_REG_ARM64 | KVM_REG_SIZE_U64/KVM_REG_SIZE_U32/KVM_REG_SIZE_U128 | KVM_REG_ARM_CORE | offset
        KVM_REG_ARM64 as u64
            | u64::from(KVM_REG_ARM_CORE)
            | $size
            | (($offset / mem::size_of::<u32>()) as u64)
    };
}

// This macro computes the ID of a specific ARM64 system register similar to how
// the kernel C macro does.
// https://elixir.bootlin.com/linux/v4.20.17/source/arch/arm64/include/uapi/asm/kvm.h#L203
macro_rules! arm64_sys_reg {
    ($name: tt, $op0: tt, $op1: tt, $crn: tt, $crm: tt, $op2: tt) => {
        const $name: u64 = KVM_REG_ARM64 as u64
            | KVM_REG_SIZE_U64 as u64
            | KVM_REG_ARM64_SYSREG as u64
            | ((($op0 as u64) << KVM_REG_ARM64_SYSREG_OP0_SHIFT)
                & KVM_REG_ARM64_SYSREG_OP0_MASK as u64)
            | ((($op1 as u64) << KVM_REG_ARM64_SYSREG_OP1_SHIFT)
                & KVM_REG_ARM64_SYSREG_OP1_MASK as u64)
            | ((($crn as u64) << KVM_REG_ARM64_SYSREG_CRN_SHIFT)
                & KVM_REG_ARM64_SYSREG_CRN_MASK as u64)
            | ((($crm as u64) << KVM_REG_ARM64_SYSREG_CRM_SHIFT)
                & KVM_REG_ARM64_SYSREG_CRM_MASK as u64)
            | ((($op2 as u64) << KVM_REG_ARM64_SYSREG_OP2_SHIFT)
                & KVM_REG_ARM64_SYSREG_OP2_MASK as u64);
    };
}

// Constant imported from the Linux kernel:
// https://elixir.bootlin.com/linux/v4.20.17/source/arch/arm64/include/asm/sysreg.h#L135
arm64_sys_reg!(MPIDR_EL1, 3, 0, 0, 0, 5);

/// Configure relevant boot registers for a given vCPU.
///
/// # Arguments
///
/// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
/// * `cpu_id` - Index of current vcpu.
/// * `boot_ip` - Starting instruction pointer.
/// * `mem` - Reserved DRAM for current VM.
pub fn setup_boot_regs(
    vcpu: &VcpuFd,
    cpu_id: u8,
    boot_ip: u64,
    mem: &GuestMemoryMmap,
) -> Result<()> {
    let kreg_off = offset__of!(kvm_regs, regs);

    // Get the register index of the PSTATE (Processor State) register.
    let pstate = offset__of!(user_pt_regs, pstate) + kreg_off;
    vcpu.set_one_reg(
        arm64_core_reg_id!(KVM_REG_SIZE_U64, pstate),
        PSTATE_FAULT_BITS_64,
    )
    .map_err(Error::SetCoreRegister)?;

    // Other vCPUs are powered off initially awaiting PSCI wakeup.
    if cpu_id == 0 {
        // Setting the PC (Processor Counter) to the current program address (kernel address).
        let pc = offset__of!(user_pt_regs, pc) + kreg_off;
        vcpu.set_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, pc), boot_ip as u64)
            .map_err(Error::SetCoreRegister)?;

        // Last mandatory thing to set -> the address pointing to the FDT (also called DTB).
        // "The device tree blob (dtb) must be placed on an 8-byte boundary and must
        // not exceed 2 megabytes in size." -> https://www.kernel.org/doc/Documentation/arm64/booting.txt.
        // We are choosing to place it the end of DRAM. See `get_fdt_addr`.
        let regs0 = offset__of!(user_pt_regs, regs) + kreg_off;
        vcpu.set_one_reg(
            arm64_core_reg_id!(KVM_REG_SIZE_U64, regs0),
            get_fdt_addr(mem) as u64,
        )
        .map_err(Error::SetCoreRegister)?;
    }
    Ok(())
}

/// Specifies whether a particular register is a system register or not.
/// The kernel splits the registers on aarch64 in core registers and system registers.
/// So, below we get the system registers by checking that they are not core registers.
///
/// # Arguments
///
/// * `regid` - The index of the register we are checking.
pub fn is_system_register(regid: u64) -> bool {
    if (regid & KVM_REG_ARM_COPROC_MASK as u64) == KVM_REG_ARM_CORE as u64 {
        return false;
    }

    let size = regid & KVM_REG_SIZE_MASK;
    if size != KVM_REG_SIZE_U32 && size != KVM_REG_SIZE_U64 {
        panic!("Unexpected register size for system register {}", size);
    }
    true
}

/// Read the MPIDR - Multiprocessor Affinity Register.
///
/// # Arguments
///
/// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
pub fn read_mpidr(vcpu: &VcpuFd) -> Result<u64> {
    vcpu.get_one_reg(MPIDR_EL1).map_err(Error::GetSysRegister)
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::aarch64::{arch_memory_regions, layout};
    use kvm_ioctls::Kvm;

    #[test]
    fn test_setup_regs() {
        let kvm = Kvm::new().unwrap();
        let vm = kvm.create_vm().unwrap();
        let vcpu = vm.create_vcpu(0).unwrap();
        let regions = arch_memory_regions(layout::FDT_MAX_SIZE + 0x1000);
        let mem = GuestMemoryMmap::from_ranges(&regions).expect("Cannot initialize memory");

        let res = setup_boot_regs(&vcpu, 0, 0x0, &mem);
        assert!(res.is_err());
        assert_eq!(
            format!("{}", res.unwrap_err()),
            "Failed to set core register: Exec format error (os error 8)"
        );

        let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default();
        vm.get_preferred_target(&mut kvi).unwrap();
        vcpu.vcpu_init(&kvi).unwrap();

        assert!(setup_boot_regs(&vcpu, 0, 0x0, &mem).is_ok());
    }
    #[test]
    fn test_read_mpidr() {
        let kvm = Kvm::new().unwrap();
        let vm = kvm.create_vm().unwrap();
        let vcpu = vm.create_vcpu(0).unwrap();
        let mut kvi: kvm_bindings::kvm_vcpu_init = kvm_bindings::kvm_vcpu_init::default();
        vm.get_preferred_target(&mut kvi).unwrap();

        // Must fail when vcpu is not initialized yet.
        let res = read_mpidr(&vcpu);
        assert!(res.is_err());
        assert_eq!(
            format!("{}", res.unwrap_err()),
            "Failed to get system register: Exec format error (os error 8)"
        );

        vcpu.vcpu_init(&kvi).unwrap();
        assert_eq!(read_mpidr(&vcpu).unwrap(), 0x8000_0000);
    }

    #[test]
    fn test_is_system_register() {
        let offset = offset__of!(user_pt_regs, pc);
        let regid = arm64_core_reg_id!(KVM_REG_SIZE_U64, offset);
        assert!(!is_system_register(regid));
        let regid = KVM_REG_ARM64 as u64
            | KVM_REG_SIZE_U64 as u64
            | kvm_bindings::KVM_REG_ARM64_SYSREG as u64;
        assert!(is_system_register(regid));
    }
}
<|endoftext|>


<commit_before>use git2::Error as Git2Error;

use libimagstore::hook::error::HookError as HE;
use libimagstore::hook::error::HookErrorKind as HEK;
use libimagstore::hook::result::HookResult;

generate_error_module!(
    generate_error_types!(GitHookError, GitHookErrorKind,
        ConfigError => "Configuration Error",
        NoConfigError => "No Configuration",
        ConfigTypeError => "Configuration value type wrong",
        RuntimeInformationSetupError => "Couldn't setup runtime information for git hook",
        RepositoryBackendError            => "Error in the git library",
        RepositoryError                   => "Error while interacting with git repository",
        RepositoryBranchError             => "Error while interacting with git branch(es)",
        RepositoryBranchNameFetchingError => "Error while fetching branch name",
        RepositorySignatureFetchingError  => "Error while fetching Authors/Committers signature",
        RepositoryIndexFetchingError      => "Error while fetching Repository Index",
        RepositoryPathAddingError         => "Error while adding Path to Index",
        RepositoryTreeWritingError        => "Error while writing repository tree",
        RepositoryTreeFindingError        => "Error while finding repository tree",
        RepositoryCommitFindingError      => "Error while finding commit",
        RepositoryCommittingError         => "Error while committing",
        RepositoryHeadFetchingError       => "Error while fetching HEAD",
        RepositoryHeadTargetFetchingError => "Error while fetching target of HEAD",
        HeadFetchError                    => "Error while getting HEAD",
        NotOnBranch                       => "No Branch is checked out",
        MkRepo => "Repository creation error",
        MkSignature => "Error while building Signature object",
        StoreIdStripError => "Couldn't strip prefix from StoreID object"
    );
);

impl GitHookError {

    pub fn inside_of<T>(self, h: HEK) -> HookResult<T> {
        Err(HE::new(h, Some(Box::new(self))))
    }

}

impl From<GitHookError> for HE {

    fn from(he: GitHookError) -> HE {
        HE::new(HEK::HookExecutionError, Some(Box::new(he)))
    }

}

impl From<Git2Error> for GitHookError {

    fn from(ge: Git2Error) -> GitHookError {
        GitHookError::new(GitHookErrorKind::RepositoryBackendError, Some(Box::new(ge)))
    }

}

pub use self::error::GitHookError;
pub use self::error::GitHookErrorKind;
pub use self::error::MapErrInto;

<commit_msg>Add more error kinds<commit_after>use git2::Error as Git2Error;

use libimagstore::hook::error::HookError as HE;
use libimagstore::hook::error::HookErrorKind as HEK;
use libimagstore::hook::result::HookResult;

generate_error_module!(
    generate_error_types!(GitHookError, GitHookErrorKind,
        ConfigError => "Configuration Error",
        NoConfigError => "No Configuration",
        ConfigTypeError => "Configuration value type wrong",
        RuntimeInformationSetupError => "Couldn't setup runtime information for git hook",
        RepositoryBackendError            => "Error in the git library",
        RepositoryError                   => "Error while interacting with git repository",
        RepositoryBranchError             => "Error while interacting with git branch(es)",
        RepositoryBranchNameFetchingError => "Error while fetching branch name",
        RepositorySignatureFetchingError  => "Error while fetching Authors/Committers signature",
        RepositoryIndexFetchingError      => "Error while fetching Repository Index",
        RepositoryPathAddingError         => "Error while adding Path to Index",
        RepositoryTreeWritingError        => "Error while writing repository tree",
        RepositoryTreeFindingError        => "Error while finding repository tree",
        RepositoryCommitFindingError      => "Error while finding commit",
        RepositoryCommittingError         => "Error while committing",
        RepositoryHeadFetchingError       => "Error while fetching HEAD",
        RepositoryHeadTargetFetchingError => "Error while fetching target of HEAD",
        HeadFetchError                    => "Error while getting HEAD",
        NotOnBranch                       => "No Branch is checked out",
        MkRepo => "Repository creation error",
        MkSignature => "Error while building Signature object",
        StoreIdHandlingError => "Error handling the store id object",
        StoreIdStripError => "Couldn't strip prefix from StoreID object",

        RepositoryFileStatusError => "Error while getting file status"
    );
);

impl GitHookError {

    pub fn inside_of<T>(self, h: HEK) -> HookResult<T> {
        Err(HE::new(h, Some(Box::new(self))))
    }

}

impl From<GitHookError> for HE {

    fn from(he: GitHookError) -> HE {
        HE::new(HEK::HookExecutionError, Some(Box::new(he)))
    }

}

impl From<Git2Error> for GitHookError {

    fn from(ge: Git2Error) -> GitHookError {
        GitHookError::new(GitHookErrorKind::RepositoryBackendError, Some(Box::new(ge)))
    }

}

pub use self::error::GitHookError;
pub use self::error::GitHookErrorKind;
pub use self::error::MapErrInto;

<|endoftext|>


<commit_before>use app::App;
use input::Button;
use serde::Serialize;
use serde::Deserialize;
use serde::Serializer;

pub struct Axis {
    pos: Button,
    neg: Button,
}

const KEYBOARD: &'static str = "Keyboard";
const MOUSE: &'static str = "Mouse";
const CONTROLLER: &'static str = "Controller";

impl Axis {
    pub fn new(pos: Button, neg: Button) -> Axis {
        Axis {
            pos: pos,
            neg: neg,
        }
    }

    pub fn get_value(&self, app: &App) -> f64 {
        let pos_bool = app.is_button_down(self.pos);
        if pos_bool == app.is_button_down(self.neg) {
            return 0.0;
        }
        if pos_bool {
            return 1.0;
        }
        -1.0 // They aren't equal and positive is false so negative is true.
    }

    fn serialize_button<S: Serializer>(button: Button, serializer: &mut S, name: &'static str)
        -> Result<(), S::Error>
    {
        let mut state = serializer.serialize_map(Some(3))?;
        serializer.serialize_map_key(&mut state, name)?;
        match button {
            Button::Keyboard(key) => {
                let mut key_state = serializer.serialize_map(Some(2))?;
                serializer.serialize_map_key(&mut key_state, "Type")?;
                serializer.serialize_map_value(&mut key_state, KEYBOARD)?;
                serializer.serialize_map_key(&mut key_state, "Key")?;
                serializer.serialize_map_value(&mut key_state, key as u16)?;
                serializer.serialize_map_end(key_state)?;
            }
            Button::Mouse(button) => {
                let mut mouse_state = serializer.serialize_map(Some(2))?;
                serializer.serialize_map_key(&mut mouse_state, "Type")?;
                serializer.serialize_map_value(&mut mouse_state, MOUSE)?;
                serializer.serialize_map_key(&mut mouse_state, "Button")?;
                serializer.serialize_map_value(&mut mouse_state, button as u8)?;
                serializer.serialize_map_end(mouse_state)?;
            }
            Button::Controller(controller_button) => {
                let mut controller_state = serializer.serialize_map(Some(3))?;
                serializer.serialize_map_key(&mut controller_state, "Type")?;
                serializer.serialize_map_value(&mut controller_state, CONTROLLER)?;
                serializer.serialize_map_key(&mut controller_state, "Id")?;
                serializer.serialize_map_value(&mut controller_state, controller_button.id)?;
                serializer.serialize_map_key(&mut controller_state, "Button")?;
                serializer.serialize_map_value(&mut controller_state, controller_button.button)?;
                serializer.serialize_map_end(controller_state)?;

            }
        }
        serializer.serialize_map_end(state)?;
        Ok(())
    }
}

impl Serialize for Axis {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
        let mut state = serializer.serialize_map(Some(2))?;
        serializer.serialize_map_key(&mut state, "Axis")?;
        Axis::serialize_button(self.pos, serializer, "Pos")?;
        Axis::serialize_button(self.neg, serializer, "Neg")?;
        serializer.serialize_map_end(state)?;
        Ok(())
    }
}
<commit_msg>Add stuff for deserialization<commit_after>use app::App;
use input::Button;
use serde::Serialize;
use serde::Deserialize;
use serde::Serializer;
use serde::Deserializer;
use serde::de::Visitor;

pub struct Axis {
    pos: Button,
    neg: Button,
}

const KEYBOARD: &'static str = "Keyboard";
const MOUSE: &'static str = "Mouse";
const CONTROLLER: &'static str = "Controller";

impl Axis {
    pub fn new(pos: Button, neg: Button) -> Axis {
        Axis {
            pos: pos,
            neg: neg,
        }
    }

    pub fn get_value(&self, app: &App) -> f64 {
        let pos_bool = app.is_button_down(self.pos);
        if pos_bool == app.is_button_down(self.neg) {
            return 0.0;
        }
        if pos_bool {
            return 1.0;
        }
        -1.0 // They aren't equal and positive is false so negative is true.
    }

    fn serialize_button<S: Serializer>(button: Button,
                                       serializer: &mut S,
                                       name: &'static str)
                                       -> Result<(), S::Error> {
        let mut state = serializer.serialize_map(Some(3))?;
        serializer.serialize_map_key(&mut state, name)?;
        match button {
            Button::Keyboard(key) => {
                let mut key_state = serializer.serialize_map(Some(2))?;
                serializer.serialize_map_key(&mut key_state, "Type")?;
                serializer.serialize_map_value(&mut key_state, KEYBOARD)?;
                serializer.serialize_map_key(&mut key_state, "Key")?;
                serializer.serialize_map_value(&mut key_state, key as u16)?;
                serializer.serialize_map_end(key_state)?;
            }
            Button::Mouse(button) => {
                let mut mouse_state = serializer.serialize_map(Some(2))?;
                serializer.serialize_map_key(&mut mouse_state, "Type")?;
                serializer.serialize_map_value(&mut mouse_state, MOUSE)?;
                serializer.serialize_map_key(&mut mouse_state, "Button")?;
                serializer.serialize_map_value(&mut mouse_state, button as u8)?;
                serializer.serialize_map_end(mouse_state)?;
            }
            Button::Controller(controller_button) => {
                let mut controller_state = serializer.serialize_map(Some(3))?;
                serializer.serialize_map_key(&mut controller_state, "Type")?;
                serializer.serialize_map_value(&mut controller_state, CONTROLLER)?;
                serializer.serialize_map_key(&mut controller_state, "Id")?;
                serializer.serialize_map_value(&mut controller_state, controller_button.id)?;
                serializer.serialize_map_key(&mut controller_state, "Button")?;
                serializer.serialize_map_value(&mut controller_state, controller_button.button)?;
                serializer.serialize_map_end(controller_state)?;

            }
        }
        serializer.serialize_map_end(state)?;
        Ok(())
    }

    fn deserialize_button<D: Deserializer>(deserializer: D) -> Result<Button, D::Error> {
        // TODO: Make this deserialize.
    }
}

struct AxisVisitor;

impl Visitor for AxisVisitor {
    type Value = Axis;
}

impl Serialize for Axis {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer
    {
        let mut state = serializer.serialize_map(Some(2))?;
        serializer.serialize_map_key(&mut state, "Axis")?;
        Axis::serialize_button(self.pos, serializer, "Pos")?;
        Axis::serialize_button(self.neg, serializer, "Neg")?;
        serializer.serialize_map_end(state)?;
        Ok(())
    }
}

impl Deserialize for Axis {
    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> where D: Deserializer {}
}
<|endoftext|>


<commit_before>use std::fs::{self, File};
use std::io::{BufRead, BufReader};

use bson::Bson;
use mongodb::{Client, CommandResult, ThreadedClient};
use mongodb::db::ThreadedDatabase;
use rand;

fn timed_query(_client: Client, command_result: &CommandResult) {
    let duration = match command_result {
        &CommandResult::Success { duration, .. } => duration,
        _ => panic!("Command failed!")
    };

    // Sanity check
    assert!(duration >= 1500000000);

    // Technically not guaranteed, but since the query is running locally, it shouldn't even be close
    assert!(duration < 2000000000);
}

#[test]
fn command_duration() {
    let mut client = Client::connect("localhost", 27017).ok().expect("damn it!");
    let db = client.db("test");
    let coll = db.collection("event_hooks");
    coll.drop().unwrap();

    let docs = (1..4).map(|i| doc! { "_id" => i, "x" => (rand::random::<u8>() as u32) }).collect();
    coll.insert_many(docs, false, None).unwrap();
    client.add_completion_hook(timed_query).unwrap();

    let doc = doc! {
        "$where" => (Bson::JavaScriptCode("function() { sleep(500); }".to_owned()))
    };

    coll.find(Some(doc), None).unwrap();
}

#[test]
fn logging() {
    for file in fs::read_dir(".").unwrap() {
        if file.unwrap().file_name().eq("test_log.txt") {
            fs::remove_file("test_log.txt").unwrap();
        }
    }

    let client = Client::connect_with_log_file("localhost", 27017, "test_log.txt").unwrap();
    let db = client.db("test");
    let coll = db.collection("logging");
    coll.drop().unwrap();

    let doc1 = doc! { "_id" => 1 };
    let doc2 = doc! { "_id" => 2 };
    let doc3 = doc! { "_id" => 3 };

    coll.insert_one(doc1, None).unwrap();
    coll.insert_one(doc2, None).unwrap();
    coll.insert_one(doc3, None).unwrap();

    let filter = doc! {
        "_id" => { "$gt" => 1 }
    };

    coll.find(Some(filter), None).unwrap();

    let f = File::open("test_log.txt").unwrap();
    let mut file = BufReader::new(&f);
    let mut line = String::new();

    // Drop collection started
    file.read_line(&mut line).unwrap();
    assert_eq!("COMMAND.drop_collection 127.0.0.1:27017 STARTED: { drop: \"logging\" }\n", &line);

    // Drop collection completed
    line.clear();
    file.read_line(&mut line).unwrap();
    assert!(line.starts_with("COMMAND.drop_collection 127.0.0.1:27017 COMPLETED: { ns: \"test.logging\", nIndexesWas: 1, ok: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // First insert started
    line.clear();
    file.read_line(&mut line).unwrap();
    assert_eq!("COMMAND.insert_one 127.0.0.1:27017 STARTED: { insert: \"logging\", documents: [{ _id: 1 }], ordered: true, writeConcern: { w: 1, wtimeout: 0, j: false } }\n", &line);

    // First insert completed
    line.clear();
    file.read_line(&mut line).unwrap();
    assert!(line.starts_with("COMMAND.insert_one 127.0.0.1:27017 COMPLETED: { ok: 1, n: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // Second insert started
    line.clear();
    file.read_line(&mut line).unwrap();
    assert_eq!("COMMAND.insert_one 127.0.0.1:27017 STARTED: { insert: \"logging\", documents: [{ _id: 2 }], ordered: true, writeConcern: { w: 1, wtimeout: 0, j: false } }\n", &line);

    // Second insert completed
    line.clear();
    file.read_line(&mut line).unwrap();
    assert!(line.starts_with("COMMAND.insert_one 127.0.0.1:27017 COMPLETED: { ok: 1, n: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // Third insert started
    line.clear();
    file.read_line(&mut line).unwrap();
    assert_eq!("COMMAND.insert_one 127.0.0.1:27017 STARTED: { insert: \"logging\", documents: [{ _id: 3 }], ordered: true, writeConcern: { w: 1, wtimeout: 0, j: false } }\n", &line);

    // Third insert completed
    line.clear();
    file.read_line(&mut line).unwrap();
    assert!(line.starts_with("COMMAND.insert_one 127.0.0.1:27017 COMPLETED: { ok: 1, n: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // Find command started
    line.clear();
    file.read_line(&mut line).unwrap();
    assert_eq!("COMMAND.find 127.0.0.1:27017 STARTED: { find: \"logging\", filter: {  }, projection: {  }, skip: 0, limit: 0, batchSize: 20, sort: {  } }\n", &line);

    // Find command completed
    line.clear();
    file.read_line(&mut line).unwrap();
    assert!(line.starts_with("COMMAND.find 127.0.0.1:27017 COMPLETED: { cursor: { id: 0, ns: \"test.logging\", firstBatch: [{ _id: 2 }, { _id: 3 }] }, ok: 1 } ("));
    assert!(line.ends_with(" ns)\n"));
}
<commit_msg>fixed issue with collection not existing before being dropped<commit_after>use std::fs::{self, File};
use std::io::{BufRead, BufReader};

use bson::Bson;
use mongodb::{Client, CommandResult, ThreadedClient};
use mongodb::db::ThreadedDatabase;
use rand;

fn timed_query(_client: Client, command_result: &CommandResult) {
    let duration = match command_result {
        &CommandResult::Success { duration, .. } => duration,
        _ => panic!("Command failed!")
    };

    // Sanity check
    assert!(duration >= 1500000000);

    // Technically not guaranteed, but since the query is running locally, it shouldn't even be close
    assert!(duration < 2000000000);
}

#[test]
fn command_duration() {
    let mut client = Client::connect("localhost", 27017).ok().expect("damn it!");
    let db = client.db("test");
    let coll = db.collection("event_hooks");
    coll.drop().unwrap();

    let docs = (1..4).map(|i| doc! { "_id" => i, "x" => (rand::random::<u8>() as u32) }).collect();
    coll.insert_many(docs, false, None).unwrap();
    client.add_completion_hook(timed_query).unwrap();

    let doc = doc! {
        "$where" => (Bson::JavaScriptCode("function() { sleep(500); }".to_owned()))
    };

    coll.find(Some(doc), None).unwrap();
}

#[test]
fn logging() {
    for file in fs::read_dir(".").unwrap() {
        if file.unwrap().file_name().eq("test_log.txt") {
            fs::remove_file("test_log.txt").unwrap();
        }
    }

    let client = Client::connect_with_log_file("localhost", 27017, "test_log.txt").unwrap();
    let db = client.db("test");
    let coll = db.collection("logging");
    coll.drop().unwrap();

    let doc1 = doc! { "_id" => 1 };
    let doc2 = doc! { "_id" => 2 };
    let doc3 = doc! { "_id" => 3 };

    coll.insert_one(doc1, None).unwrap();
    coll.insert_one(doc2, None).unwrap();
    coll.insert_one(doc3, None).unwrap();

    let filter = doc! {
        "_id" => { "$gt" => 1 }
    };

    coll.find(Some(filter), None).unwrap();

    let f = File::open("test_log.txt").unwrap();
    let mut file = BufReader::new(&f);
    let mut line = String::new();

    // Drop collection started
    file.read_line(&mut line).unwrap();
    assert_eq!("COMMAND.drop_collection 127.0.0.1:27017 STARTED: { drop: \"logging\" }\n", &line);

    // Drop collection completed
    line.clear();
    file.read_line(&mut line).unwrap();
    // Can't assert the contents of the response until `create_collection` is implemented, otherwise
    // the collection might not exist, so there might be an error message.
    assert!(line.starts_with("COMMAND.drop_collection 127.0.0.1:27017 COMPLETED: {"));

    // First insert started
    line.clear();
    file.read_line(&mut line).unwrap();
    assert_eq!("COMMAND.insert_one 127.0.0.1:27017 STARTED: { insert: \"logging\", documents: [{ _id: 1 }], ordered: true, writeConcern: { w: 1, wtimeout: 0, j: false } }\n", &line);

    // First insert completed
    line.clear();
    file.read_line(&mut line).unwrap();
    assert!(line.starts_with("COMMAND.insert_one 127.0.0.1:27017 COMPLETED: { ok: 1, n: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // Second insert started
    line.clear();
    file.read_line(&mut line).unwrap();
    assert_eq!("COMMAND.insert_one 127.0.0.1:27017 STARTED: { insert: \"logging\", documents: [{ _id: 2 }], ordered: true, writeConcern: { w: 1, wtimeout: 0, j: false } }\n", &line);

    // Second insert completed
    line.clear();
    file.read_line(&mut line).unwrap();
    assert!(line.starts_with("COMMAND.insert_one 127.0.0.1:27017 COMPLETED: { ok: 1, n: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // Third insert started
    line.clear();
    file.read_line(&mut line).unwrap();
    assert_eq!("COMMAND.insert_one 127.0.0.1:27017 STARTED: { insert: \"logging\", documents: [{ _id: 3 }], ordered: true, writeConcern: { w: 1, wtimeout: 0, j: false } }\n", &line);

    // Third insert completed
    line.clear();
    file.read_line(&mut line).unwrap();
    assert!(line.starts_with("COMMAND.insert_one 127.0.0.1:27017 COMPLETED: { ok: 1, n: 1 } ("));
    assert!(line.ends_with(" ns)\n"));

    // Find command started
    line.clear();
    file.read_line(&mut line).unwrap();
    assert_eq!("COMMAND.find 127.0.0.1:27017 STARTED: { find: \"logging\", filter: {  }, projection: {  }, skip: 0, limit: 0, batchSize: 20, sort: {  } }\n", &line);

    // Find command completed
    line.clear();
    file.read_line(&mut line).unwrap();
    assert!(line.starts_with("COMMAND.find 127.0.0.1:27017 COMPLETED: { cursor: { id: 0, ns: \"test.logging\", firstBatch: [{ _id: 2 }, { _id: 3 }] }, ok: 1 } ("));
    assert!(line.ends_with(" ns)\n"));
}
<|endoftext|>