<commit_before>//! This module implements several error types and traits.  The suggested usage in returned results
//! is as follows:
//!
//! * The concrete `util::concrete::Error` type (re-exported as `util::Error`) is great for code
//!   that is not part of the request/response lifecycle.  It avoids pulling in the unnecessary
//!   infrastructure to convert errors into a user facing JSON responses (relative to `AppError`).
//! * `diesel::QueryResult` - There is a lot of code that only deals with query errors.  If only
//!   one type of error is possible in a function, using that specific error is preferable to the
//!   more general `util::Error`.  This is especially common in model code.
//! * `util::errors::AppResult` - Some failures should be converted into user facing JSON
//!   responses.  This error type is more dynamic and is box allocated.  Low-level errors are
//!   typically not converted to user facing errors and most usage is within the models,
//!   controllers, and middleware layers.

use std::any::{Any, TypeId};
use std::error::Error;
use std::fmt;

use chrono::NaiveDateTime;
use diesel::result::Error as DieselError;

use crate::util::AppResponse;

mod json;

pub(crate) use json::{InsecurelyGeneratedTokenRevoked, NotFound, ReadOnlyMode, TooManyRequests};

/// Returns an error with status 200 and the provided description as JSON
///
/// This is for backwards compatibility with cargo endpoints.  For all other
/// endpoints, use helpers like `bad_request` or `server_error` which set a
/// correct status code.
pub fn cargo_err<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(json::Ok(error.to_string()))
}

// The following are intended to be used for errors being sent back to the Ember
// frontend, not to cargo as cargo does not handle non-200 response codes well
// (see <https://github.com/rust-lang/cargo/issues/3995>), but Ember requires
// non-200 response codes for its stores to work properly.

/// Return an error with status 400 and the provided description as JSON
pub fn bad_request<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(json::BadRequest(error.to_string()))
}

pub fn account_locked(reason: &str, until: Option<NaiveDateTime>) -> Box<dyn AppError> {
    Box::new(json::AccountLocked {
        reason: reason.to_string(),
        until,
    })
}

pub fn forbidden() -> Box<dyn AppError> {
    Box::new(json::Forbidden)
}

pub fn not_found() -> Box<dyn AppError> {
    Box::new(json::NotFound)
}

/// Returns an error with status 500 and the provided description as JSON
pub fn server_error<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(json::ServerError(error.to_string()))
}

// =============================================================================
// AppError trait

pub trait AppError: Send + fmt::Display + fmt::Debug + 'static {
    /// Generate an HTTP response for the error
    ///
    /// If none is returned, the error will bubble up the middleware stack
    /// where it is eventually logged and turned into a status 500 response.
    fn response(&self) -> Option<AppResponse>;

    /// The cause of an error response
    ///
    /// If present, an error provided to the `LogRequests` middleware.
    ///
    /// This is intended for use with the `ChainError` trait, where a user facing
    /// error may wrap an internal error we still want to log.
    fn cause(&self) -> Option<&dyn AppError> {
        None
    }

    fn get_type_id(&self) -> TypeId {
        TypeId::of::<Self>()
    }

    fn chain<E>(self, error: E) -> Box<dyn AppError>
    where
        Self: Sized,
        E: AppError,
    {
        Box::new(ChainedError {
            error,
            cause: Box::new(self),
        })
    }
}

impl dyn AppError {
    pub fn is<T: Any>(&self) -> bool {
        self.get_type_id() == TypeId::of::<T>()
    }

    fn try_convert(err: &(dyn Error + Send + 'static)) -> Option<Box<Self>> {
        match err.downcast_ref() {
            Some(DieselError::NotFound) => Some(not_found()),
            Some(DieselError::DatabaseError(_, info))
                if info.message().ends_with("read-only transaction") =>
            {
                Some(Box::new(ReadOnlyMode))
            }
            _ => None,
        }
    }
}

impl AppError for Box<dyn AppError> {
    fn response(&self) -> Option<AppResponse> {
        (**self).response()
    }

    fn cause(&self) -> Option<&dyn AppError> {
        (**self).cause()
    }

    fn get_type_id(&self) -> TypeId {
        (**self).get_type_id()
    }
}

pub type AppResult<T> = Result<T, Box<dyn AppError>>;

// =============================================================================
// Chaining errors

pub trait ChainError<T> {
    fn chain_error<E, F>(self, callback: F) -> AppResult<T>
    where
        E: AppError,
        F: FnOnce() -> E;
}

#[derive(Debug)]
struct ChainedError<E> {
    error: E,
    cause: Box<dyn AppError>,
}

impl<T, E: AppError> ChainError<T> for Result<T, E> {
    fn chain_error<E2, C>(self, callback: C) -> AppResult<T>
    where
        E2: AppError,
        C: FnOnce() -> E2,
    {
        self.map_err(move |err| err.chain(callback()))
    }
}

impl<T> ChainError<T> for Option<T> {
    fn chain_error<E, C>(self, callback: C) -> AppResult<T>
    where
        E: AppError,
        C: FnOnce() -> E,
    {
        match self {
            Some(t) => Ok(t),
            None => Err(Box::new(callback())),
        }
    }
}

impl<E: AppError> AppError for ChainedError<E> {
    fn response(&self) -> Option<AppResponse> {
        self.error.response()
    }

    fn cause(&self) -> Option<&dyn AppError> {
        Some(&*self.cause)
    }
}

impl<E: AppError> fmt::Display for ChainedError<E> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} caused by {}", self.error, self.cause)
    }
}

// =============================================================================
// Error impls

impl<E: Error + Send + 'static> AppError for E {
    fn response(&self) -> Option<AppResponse> {
        None
    }
}

impl<E: Error + Send + 'static> From<E> for Box<dyn AppError> {
    fn from(err: E) -> Box<dyn AppError> {
        AppError::try_convert(&err).unwrap_or_else(|| Box::new(err))
    }
}
// =============================================================================
// Internal error for use with `chain_error`

#[derive(Debug)]
struct InternalAppError {
    description: String,
}

impl fmt::Display for InternalAppError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.description)?;
        Ok(())
    }
}

impl AppError for InternalAppError {
    fn response(&self) -> Option<AppResponse> {
        None
    }
}

#[derive(Debug)]
struct InternalAppErrorStatic {
    description: &'static str,
}

impl fmt::Display for InternalAppErrorStatic {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.description)?;
        Ok(())
    }
}

impl AppError for InternalAppErrorStatic {
    fn response(&self) -> Option<AppResponse> {
        None
    }
}

pub fn internal<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(InternalAppError {
        description: error.to_string(),
    })
}

#[derive(Debug)]
struct AppErrToStdErr(pub Box<dyn AppError>);

impl Error for AppErrToStdErr {}

impl fmt::Display for AppErrToStdErr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

pub(crate) fn std_error(e: Box<dyn AppError>) -> Box<dyn Error + Send> {
    Box::new(AppErrToStdErr(e))
}

#[test]
fn chain_error_internal() {
    assert_eq!(
        None::<()>
            .chain_error(|| internal("inner"))
            .chain_error(|| internal("middle"))
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by middle caused by inner"
    );
    assert_eq!(
        Err::<(), _>(internal("inner"))
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by inner"
    );

    // Don't do this, the user will see a generic 500 error instead of the intended message
    assert_eq!(
        Err::<(), _>(cargo_err("inner"))
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by inner"
    );
    assert_eq!(
        Err::<(), _>(forbidden())
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by must be logged in to perform that action"
    );
}

#[test]
fn chain_error_user_facing() {
    // Do this rarely, the user will only see the outer error
    assert_eq!(
        Err::<(), _>(cargo_err("inner"))
            .chain_error(|| cargo_err("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by inner" // never logged
    );

    // The outer error is sent as a response to the client.
    // The inner error never bubbles up to the logging middleware
    assert_eq!(
        Err::<(), _>(std::io::Error::from(std::io::ErrorKind::PermissionDenied))
            .chain_error(|| cargo_err("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by permission denied" // never logged
    );
}
<commit_msg>Auto merge of #3083 - tshepang:patch-2, r=Turbo87<commit_after>//! This module implements several error types and traits.
//!
//! The suggested usage in returned results is as follows:
//!
//! * The concrete `util::concrete::Error` type (re-exported as `util::Error`) is great for code
//!   that is not part of the request/response lifecycle.  It avoids pulling in the unnecessary
//!   infrastructure to convert errors into a user facing JSON responses (relative to `AppError`).
//! * `diesel::QueryResult` - There is a lot of code that only deals with query errors.  If only
//!   one type of error is possible in a function, using that specific error is preferable to the
//!   more general `util::Error`.  This is especially common in model code.
//! * `util::errors::AppResult` - Some failures should be converted into user facing JSON
//!   responses.  This error type is more dynamic and is box allocated.  Low-level errors are
//!   typically not converted to user facing errors and most usage is within the models,
//!   controllers, and middleware layers.

use std::any::{Any, TypeId};
use std::error::Error;
use std::fmt;

use chrono::NaiveDateTime;
use diesel::result::Error as DieselError;

use crate::util::AppResponse;

mod json;

pub(crate) use json::{InsecurelyGeneratedTokenRevoked, NotFound, ReadOnlyMode, TooManyRequests};

/// Returns an error with status 200 and the provided description as JSON
///
/// This is for backwards compatibility with cargo endpoints.  For all other
/// endpoints, use helpers like `bad_request` or `server_error` which set a
/// correct status code.
pub fn cargo_err<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(json::Ok(error.to_string()))
}

// The following are intended to be used for errors being sent back to the Ember
// frontend, not to cargo as cargo does not handle non-200 response codes well
// (see <https://github.com/rust-lang/cargo/issues/3995>), but Ember requires
// non-200 response codes for its stores to work properly.

/// Return an error with status 400 and the provided description as JSON
pub fn bad_request<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(json::BadRequest(error.to_string()))
}

pub fn account_locked(reason: &str, until: Option<NaiveDateTime>) -> Box<dyn AppError> {
    Box::new(json::AccountLocked {
        reason: reason.to_string(),
        until,
    })
}

pub fn forbidden() -> Box<dyn AppError> {
    Box::new(json::Forbidden)
}

pub fn not_found() -> Box<dyn AppError> {
    Box::new(json::NotFound)
}

/// Returns an error with status 500 and the provided description as JSON
pub fn server_error<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(json::ServerError(error.to_string()))
}

// =============================================================================
// AppError trait

pub trait AppError: Send + fmt::Display + fmt::Debug + 'static {
    /// Generate an HTTP response for the error
    ///
    /// If none is returned, the error will bubble up the middleware stack
    /// where it is eventually logged and turned into a status 500 response.
    fn response(&self) -> Option<AppResponse>;

    /// The cause of an error response
    ///
    /// If present, an error provided to the `LogRequests` middleware.
    ///
    /// This is intended for use with the `ChainError` trait, where a user facing
    /// error may wrap an internal error we still want to log.
    fn cause(&self) -> Option<&dyn AppError> {
        None
    }

    fn get_type_id(&self) -> TypeId {
        TypeId::of::<Self>()
    }

    fn chain<E>(self, error: E) -> Box<dyn AppError>
    where
        Self: Sized,
        E: AppError,
    {
        Box::new(ChainedError {
            error,
            cause: Box::new(self),
        })
    }
}

impl dyn AppError {
    pub fn is<T: Any>(&self) -> bool {
        self.get_type_id() == TypeId::of::<T>()
    }

    fn try_convert(err: &(dyn Error + Send + 'static)) -> Option<Box<Self>> {
        match err.downcast_ref() {
            Some(DieselError::NotFound) => Some(not_found()),
            Some(DieselError::DatabaseError(_, info))
                if info.message().ends_with("read-only transaction") =>
            {
                Some(Box::new(ReadOnlyMode))
            }
            _ => None,
        }
    }
}

impl AppError for Box<dyn AppError> {
    fn response(&self) -> Option<AppResponse> {
        (**self).response()
    }

    fn cause(&self) -> Option<&dyn AppError> {
        (**self).cause()
    }

    fn get_type_id(&self) -> TypeId {
        (**self).get_type_id()
    }
}

pub type AppResult<T> = Result<T, Box<dyn AppError>>;

// =============================================================================
// Chaining errors

pub trait ChainError<T> {
    fn chain_error<E, F>(self, callback: F) -> AppResult<T>
    where
        E: AppError,
        F: FnOnce() -> E;
}

#[derive(Debug)]
struct ChainedError<E> {
    error: E,
    cause: Box<dyn AppError>,
}

impl<T, E: AppError> ChainError<T> for Result<T, E> {
    fn chain_error<E2, C>(self, callback: C) -> AppResult<T>
    where
        E2: AppError,
        C: FnOnce() -> E2,
    {
        self.map_err(move |err| err.chain(callback()))
    }
}

impl<T> ChainError<T> for Option<T> {
    fn chain_error<E, C>(self, callback: C) -> AppResult<T>
    where
        E: AppError,
        C: FnOnce() -> E,
    {
        match self {
            Some(t) => Ok(t),
            None => Err(Box::new(callback())),
        }
    }
}

impl<E: AppError> AppError for ChainedError<E> {
    fn response(&self) -> Option<AppResponse> {
        self.error.response()
    }

    fn cause(&self) -> Option<&dyn AppError> {
        Some(&*self.cause)
    }
}

impl<E: AppError> fmt::Display for ChainedError<E> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} caused by {}", self.error, self.cause)
    }
}

// =============================================================================
// Error impls

impl<E: Error + Send + 'static> AppError for E {
    fn response(&self) -> Option<AppResponse> {
        None
    }
}

impl<E: Error + Send + 'static> From<E> for Box<dyn AppError> {
    fn from(err: E) -> Box<dyn AppError> {
        AppError::try_convert(&err).unwrap_or_else(|| Box::new(err))
    }
}
// =============================================================================
// Internal error for use with `chain_error`

#[derive(Debug)]
struct InternalAppError {
    description: String,
}

impl fmt::Display for InternalAppError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.description)?;
        Ok(())
    }
}

impl AppError for InternalAppError {
    fn response(&self) -> Option<AppResponse> {
        None
    }
}

#[derive(Debug)]
struct InternalAppErrorStatic {
    description: &'static str,
}

impl fmt::Display for InternalAppErrorStatic {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.description)?;
        Ok(())
    }
}

impl AppError for InternalAppErrorStatic {
    fn response(&self) -> Option<AppResponse> {
        None
    }
}

pub fn internal<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(InternalAppError {
        description: error.to_string(),
    })
}

#[derive(Debug)]
struct AppErrToStdErr(pub Box<dyn AppError>);

impl Error for AppErrToStdErr {}

impl fmt::Display for AppErrToStdErr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

pub(crate) fn std_error(e: Box<dyn AppError>) -> Box<dyn Error + Send> {
    Box::new(AppErrToStdErr(e))
}

#[test]
fn chain_error_internal() {
    assert_eq!(
        None::<()>
            .chain_error(|| internal("inner"))
            .chain_error(|| internal("middle"))
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by middle caused by inner"
    );
    assert_eq!(
        Err::<(), _>(internal("inner"))
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by inner"
    );

    // Don't do this, the user will see a generic 500 error instead of the intended message
    assert_eq!(
        Err::<(), _>(cargo_err("inner"))
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by inner"
    );
    assert_eq!(
        Err::<(), _>(forbidden())
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by must be logged in to perform that action"
    );
}

#[test]
fn chain_error_user_facing() {
    // Do this rarely, the user will only see the outer error
    assert_eq!(
        Err::<(), _>(cargo_err("inner"))
            .chain_error(|| cargo_err("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by inner" // never logged
    );

    // The outer error is sent as a response to the client.
    // The inner error never bubbles up to the logging middleware
    assert_eq!(
        Err::<(), _>(std::io::Error::from(std::io::ErrorKind::PermissionDenied))
            .chain_error(|| cargo_err("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by permission denied" // never logged
    );
}
<|endoftext|>


<commit_before>//! rustdoc handler

use super::pool::Pool;
use super::file::File;
use super::{latest_version, redirect_base};
use super::crate_details::CrateDetails;
use iron::prelude::*;
use iron::{status, Url};
use iron::modifiers::Redirect;
use router::Router;
use super::{match_version, MatchVersion};
use super::error::Nope;
use super::page::Page;
use rustc_serialize::json::{Json, ToJson};
use std::collections::BTreeMap;
use iron::headers::{Expires, HttpDate, CacheControl, CacheDirective};
use postgres::Connection;
use time;
use iron::Handler;
use utils;

#[derive(Debug)]
struct RustdocPage {
    pub head: String,
    pub body: String,
    pub body_class: String,
    pub name: String,
    pub full: String,
    pub version: String,
    pub description: Option<String>,
    pub crate_details: Option<CrateDetails>,
}

impl Default for RustdocPage {
    fn default() -> RustdocPage {
        RustdocPage {
            head: String::new(),
            body: String::new(),
            body_class: String::new(),
            name: String::new(),
            full: String::new(),
            version: String::new(),
            description: None,
            crate_details: None,
        }
    }
}

impl ToJson for RustdocPage {
    fn to_json(&self) -> Json {
        let mut m: BTreeMap<String, Json> = BTreeMap::new();
        m.insert("rustdoc_head".to_string(), self.head.to_json());
        m.insert("rustdoc_body".to_string(), self.body.to_json());
        m.insert("rustdoc_body_class".to_string(), self.body_class.to_json());
        m.insert("rustdoc_full".to_string(), self.full.to_json());
        m.insert("rustdoc_status".to_string(), true.to_json());
        m.insert("name".to_string(), self.name.to_json());
        m.insert("version".to_string(), self.version.to_json());
        m.insert("description".to_string(), self.description.to_json());
        m.insert("crate_details".to_string(), self.crate_details.to_json());
        m.to_json()
    }
}

pub struct RustLangRedirector {
    url: Url,
}

impl RustLangRedirector {
    pub fn new(target: &'static str) -> Self {
        let url = url::Url::parse("https://doc.rust-lang.org/stable/")
            .expect("failed to parse rust-lang.org base URL")
            .join(target)
            .expect("failed to append crate name to rust-lang.org base URL");
        let url = Url::from_generic_url(url)
            .expect("failed to convert url::Url to iron::Url");
        Self { url }
    }
}

impl iron::Handler for RustLangRedirector {
    fn handle(&self, _req: &mut Request) -> IronResult<Response> {
        Ok(Response::with((status::Found, Redirect(self.url.clone()))))
    }
}

/// Handler called for `/:crate` and `/:crate/:version` URLs. Automatically redirects to the docs
/// or crate details page based on whether the given crate version was successfully built.
pub fn rustdoc_redirector_handler(req: &mut Request) -> IronResult<Response> {

    fn redirect_to_doc(req: &Request,
                       name: &str,
                       vers: &str,
                       target_name: &str)
                       -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}/{}/{}/{}/",
                                            redirect_base(req),
                                            name,
                                            vers,
                                            target_name)[..]));
        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    fn redirect_to_crate(req: &Request,
                         name: &str,
                         vers: &str)
                         -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}/crate/{}/{}",
                                            redirect_base(req),
                                            name,
                                            vers)[..]));

        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    // this unwrap is safe because iron urls are always able to use `path_segments`
    // i'm using this instead of `req.url.path()` to avoid allocating the Vec, and also to avoid
    // keeping the borrow alive into the return statement
    if req.url.as_ref().path_segments().unwrap().last().map_or(false, |s| s.ends_with(".js")) {
        // javascript files should be handled by the file server instead of erroneously
        // redirecting to the crate root page
        if req.url.as_ref().path_segments().unwrap().count() > 2 {
            // this URL is actually from a crate-internal path, serve it there instead
            return rustdoc_html_server_handler(req);
        } else {
            let path = req.url.path();
            let path = path.join("/");
            let conn = extension!(req, Pool);
            match File::from_path(&conn, &path) {
                Some(f) => return Ok(f.serve()),
                None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
            }
        }
    } else if req.url.as_ref().path_segments().unwrap().last().map_or(false, |s| s.ends_with(".ico")) {
        // route .ico files into their dedicated handler so that docs.rs's favicon is always
        // displayed
        return super::ico_handler(req);
    }

    let router = extension!(req, Router);
    // this handler should never called without crate pattern
    let crate_name = cexpect!(router.find("crate"));
    let req_version = router.find("version");

    let conn = extension!(req, Pool);

    // it doesn't matter if the version that was given was exact or not, since we're redirecting
    // anyway
    let version = match match_version(&conn, &crate_name, req_version).into_option() {
        Some(v) => v,
        None => return Err(IronError::new(Nope::CrateNotFound, status::NotFound)),
    };

    // get target name and whether it has docs
    // FIXME: This is a bit inefficient but allowing us to use less code in general
    let (target_name, has_docs): (String, bool) = {
        let rows = ctry!(conn.query("SELECT target_name, rustdoc_status
                                     FROM releases
                                     INNER JOIN crates ON crates.id = releases.crate_id
                                     WHERE crates.name = $1 AND releases.version = $2",
                                    &[&crate_name, &version]));

        (rows.get(0).get(0), rows.get(0).get(1))
    };

    if has_docs {
        redirect_to_doc(req, &crate_name, &version, &target_name)
    } else {
        redirect_to_crate(req, &crate_name, &version)
    }
}

/// Serves documentation generated by rustdoc.
///
/// This includes all HTML files for an individual crate, as well as the `search-index.js`, which is
/// also crate-specific.
pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {

    let router = extension!(req, Router);
    let name = router.find("crate").unwrap_or("").to_string();
    let url_version = router.find("version");
    let version; // pre-declaring it to enforce drop order relative to `req_path`
    let conn = extension!(req, Pool);

    let mut req_path = req.url.path();

    // remove name and version from path
    for _ in 0..2 {
        req_path.remove(0);
    }

    version = match match_version(&conn, &name, url_version) {
        MatchVersion::Exact(v) => v,
        MatchVersion::Semver(v) => {
            // to prevent cloudfront caching the wrong artifacts on URLs with loose semver
            // versions, redirect the browser to the returned version instead of loading it
            // immediately
            let url = ctry!(Url::parse(&format!("{}/{}/{}/{}",
                                                redirect_base(req),
                                                name,
                                                v,
                                                req_path.join("/"))[..]));
            return Ok(super::redirect(url));
        }
        MatchVersion::None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
    };

    // docs have "rustdoc" prefix in database
    req_path.insert(0, "rustdoc");

    // add crate name and version
    req_path.insert(1, &name);
    req_path.insert(2, &version);

    let path = {
        let mut path = req_path.join("/");
        if path.ends_with('/') {
            req_path.pop(); // get rid of empty string
            path.push_str("index.html");
            req_path.push("index.html");
        }
        path
    };

    let file = match File::from_path(&conn, &path) {
        Some(f) => f,
        None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
    };

    // serve file directly if it's not html
    if !path.ends_with(".html") {
        return Ok(file.serve());
    }

    let mut content = RustdocPage::default();

    let file_content = ctry!(String::from_utf8(file.0.content));

    let (head, body, mut body_class) = ctry!(utils::extract_head_and_body(&file_content));
    content.head = head;
    content.body = body;

    if body_class.is_empty() {
        body_class = "rustdoc container-rustdoc".to_string();
    } else {
        // rustdoc adds its own "rustdoc" class to the body
        body_class.push_str(" container-rustdoc");
    }
    content.body_class = body_class;

    content.full = file_content;
    let crate_details = cexpect!(CrateDetails::new(&conn, &name, &version));
    let (path, version) = if let Some(version) = latest_version(&crate_details.versions, &version) {
        req_path[2] = &version;
        (path_for_version(&req_path, &crate_details.target_name, &conn), version)
    } else {
        Default::default()
    };

    content.crate_details = Some(crate_details);

    Page::new(content)
        .set_true("show_package_navigation")
        .set_true("package_navigation_documentation_tab")
        .set_true("package_navigation_show_platforms_tab")
        .set_bool("is_latest_version", path.is_empty())
        .set("path_in_latest", &path)
        .set("latest_version", &version)
        .to_resp("rustdoc")
}

fn path_for_version(req_path: &[&str], target_name: &str, conn: &Connection) -> String {
    if File::from_path(&conn, &req_path.join("/")).is_some() {
        req_path[3..].join("/") // NOTE: this adds 'index.html' if it wasn't there before
    } else { // this page doesn't exist in the latest version
        let search_item = if *req_path.last().unwrap() == "index.html" { // this is a module
            req_path[req_path.len() - 2]
        } else { // this is an item
            req_path.last().unwrap().split('.').nth(1)
                .expect("paths should be of the form <class>.<name>.html")
        };
        // check if req_path[3] is the platform choice or the name of the crate
        let concat_path;
        let crate_root = if req_path[3] != target_name {
            concat_path = format!("{}/{}", req_path[3], req_path[4]);
            &concat_path
        } else {
            req_path[3]
        };
        format!("{}/?search={}", crate_root, search_item)
    }
}

pub fn badge_handler(req: &mut Request) -> IronResult<Response> {
    use iron::headers::ContentType;
    use params::{Params, Value};
    use badge::{Badge, BadgeOptions};

    let version = {
        let params = ctry!(req.get_ref::<Params>());
        match params.find(&["version"]) {
            Some(&Value::String(ref version)) => version.clone(),
            _ => "*".to_owned(),
        }
    };

    let name = cexpect!(extension!(req, Router).find("crate"));
    let conn = extension!(req, Pool);

    let options = match match_version(&conn, &name, Some(&version)) {
        MatchVersion::Exact(version) => {
            let rows = ctry!(conn.query("SELECT rustdoc_status
                                         FROM releases
                                         INNER JOIN crates ON crates.id = releases.crate_id
                                         WHERE crates.name = $1 AND releases.version = $2",
                                        &[&name, &version]));
            if rows.len() > 0 && rows.get(0).get(0) {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#4d76ae".to_owned(),
                }
            } else {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#e05d44".to_owned(),
                }
            }
        }
        MatchVersion::Semver(version) => {
            let url = ctry!(Url::parse(&format!("{}/{}/badge.svg?version={}",
                                                redirect_base(req),
                                                name,
                                                version)[..]));

            return Ok(super::redirect(url));
        }
        MatchVersion::None => {
            BadgeOptions {
                subject: "docs".to_owned(),
                status: "no builds".to_owned(),
                color: "#e05d44".to_owned(),
            }
        }
    };

    let mut resp = Response::with((status::Ok, ctry!(Badge::new(options)).to_svg()));
    resp.headers.set(ContentType("image/svg+xml".parse().unwrap()));
    resp.headers.set(Expires(HttpDate(time::now())));
    resp.headers.set(CacheControl(vec![CacheDirective::NoCache,
                                       CacheDirective::NoStore,
                                       CacheDirective::MustRevalidate]));
    Ok(resp)
}

/// Serves shared web resources used by rustdoc-generated documentation.
///
/// This includes common `css` and `js` files that only change when the compiler is updated, but are
/// otherwise the same for all crates documented with that compiler. Those have a custom handler to
/// deduplicate them and save space.
pub struct SharedResourceHandler;

impl Handler for SharedResourceHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        let path = req.url.path();
        let filename = path.last().unwrap();  // unwrap is fine: vector is non-empty
        let suffix = filename.split('.').last().unwrap();  // unwrap is fine: split always works
        if ["js", "css", "woff", "svg"].contains(&suffix) {
            let conn = extension!(req, Pool);

            if let Some(file) = File::from_path(conn, filename) {
                return Ok(file.serve());
            }
        }

        // Just always return a 404 here - the main handler will then try the other handlers
        Err(IronError::new(Nope::ResourceNotFound, status::NotFound))
    }
}
<commit_msg>fix comments and doc comments<commit_after>//! rustdoc handler

use super::pool::Pool;
use super::file::File;
use super::{latest_version, redirect_base};
use super::crate_details::CrateDetails;
use iron::prelude::*;
use iron::{status, Url};
use iron::modifiers::Redirect;
use router::Router;
use super::{match_version, MatchVersion};
use super::error::Nope;
use super::page::Page;
use rustc_serialize::json::{Json, ToJson};
use std::collections::BTreeMap;
use iron::headers::{Expires, HttpDate, CacheControl, CacheDirective};
use postgres::Connection;
use time;
use iron::Handler;
use utils;

#[derive(Debug)]
struct RustdocPage {
    pub head: String,
    pub body: String,
    pub body_class: String,
    pub name: String,
    pub full: String,
    pub version: String,
    pub description: Option<String>,
    pub crate_details: Option<CrateDetails>,
}

impl Default for RustdocPage {
    fn default() -> RustdocPage {
        RustdocPage {
            head: String::new(),
            body: String::new(),
            body_class: String::new(),
            name: String::new(),
            full: String::new(),
            version: String::new(),
            description: None,
            crate_details: None,
        }
    }
}

impl ToJson for RustdocPage {
    fn to_json(&self) -> Json {
        let mut m: BTreeMap<String, Json> = BTreeMap::new();
        m.insert("rustdoc_head".to_string(), self.head.to_json());
        m.insert("rustdoc_body".to_string(), self.body.to_json());
        m.insert("rustdoc_body_class".to_string(), self.body_class.to_json());
        m.insert("rustdoc_full".to_string(), self.full.to_json());
        m.insert("rustdoc_status".to_string(), true.to_json());
        m.insert("name".to_string(), self.name.to_json());
        m.insert("version".to_string(), self.version.to_json());
        m.insert("description".to_string(), self.description.to_json());
        m.insert("crate_details".to_string(), self.crate_details.to_json());
        m.to_json()
    }
}

pub struct RustLangRedirector {
    url: Url,
}

impl RustLangRedirector {
    pub fn new(target: &'static str) -> Self {
        let url = url::Url::parse("https://doc.rust-lang.org/stable/")
            .expect("failed to parse rust-lang.org base URL")
            .join(target)
            .expect("failed to append crate name to rust-lang.org base URL");
        let url = Url::from_generic_url(url)
            .expect("failed to convert url::Url to iron::Url");
        Self { url }
    }
}

impl iron::Handler for RustLangRedirector {
    fn handle(&self, _req: &mut Request) -> IronResult<Response> {
        Ok(Response::with((status::Found, Redirect(self.url.clone()))))
    }
}

/// Handler called for `/:crate` and `/:crate/:version` URLs. Automatically redirects to the docs
/// or crate details page based on whether the given crate version was successfully built.
pub fn rustdoc_redirector_handler(req: &mut Request) -> IronResult<Response> {

    fn redirect_to_doc(req: &Request,
                       name: &str,
                       vers: &str,
                       target_name: &str)
                       -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}/{}/{}/{}/",
                                            redirect_base(req),
                                            name,
                                            vers,
                                            target_name)[..]));
        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    fn redirect_to_crate(req: &Request,
                         name: &str,
                         vers: &str)
                         -> IronResult<Response> {
        let url = ctry!(Url::parse(&format!("{}/crate/{}/{}",
                                            redirect_base(req),
                                            name,
                                            vers)[..]));

        let mut resp = Response::with((status::Found, Redirect(url)));
        resp.headers.set(Expires(HttpDate(time::now())));

        Ok(resp)
    }

    // this unwrap is safe because iron urls are always able to use `path_segments`
    // i'm using this instead of `req.url.path()` to avoid allocating the Vec, and also to avoid
    // keeping the borrow alive into the return statement
    if req.url.as_ref().path_segments().unwrap().last().map_or(false, |s| s.ends_with(".js")) {
        // javascript files should be handled by the file server instead of erroneously
        // redirecting to the crate root page
        if req.url.as_ref().path_segments().unwrap().count() > 2 {
            // this URL is actually from a crate-internal path, serve it there instead
            return rustdoc_html_server_handler(req);
        } else {
            let path = req.url.path();
            let path = path.join("/");
            let conn = extension!(req, Pool);
            match File::from_path(&conn, &path) {
                Some(f) => return Ok(f.serve()),
                None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
            }
        }
    } else if req.url.as_ref().path_segments().unwrap().last().map_or(false, |s| s.ends_with(".ico")) {
        // route .ico files into their dedicated handler so that docs.rs's favicon is always
        // displayed
        return super::ico_handler(req);
    }

    let router = extension!(req, Router);
    // this handler should never called without crate pattern
    let crate_name = cexpect!(router.find("crate"));
    let req_version = router.find("version");

    let conn = extension!(req, Pool);

    // it doesn't matter if the version that was given was exact or not, since we're redirecting
    // anyway
    let version = match match_version(&conn, &crate_name, req_version).into_option() {
        Some(v) => v,
        None => return Err(IronError::new(Nope::CrateNotFound, status::NotFound)),
    };

    // get target name and whether it has docs
    // FIXME: This is a bit inefficient but allowing us to use less code in general
    let (target_name, has_docs): (String, bool) = {
        let rows = ctry!(conn.query("SELECT target_name, rustdoc_status
                                     FROM releases
                                     INNER JOIN crates ON crates.id = releases.crate_id
                                     WHERE crates.name = $1 AND releases.version = $2",
                                    &[&crate_name, &version]));

        (rows.get(0).get(0), rows.get(0).get(1))
    };

    if has_docs {
        redirect_to_doc(req, &crate_name, &version, &target_name)
    } else {
        redirect_to_crate(req, &crate_name, &version)
    }
}

/// Serves documentation generated by rustdoc.
///
/// This includes all HTML files for an individual crate, as well as the `search-index.js`, which is
/// also crate-specific.
pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {

    let router = extension!(req, Router);
    let name = router.find("crate").unwrap_or("").to_string();
    let url_version = router.find("version");
    let version; // pre-declaring it to enforce drop order relative to `req_path`
    let conn = extension!(req, Pool);

    let mut req_path = req.url.path();

    // remove name and version from path
    for _ in 0..2 {
        req_path.remove(0);
    }

    version = match match_version(&conn, &name, url_version) {
        MatchVersion::Exact(v) => v,
        MatchVersion::Semver(v) => {
            // to prevent cloudfront caching the wrong artifacts on URLs with loose semver
            // versions, redirect the browser to the returned version instead of loading it
            // immediately
            let url = ctry!(Url::parse(&format!("{}/{}/{}/{}",
                                                redirect_base(req),
                                                name,
                                                v,
                                                req_path.join("/"))[..]));
            return Ok(super::redirect(url));
        }
        MatchVersion::None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
    };

    // docs have "rustdoc" prefix in database
    req_path.insert(0, "rustdoc");

    // add crate name and version
    req_path.insert(1, &name);
    req_path.insert(2, &version);

    let path = {
        let mut path = req_path.join("/");
        if path.ends_with('/') {
            req_path.pop(); // get rid of empty string
            path.push_str("index.html");
            req_path.push("index.html");
        }
        path
    };

    let file = match File::from_path(&conn, &path) {
        Some(f) => f,
        None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
    };

    // serve file directly if it's not html
    if !path.ends_with(".html") {
        return Ok(file.serve());
    }

    let mut content = RustdocPage::default();

    let file_content = ctry!(String::from_utf8(file.0.content));

    let (head, body, mut body_class) = ctry!(utils::extract_head_and_body(&file_content));
    content.head = head;
    content.body = body;

    if body_class.is_empty() {
        body_class = "rustdoc container-rustdoc".to_string();
    } else {
        // rustdoc adds its own "rustdoc" class to the body
        body_class.push_str(" container-rustdoc");
    }
    content.body_class = body_class;

    content.full = file_content;
    let crate_details = cexpect!(CrateDetails::new(&conn, &name, &version));
    let (path, version) = if let Some(version) = latest_version(&crate_details.versions, &version) {
        req_path[2] = &version;
        (path_for_version(&req_path, &crate_details.target_name, &conn), version)
    } else {
        Default::default()
    };

    content.crate_details = Some(crate_details);

    Page::new(content)
        .set_true("show_package_navigation")
        .set_true("package_navigation_documentation_tab")
        .set_true("package_navigation_show_platforms_tab")
        .set_bool("is_latest_version", path.is_empty())
        .set("path_in_latest", &path)
        .set("latest_version", &version)
        .to_resp("rustdoc")
}

/// Checks whether the given path (including version and target information) exists.
/// The crate's `target_name` is used to confirm whether a platform triple is part of the path.
///
/// Returns a path that can be appended to `/crate/version/` to create a complete URL.
fn path_for_version(req_path: &[&str], target_name: &str, conn: &Connection) -> String {
    if File::from_path(&conn, &req_path.join("/")).is_some() {
        // NOTE: this adds 'index.html' if it wasn't there before
        req_path[3..].join("/")
    } else {
        // this page doesn't exist in the latest version
        let search_item = if *req_path.last().unwrap() == "index.html" {
            // this is a module
            req_path[req_path.len() - 2]
        } else {
            // this is an item
            req_path.last().unwrap().split('.').nth(1)
                .expect("paths should be of the form <class>.<name>.html")
        };
        // check if req_path[3] is the platform choice or the name of the crate
        let concat_path;
        let crate_root = if req_path[3] != target_name {
            concat_path = format!("{}/{}", req_path[3], req_path[4]);
            &concat_path
        } else {
            req_path[3]
        };
        format!("{}/?search={}", crate_root, search_item)
    }
}

pub fn badge_handler(req: &mut Request) -> IronResult<Response> {
    use iron::headers::ContentType;
    use params::{Params, Value};
    use badge::{Badge, BadgeOptions};

    let version = {
        let params = ctry!(req.get_ref::<Params>());
        match params.find(&["version"]) {
            Some(&Value::String(ref version)) => version.clone(),
            _ => "*".to_owned(),
        }
    };

    let name = cexpect!(extension!(req, Router).find("crate"));
    let conn = extension!(req, Pool);

    let options = match match_version(&conn, &name, Some(&version)) {
        MatchVersion::Exact(version) => {
            let rows = ctry!(conn.query("SELECT rustdoc_status
                                         FROM releases
                                         INNER JOIN crates ON crates.id = releases.crate_id
                                         WHERE crates.name = $1 AND releases.version = $2",
                                        &[&name, &version]));
            if rows.len() > 0 && rows.get(0).get(0) {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#4d76ae".to_owned(),
                }
            } else {
                BadgeOptions {
                    subject: "docs".to_owned(),
                    status: version,
                    color: "#e05d44".to_owned(),
                }
            }
        }
        MatchVersion::Semver(version) => {
            let url = ctry!(Url::parse(&format!("{}/{}/badge.svg?version={}",
                                                redirect_base(req),
                                                name,
                                                version)[..]));

            return Ok(super::redirect(url));
        }
        MatchVersion::None => {
            BadgeOptions {
                subject: "docs".to_owned(),
                status: "no builds".to_owned(),
                color: "#e05d44".to_owned(),
            }
        }
    };

    let mut resp = Response::with((status::Ok, ctry!(Badge::new(options)).to_svg()));
    resp.headers.set(ContentType("image/svg+xml".parse().unwrap()));
    resp.headers.set(Expires(HttpDate(time::now())));
    resp.headers.set(CacheControl(vec![CacheDirective::NoCache,
                                       CacheDirective::NoStore,
                                       CacheDirective::MustRevalidate]));
    Ok(resp)
}

/// Serves shared web resources used by rustdoc-generated documentation.
///
/// This includes common `css` and `js` files that only change when the compiler is updated, but are
/// otherwise the same for all crates documented with that compiler. Those have a custom handler to
/// deduplicate them and save space.
pub struct SharedResourceHandler;

impl Handler for SharedResourceHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        let path = req.url.path();
        let filename = path.last().unwrap();  // unwrap is fine: vector is non-empty
        let suffix = filename.split('.').last().unwrap();  // unwrap is fine: split always works
        if ["js", "css", "woff", "svg"].contains(&suffix) {
            let conn = extension!(req, Pool);

            if let Some(file) = File::from_path(conn, filename) {
                return Ok(file.serve());
            }
        }

        // Just always return a 404 here - the main handler will then try the other handlers
        Err(IronError::new(Nope::ResourceNotFound, status::NotFound))
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate wlroots;

use std::process::Command;
use std::thread;
use std::time::Duration;

use wlroots::{project_box, Area, Compositor, CompositorBuilder, CursorBuilder, CursorHandler,
              CursorId, InputManagerHandler, Keyboard, KeyboardHandler, Origin, Output,
              OutputBuilder, OutputBuilderResult, OutputHandler, OutputLayout,
              OutputManagerHandler, Pointer, PointerHandler, Renderer, Seat, SeatHandler, Size,
              Surface, XCursorTheme, XdgV6ShellHandler, XdgV6ShellManagerHandler,
              XdgV6ShellSurface, XdgV6ShellSurfaceHandle};
use wlroots::key_events::KeyEvent;
use wlroots::pointer_events::{ButtonEvent, MotionEvent};
use wlroots::utils::{init_logging, L_DEBUG};
use wlroots::wlroots_sys::wlr_button_state::WLR_BUTTON_PRESSED;
use wlroots::xkbcommon::xkb::keysyms::KEY_Escape;

struct State {
    xcursor_theme: XCursorTheme,
    layout: OutputLayout,
    cursor_id: CursorId,
    shells: Vec<XdgV6ShellSurfaceHandle>
}

impl State {
    fn new(xcursor_theme: XCursorTheme, layout: OutputLayout, cursor_id: CursorId) -> Self {
        State { xcursor_theme,
                layout,
                cursor_id,
                shells: vec![] }
    }
}

compositor_data!(State);

struct SeatHandlerEx;

struct CursorEx;

impl CursorHandler for CursorEx {}

impl SeatHandler for SeatHandlerEx {
    // TODO
}

struct XdgV6ShellHandlerEx;
struct XdgV6ShellManager;

impl XdgV6ShellHandler for XdgV6ShellHandlerEx {}
impl XdgV6ShellManagerHandler for XdgV6ShellManager {
    fn new_surface(&mut self,
                   compositor: &mut Compositor,
                   shell: &mut XdgV6ShellSurface,
                   _: &mut Surface)
                   -> Option<Box<XdgV6ShellHandler>> {
        let state: &mut State = compositor.into();
        state.shells.push(shell.weak_reference());
        for (mut output, _) in state.layout.outputs() {
            output.run(|output| output.schedule_frame()).unwrap();
        }
        Some(Box::new(XdgV6ShellHandlerEx))
    }

    fn surface_destroyed(&mut self,
                         compositor: &mut Compositor,
                         shell: &mut XdgV6ShellSurface,
                         _: &mut Surface) {
        let state: &mut State = compositor.into();
        let weak = shell.weak_reference();
        if let Some(index) = state.shells.iter().position(|s| *s == weak) {
            state.shells.remove(index);
        }
    }
}

struct OutputManager;

struct ExOutput;

struct InputManager;

struct ExPointer;

struct ExKeyboardHandler;

impl OutputManagerHandler for OutputManager {
    fn output_added<'output>(&mut self,
                             compositor: &mut Compositor,
                             builder: OutputBuilder<'output>)
                             -> Option<OutputBuilderResult<'output>> {
        let result = builder.build_best_mode(ExOutput);
        let state: &mut State = compositor.into();
        let xcursor = state.xcursor_theme
                           .get_cursor("left_ptr".into())
                           .expect("Could not load left_ptr cursor");
        let image = &xcursor.images()[0];
        // TODO use output config if present instead of auto
        state.layout.add_auto(result.output);
        let mut cursor = state.layout.cursor(state.cursor_id).unwrap();
        cursor.set_cursor_image(image);
        let (x, y) = cursor.coords();
        // https://en.wikipedia.org/wiki/Mouse_warping
        cursor.warp(None, x, y);
        Some(result)
    }
}

impl KeyboardHandler for ExKeyboardHandler {
    fn on_key(&mut self, compositor: &mut Compositor, _: &mut Keyboard, key_event: &mut KeyEvent) {
        for key in key_event.pressed_keys() {
            if key == KEY_Escape {
                compositor.terminate()
            } else {
                thread::spawn(move || {
                                  Command::new("weston-terminal").output().unwrap();
                              });
            }
        }
    }
}

impl PointerHandler for ExPointer {
    fn on_motion(&mut self, compositor: &mut Compositor, _: &mut Pointer, event: &MotionEvent) {
        let state: &mut State = compositor.into();
        let (delta_x, delta_y) = event.delta();
        state.layout
             .cursor(state.cursor_id)
             .unwrap()
             .move_to(event.device(), delta_x, delta_y);
    }

    fn on_button(&mut self, compositor: &mut Compositor, _: &mut Pointer, event: &ButtonEvent) {
        let state: &mut State = compositor.into();
        if event.state() == WLR_BUTTON_PRESSED {
            wlr_log!(L_DEBUG, "Clicking pointer {}", event.button())
        }
    }
}

impl OutputHandler for ExOutput {
    fn on_frame(&mut self, compositor: &mut Compositor, output: &mut Output) {
        let state: &mut State = compositor.data.downcast_mut().unwrap();
        if state.shells.len() < 1 {
            return
        }
        let renderer = compositor.renderer
                                 .as_mut()
                                 .expect("Compositor was not loaded with a renderer");
        render_shells(state, &mut renderer.render(output));
    }
}

impl InputManagerHandler for InputManager {
    fn pointer_added(&mut self,
                     _: &mut Compositor,
                     _: &mut Pointer)
                     -> Option<Box<PointerHandler>> {
        Some(Box::new(ExPointer))
    }

    fn keyboard_added(&mut self,
                      _: &mut Compositor,
                      _: &mut Keyboard)
                      -> Option<Box<KeyboardHandler>> {
        Some(Box::new(ExKeyboardHandler))
    }
}

fn main() {
    init_logging(L_DEBUG, None);
    let cursor = CursorBuilder::new(Box::new(CursorEx)).expect("Could not create cursor");
    let xcursor_theme = XCursorTheme::load_theme(None, 16).expect("Could not load theme");
    let mut layout = OutputLayout::new().expect("Could not construct an output layout");

    let cursor_id = layout.attach_cursor(cursor);
    let mut compositor =
        CompositorBuilder::new().gles2(true)
                                .input_manager(Box::new(InputManager))
                                .output_manager(Box::new(OutputManager))
                                .xdg_shell_v6_manager(Box::new(XdgV6ShellManager))
                                .build_auto(State::new(xcursor_theme, layout, cursor_id));
    Seat::create(&mut compositor, "Main Seat".into(), Box::new(SeatHandlerEx))
        .expect("Could not allocate the global seat");
    compositor.run();
}

/// Render the shells in the current compositor state on the given output.
fn render_shells(state: &mut State, renderer: &mut Renderer) {
    let shells = state.shells.clone();
    for mut shell in shells {
        shell.run(|shell| {
                      shell.surface()
                           .run(|surface| {
                                    let (width, height) = surface.current_state().size();
                                    let (render_width, render_height) =
                                        (width * renderer.output.scale() as i32,
                                        height * renderer.output.scale() as i32);
                                    let (lx, ly) = (0.0, 0.0);
                                    let render_box = Area::new(Origin::new(lx as i32, ly as i32),
                                                               Size::new(render_width,
                                                                         render_height));
                                    if state.layout.intersects(renderer.output, render_box) {
                                        let transform = renderer.output.get_transform().invert();
                                        let matrix = project_box(render_box,
                                                                 transform,
                                                                 0.0,
                                                                 renderer.output
                                                                         .transform_matrix());
                                        renderer.render_texture_with_matrix(&surface.texture(),
                                                                            matrix);
                                        surface.send_frame_done(Duration::from_secs(1));
                                    }
                                })
                           .unwrap()
                  })
             .unwrap();
    }
}
<commit_msg>xdg-shell-test: store seat id, set keyboard on seat<commit_after>#[macro_use]
extern crate wlroots;

use std::process::Command;
use std::thread;
use std::time::Duration;

use wlroots::{project_box, Area, Compositor, CompositorBuilder, CursorBuilder, CursorHandler,
              CursorId, InputManagerHandler, Keyboard, KeyboardHandler, Origin, Output,
              OutputBuilder, OutputBuilderResult, OutputHandler, OutputLayout,
              OutputManagerHandler, Pointer, PointerHandler, Renderer, Seat, SeatHandler, SeatId,
              Size, Surface, XCursorTheme, XdgV6ShellHandler, XdgV6ShellManagerHandler,
              XdgV6ShellSurface, XdgV6ShellSurfaceHandle};
use wlroots::key_events::KeyEvent;
use wlroots::pointer_events::{ButtonEvent, MotionEvent};
use wlroots::utils::{init_logging, L_DEBUG};
use wlroots::wlroots_sys::wlr_button_state::WLR_BUTTON_PRESSED;
use wlroots::xkbcommon::xkb::keysyms::KEY_Escape;

struct State {
    xcursor_theme: XCursorTheme,
    layout: OutputLayout,
    cursor_id: CursorId,
    shells: Vec<XdgV6ShellSurfaceHandle>,
    seat_id: Option<SeatId>
}

impl State {
    fn new(xcursor_theme: XCursorTheme, layout: OutputLayout, cursor_id: CursorId) -> Self {
        State { xcursor_theme,
                layout,
                cursor_id,
                seat_id: None,
                shells: vec![] }
    }
}

compositor_data!(State);

struct SeatHandlerEx;

struct CursorEx;

impl CursorHandler for CursorEx {}

impl SeatHandler for SeatHandlerEx {
    // TODO
}

struct XdgV6ShellHandlerEx;
struct XdgV6ShellManager;

impl XdgV6ShellHandler for XdgV6ShellHandlerEx {}
impl XdgV6ShellManagerHandler for XdgV6ShellManager {
    fn new_surface(&mut self,
                   compositor: &mut Compositor,
                   shell: &mut XdgV6ShellSurface,
                   _: &mut Surface)
                   -> Option<Box<XdgV6ShellHandler>> {
        let state: &mut State = compositor.into();
        state.shells.push(shell.weak_reference());
        for (mut output, _) in state.layout.outputs() {
            output.run(|output| output.schedule_frame()).unwrap();
        }
        Some(Box::new(XdgV6ShellHandlerEx))
    }

    fn surface_destroyed(&mut self,
                         compositor: &mut Compositor,
                         shell: &mut XdgV6ShellSurface,
                         _: &mut Surface) {
        let state: &mut State = compositor.into();
        let weak = shell.weak_reference();
        if let Some(index) = state.shells.iter().position(|s| *s == weak) {
            state.shells.remove(index);
        }
    }
}

struct OutputManager;

struct ExOutput;

struct InputManager;

struct ExPointer;

struct ExKeyboardHandler;

impl OutputManagerHandler for OutputManager {
    fn output_added<'output>(&mut self,
                             compositor: &mut Compositor,
                             builder: OutputBuilder<'output>)
                             -> Option<OutputBuilderResult<'output>> {
        let result = builder.build_best_mode(ExOutput);
        let state: &mut State = compositor.into();
        let xcursor = state.xcursor_theme
                           .get_cursor("left_ptr".into())
                           .expect("Could not load left_ptr cursor");
        let image = &xcursor.images()[0];
        // TODO use output config if present instead of auto
        state.layout.add_auto(result.output);
        let mut cursor = state.layout.cursor(state.cursor_id).unwrap();
        cursor.set_cursor_image(image);
        let (x, y) = cursor.coords();
        // https://en.wikipedia.org/wiki/Mouse_warping
        cursor.warp(None, x, y);
        Some(result)
    }
}

impl KeyboardHandler for ExKeyboardHandler {
    fn on_key(&mut self, compositor: &mut Compositor, _: &mut Keyboard, key_event: &mut KeyEvent) {
        for key in key_event.pressed_keys() {
            if key == KEY_Escape {
                compositor.terminate()
            } else {
                thread::spawn(move || {
                                  Command::new("weston-terminal").output().unwrap();
                              });
            }
        }
    }
}

impl PointerHandler for ExPointer {
    fn on_motion(&mut self, compositor: &mut Compositor, _: &mut Pointer, event: &MotionEvent) {
        let state: &mut State = compositor.into();
        let (delta_x, delta_y) = event.delta();
        state.layout
             .cursor(state.cursor_id)
             .unwrap()
             .move_to(event.device(), delta_x, delta_y);
    }

    fn on_button(&mut self, _: &mut Compositor, _: &mut Pointer, event: &ButtonEvent) {
        if event.state() == WLR_BUTTON_PRESSED {
            wlr_log!(L_DEBUG, "Clicking pointer {}", event.button())
        }
    }
}

impl OutputHandler for ExOutput {
    fn on_frame(&mut self, compositor: &mut Compositor, output: &mut Output) {
        let state: &mut State = compositor.data.downcast_mut().unwrap();
        if state.shells.len() < 1 {
            return
        }
        let renderer = compositor.renderer
                                 .as_mut()
                                 .expect("Compositor was not loaded with a renderer");
        render_shells(state, &mut renderer.render(output));
    }
}

impl InputManagerHandler for InputManager {
    fn pointer_added(&mut self,
                     _: &mut Compositor,
                     _: &mut Pointer)
                     -> Option<Box<PointerHandler>> {
        Some(Box::new(ExPointer))
    }

    fn keyboard_added(&mut self,
                      compositor: &mut Compositor,
                      keyboard: &mut Keyboard)
                      -> Option<Box<KeyboardHandler>> {
        let seat_id = {
            let state: &mut State = compositor.into();
            state.seat_id.unwrap()
        };
        let seat = compositor.seats.get(seat_id).expect("Invalid seat id");
        seat.set_keyboard(keyboard.input_device());
        Some(Box::new(ExKeyboardHandler))
    }
}

fn main() {
    init_logging(L_DEBUG, None);
    let cursor = CursorBuilder::new(Box::new(CursorEx)).expect("Could not create cursor");
    let xcursor_theme = XCursorTheme::load_theme(None, 16).expect("Could not load theme");
    let mut layout = OutputLayout::new().expect("Could not construct an output layout");

    let cursor_id = layout.attach_cursor(cursor);
    let mut compositor =
        CompositorBuilder::new().gles2(true)
                                .input_manager(Box::new(InputManager))
                                .output_manager(Box::new(OutputManager))
                                .xdg_shell_v6_manager(Box::new(XdgV6ShellManager))
                                .build_auto(State::new(xcursor_theme, layout, cursor_id));

    {
        let seat_id = Seat::create(&mut compositor, "Main Seat".into(), Box::new(SeatHandlerEx))
            .expect("Could not allocate the global seat").id();
        let state: &mut State = (&mut compositor).into();
        state.seat_id = Some(seat_id);
    }
    compositor.run();
}

/// Render the shells in the current compositor state on the given output.
fn render_shells(state: &mut State, renderer: &mut Renderer) {
    let shells = state.shells.clone();
    for mut shell in shells {
        shell.run(|shell| {
                      shell.surface()
                           .run(|surface| {
                                    let (width, height) = surface.current_state().size();
                                    let (render_width, render_height) =
                                        (width * renderer.output.scale() as i32,
                                        height * renderer.output.scale() as i32);
                                    let (lx, ly) = (0.0, 0.0);
                                    let render_box = Area::new(Origin::new(lx as i32, ly as i32),
                                                               Size::new(render_width,
                                                                         render_height));
                                    if state.layout.intersects(renderer.output, render_box) {
                                        let transform = renderer.output.get_transform().invert();
                                        let matrix = project_box(render_box,
                                                                 transform,
                                                                 0.0,
                                                                 renderer.output
                                                                         .transform_matrix());
                                        renderer.render_texture_with_matrix(&surface.texture(),
                                                                            matrix);
                                        surface.send_frame_done(Duration::from_secs(1));
                                    }
                                })
                           .unwrap()
                  })
             .unwrap();
    }
}
<|endoftext|>


<commit_before>// run-pass
#![allow(dead_code)]
// check that we don't have linear stack usage with multiple calls to `push`

#![feature(test)]

extern crate test;
use std::mem;

fn meal() -> Big {
    if test::black_box(false) {
        panic!()
    }
    Big { drop_me: [
        None, None, None, None, None, None, None, None,
        None, None, None, None, None, None, None, None,
        None, None, None, None, None, None, None, None,
        None, None, None, None, None, None, None, None,
        None, None, None, None, None, None, None, None,
        None, None, None, None, None, None, None, None,
    ]}
}

pub struct Big {
    drop_me: [Option<Box<u8>>; 48],
}

#[inline]
fn push(out: &mut Vec<Big>) {
    out.push(meal());
}

#[inline(never)]
pub fn supersize_me(out: &mut Vec<Big>) {
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out); // 16 calls to `push`

    verify_stack_usage(out);

    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out); // 16 calls to `push`
}

#[inline(never)]
fn verify_stack_usage(before_ptr: *mut Vec<Big>) {
    // to check stack usage, create locals before and after
    // and check the difference in addresses between them.
    let mut stack_var: Vec<Big> = vec![];
    test::black_box(&mut stack_var);
    let stack_usage = isize::abs(
        (&mut stack_var as *mut _ as isize) -
            (before_ptr as isize)) as usize;
    // give space for 2 copies of `Big` + 256 "misc" bytes.
    if stack_usage > mem::size_of::<Big>() * 2 + 256 {
        panic!("used {} bytes of stack, but `struct Big` is only {} bytes",
               stack_usage, mem::size_of::<Big>());
    }

}

pub fn main() {
    let mut v = vec![];
    test::black_box(&mut v);
    supersize_me(&mut v);
}
<commit_msg>increase stack slack for x86_64-pc-windows-gnu<commit_after>// run-pass
#![allow(dead_code)]
// check that we don't have linear stack usage with multiple calls to `push`

#![feature(test)]

extern crate test;
use std::mem;

fn meal() -> Big {
    if test::black_box(false) {
        panic!()
    }
    Big { drop_me: [
        None, None, None, None, None, None, None, None,
        None, None, None, None, None, None, None, None,
        None, None, None, None, None, None, None, None,
        None, None, None, None, None, None, None, None,
        None, None, None, None, None, None, None, None,
        None, None, None, None, None, None, None, None,
    ]}
}

pub struct Big {
    drop_me: [Option<Box<u8>>; 48],
}

#[inline]
fn push(out: &mut Vec<Big>) {
    out.push(meal());
}

#[inline(never)]
pub fn supersize_me(out: &mut Vec<Big>) {
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out); // 16 calls to `push`

    verify_stack_usage(out);

    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out);
    push(out); // 16 calls to `push`
}

#[inline(never)]
fn verify_stack_usage(before_ptr: *mut Vec<Big>) {
    // To check stack usage, create locals before and after
    // and check the difference in addresses between them.
    let mut stack_var: Vec<Big> = vec![];
    test::black_box(&mut stack_var);
    let stack_usage = isize::abs(
        (&mut stack_var as *mut _ as isize) -
            (before_ptr as isize)) as usize;
    // Give space for 2 copies of `Big` + 272 "misc" bytes
    // (value observed on x86_64-pc-windows-gnu).
    if stack_usage > mem::size_of::<Big>() * 2 + 272 {
        panic!("used {} bytes of stack, but `struct Big` is only {} bytes",
               stack_usage, mem::size_of::<Big>());
    }

}

pub fn main() {
    let mut v = vec![];
    test::black_box(&mut v);
    supersize_me(&mut v);
}
<|endoftext|>


<commit_before>use core::f64::consts::pi;
use num::cast::*;
use vec::Vec3;

pub trait Angle<T>: Add<self,self>
                  , Sub<self,self>
                  , Mul<T,self>
                  , Div<T,self>
                  , Modulo<T,self>
                  , Neg<self> {
    pure fn to_radians() -> Radians<T>;
    pure fn to_degrees() -> Degrees<T>;
}

pub enum Radians<T> = T;

pub impl<T:Copy Num NumCast> Radians<T>: Angle<T> {
    #[inline(always)] pure fn to_radians() -> Radians<T> { self }
    #[inline(always)] pure fn to_degrees() -> Degrees<T> { Degrees(*self * cast(180.0 / pi)) }

    #[inline(always)] pure fn add(rhs: &Radians<T>) -> Radians<T> { Radians(*self + **rhs) }
    #[inline(always)] pure fn sub(rhs: &Radians<T>) -> Radians<T> { Radians(*self - **rhs) }
    #[inline(always)] pure fn mul(rhs: &T)          -> Radians<T> { Radians(*self * *rhs) }
    #[inline(always)] pure fn div(rhs: &T)          -> Radians<T> { Radians(*self / *rhs) }
    #[inline(always)] pure fn modulo(rhs: &T)       -> Radians<T> { Radians(*self % *rhs) }
    #[inline(always)] pure fn neg()                 -> Radians<T> { Radians(-*self) }
}

pub enum Degrees<T> = T;

pub impl<T:Copy Num NumCast> Degrees<T>: Angle<T> {
    #[inline(always)] pure fn to_radians() -> Radians<T> { Radians(*self * cast(pi / 180.0)) }
    #[inline(always)] pure fn to_degrees() -> Degrees<T> { self }

    #[inline(always)] pure fn add(rhs: &Degrees<T>) -> Degrees<T> { Degrees(*self + **rhs) }
    #[inline(always)] pure fn sub(rhs: &Degrees<T>) -> Degrees<T> { Degrees(*self - **rhs) }
    #[inline(always)] pure fn mul(rhs: &T)          -> Degrees<T> { Degrees(*self * *rhs) }
    #[inline(always)] pure fn div(rhs: &T)          -> Degrees<T> { Degrees(*self / *rhs) }
    #[inline(always)] pure fn modulo(rhs: &T)       -> Degrees<T> { Degrees(*self % *rhs) }
    #[inline(always)] pure fn neg()                 -> Degrees<T> { Degrees(-*self) }
}

pub struct AxialRotation<T> {
    axis: Vec3<T>,
    theta: Radians<T>,
}

pub struct Euler<T> {
    x: Radians<T>,   // pitch
    y: Radians<T>,   // yaw
    z: Radians<T>,   // roll
}<commit_msg>Implement Eq and Ord on angle types<commit_after>use core::cmp::{Eq, Ord};
use core::f64::consts::pi;
use num::cast::*;
use vec::Vec3;

pub trait Angle<T>: Add<self,self>
                  , Sub<self,self>
                  , Mul<T,self>
                  , Div<T,self>
                  , Modulo<T,self>
                  , Neg<self>
                  , Eq, Ord {
    pure fn to_radians() -> Radians<T>;
    pure fn to_degrees() -> Degrees<T>;
}

pub enum Radians<T> = T;

pub impl<T:Copy Num NumCast> Radians<T>: Angle<T> {
    #[inline(always)] pure fn to_radians() -> Radians<T> { self }
    #[inline(always)] pure fn to_degrees() -> Degrees<T> { Degrees(*self * cast(180.0 / pi)) }

    #[inline(always)] pure fn add(rhs: &Radians<T>) -> Radians<T> { Radians(*self + **rhs) }
    #[inline(always)] pure fn sub(rhs: &Radians<T>) -> Radians<T> { Radians(*self - **rhs) }
    #[inline(always)] pure fn mul(rhs: &T)          -> Radians<T> { Radians(*self * *rhs) }
    #[inline(always)] pure fn div(rhs: &T)          -> Radians<T> { Radians(*self / *rhs) }
    #[inline(always)] pure fn modulo(rhs: &T)       -> Radians<T> { Radians(*self % *rhs) }
    #[inline(always)] pure fn neg()                 -> Radians<T> { Radians(-*self) }
}

pub impl<T:Copy Eq> Radians<T>: Eq {
    #[inline(always)] pure fn eq(other: &Radians<T>) -> bool { *self == **other }
    #[inline(always)] pure fn ne(other: &Radians<T>) -> bool { *self != **other }
}

pub impl<T:Copy Ord> Radians<T>: Ord {
    #[inline(always)] pure fn lt(other: &Radians<T>) -> bool { *self <  **other }
    #[inline(always)] pure fn le(other: &Radians<T>) -> bool { *self <= **other }
    #[inline(always)] pure fn ge(other: &Radians<T>) -> bool { *self >= **other }
    #[inline(always)] pure fn gt(other: &Radians<T>) -> bool { *self >  **other }
}

pub enum Degrees<T> = T;

pub impl<T:Copy Num NumCast> Degrees<T>: Angle<T> {
    #[inline(always)] pure fn to_radians() -> Radians<T> { Radians(*self * cast(pi / 180.0)) }
    #[inline(always)] pure fn to_degrees() -> Degrees<T> { self }

    #[inline(always)] pure fn add(rhs: &Degrees<T>) -> Degrees<T> { Degrees(*self + **rhs) }
    #[inline(always)] pure fn sub(rhs: &Degrees<T>) -> Degrees<T> { Degrees(*self - **rhs) }
    #[inline(always)] pure fn mul(rhs: &T)          -> Degrees<T> { Degrees(*self * *rhs) }
    #[inline(always)] pure fn div(rhs: &T)          -> Degrees<T> { Degrees(*self / *rhs) }
    #[inline(always)] pure fn modulo(rhs: &T)       -> Degrees<T> { Degrees(*self % *rhs) }
    #[inline(always)] pure fn neg()                 -> Degrees<T> { Degrees(-*self) }
}

pub impl<T:Copy Eq> Degrees<T>: Eq {
    #[inline(always)] pure fn eq(other: &Degrees<T>) -> bool { *self == **other }
    #[inline(always)] pure fn ne(other: &Degrees<T>) -> bool { *self != **other }
}

pub impl<T:Copy Ord> Degrees<T>: Ord {
    #[inline(always)] pure fn lt(other: &Degrees<T>) -> bool { *self <  **other }
    #[inline(always)] pure fn le(other: &Degrees<T>) -> bool { *self <= **other }
    #[inline(always)] pure fn ge(other: &Degrees<T>) -> bool { *self >= **other }
    #[inline(always)] pure fn gt(other: &Degrees<T>) -> bool { *self >  **other }
}

pub struct AxialRotation<T> {
    axis: Vec3<T>,
    theta: Radians<T>,
}

pub struct Euler<T> {
    x: Radians<T>,   // pitch
    y: Radians<T>,   // yaw
    z: Radians<T>,   // roll
}<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use num_traits::{Float, FloatConst, Zero, One};
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, Sub, SubAssign};
use core::cmp::{Eq, PartialEq};
use core::hash::{Hash};
use crate::trig::Trig;
use crate::approxeq::ApproxEq;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

/// An angle in radians
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Angle<T> {
    pub radians: T,
}

impl<T> Angle<T> {
    #[inline]
    pub fn radians(radians: T) -> Self {
        Angle { radians }
    }

    #[inline]
    pub fn get(self) -> T {
        self.radians
    }
}

impl<T> Angle<T>
where
    T: Trig,
{
    #[inline]
    pub fn degrees(deg: T) -> Self {
        Angle {
            radians: T::degrees_to_radians(deg),
        }
    }

    #[inline]
    pub fn to_degrees(self) -> T {
        T::radians_to_degrees(self.radians)
    }
}

impl<T> Angle<T>
where
    T: Rem<Output = T> + Sub<Output = T> + Add<Output = T> + Zero + FloatConst + PartialOrd + Copy,
{
    /// Returns this angle in the [0..2*PI[ range.
    pub fn positive(&self) -> Self {
        let two_pi = T::PI() + T::PI();
        let mut a = self.radians % two_pi;
        if a < T::zero() {
            a = a + two_pi;
        }
        Angle::radians(a)
    }

    /// Returns this angle in the ]-PI..PI] range.
    pub fn signed(&self) -> Self {
        Angle::pi() - (Angle::pi() - *self).positive()
    }

}

impl<T> Angle<T>
where
    T: Rem<Output = T> + Mul<Output = T> + Sub<Output = T> + Add<Output = T> + One + FloatConst + Copy,
{
    /// Returns the shortest signed angle between two angles.
    ///
    /// Takes wrapping and signs into account.
    pub fn angle_to(&self, to: Self) -> Self {
        let two = T::one() + T::one();
        let max = T::PI() * two;
        let d = (to.radians - self.radians) % max;

        Angle::radians(two * d % max - d)
    }

    /// Linear interpolation between two angles, using the shortest path.
    pub fn lerp(&self, other: Self, t: T) -> Self {
        *self + self.angle_to(other) * t
    }
}

impl<T> Angle<T>
where
    T: Float,
{
    /// Returns (sin(self), cos(self)).
    pub fn sin_cos(self) -> (T, T) {
        self.radians.sin_cos()
    }
}

impl<T> Angle<T>
where
    T: Zero,
{
    pub fn zero() -> Self {
        Angle::radians(T::zero())
    }
}

impl<T> Angle<T>
where
    T: FloatConst + Add<Output = T>,
{
    pub fn pi() -> Self {
        Angle::radians(T::PI())
    }

    pub fn two_pi() -> Self {
        Angle::radians(T::PI() + T::PI())
    }

    pub fn frac_pi_2() -> Self {
        Angle::radians(T::FRAC_PI_2())
    }

    pub fn frac_pi_3() -> Self {
        Angle::radians(T::FRAC_PI_3())
    }

    pub fn frac_pi_4() -> Self {
        Angle::radians(T::FRAC_PI_4())
    }
}

impl<T: Add<T, Output = T>> Add for Angle<T> {
    type Output = Angle<T>;
    fn add(self, other: Angle<T>) -> Angle<T> {
        Angle::radians(self.radians + other.radians)
    }
}

impl<T: AddAssign<T>> AddAssign for Angle<T> {
    fn add_assign(&mut self, other: Angle<T>) {
        self.radians += other.radians;
    }
}

impl<T: Sub<T, Output = T>> Sub<Angle<T>> for Angle<T> {
    type Output = Angle<T>;
    fn sub(self, other: Angle<T>) -> <Self as Sub>::Output {
        Angle::radians(self.radians - other.radians)
    }
}

impl<T: SubAssign<T>> SubAssign for Angle<T> {
    fn sub_assign(&mut self, other: Angle<T>) {
        self.radians -= other.radians;
    }
}

impl<T: Div<T, Output = T>> Div<Angle<T>> for Angle<T> {
    type Output = T;
    #[inline]
    fn div(self, other: Angle<T>) -> T {
        self.radians / other.radians
    }
}

impl<T: Div<T, Output = T>> Div<T> for Angle<T> {
    type Output = Angle<T>;
    #[inline]
    fn div(self, factor: T) -> Angle<T> {
        Angle::radians(self.radians / factor)
    }
}

impl<T: DivAssign<T>> DivAssign<T> for Angle<T> {
    fn div_assign(&mut self, factor: T) {
        self.radians /= factor;
    }
}

impl<T: Mul<T, Output = T>> Mul<T> for Angle<T> {
    type Output = Angle<T>;
    #[inline]
    fn mul(self, factor: T) -> Angle<T> {
        Angle::radians(self.radians * factor)
    }
}

impl<T: MulAssign<T>> MulAssign<T> for Angle<T> {
    fn mul_assign(&mut self, factor: T) {
        self.radians *= factor;
    }
}

impl<T: Neg<Output = T>> Neg for Angle<T> {
    type Output = Self;
    fn neg(self) -> Self {
        Angle::radians(-self.radians)
    }
}

impl<T: ApproxEq<T>> ApproxEq<T> for Angle<T> {
    #[inline]
    fn approx_epsilon() -> T {
        T::approx_epsilon()
    }

    #[inline]
    fn approx_eq_eps(&self, other: &Angle<T>, approx_epsilon: &T) -> bool {
        self.radians.approx_eq_eps(&other.radians, approx_epsilon)
    }
}

#[test]
fn wrap_angles() {
    use core::f32::consts::{FRAC_PI_2, PI};

    assert!(Angle::radians(0.0).positive().approx_eq(&Angle::zero()));
    assert!(
        Angle::radians(FRAC_PI_2)
            .positive()
            .approx_eq(&Angle::frac_pi_2())
    );
    assert!(
        Angle::radians(-FRAC_PI_2)
            .positive()
            .approx_eq(&Angle::radians(3.0 * FRAC_PI_2))
    );
    assert!(
        Angle::radians(3.0 * FRAC_PI_2)
            .positive()
            .approx_eq(&Angle::radians(3.0 * FRAC_PI_2))
    );
    assert!(
        Angle::radians(5.0 * FRAC_PI_2)
            .positive()
            .approx_eq(&Angle::frac_pi_2())
    );
    assert!(Angle::radians(2.0 * PI).positive().approx_eq(&Angle::zero()));
    assert!(Angle::radians(-2.0 * PI).positive().approx_eq(&Angle::zero()));
    assert!(Angle::radians(PI).positive().approx_eq(&Angle::pi()));
    assert!(Angle::radians(-PI).positive().approx_eq(&Angle::pi()));

    assert!(
        Angle::radians(FRAC_PI_2)
            .signed()
            .approx_eq(&Angle::frac_pi_2())
    );
    assert!(
        Angle::radians(3.0 * FRAC_PI_2)
            .signed()
            .approx_eq(&-Angle::frac_pi_2())
    );
    assert!(
        Angle::radians(5.0 * FRAC_PI_2)
            .signed()
            .approx_eq(&Angle::frac_pi_2())
    );
    assert!(Angle::radians(2.0 * PI).signed().approx_eq(&Angle::zero()));
    assert!(Angle::radians(-2.0 * PI).signed().approx_eq(&Angle::zero()));
    assert!(Angle::radians(-PI).signed().approx_eq(&Angle::pi()));
    assert!(Angle::radians(PI).signed().approx_eq(&Angle::pi()));
}

#[test]
fn lerp() {
    type A = Angle<f32>;

    let a = A::radians(1.0);
    let b = A::radians(2.0);
    assert!(a.lerp(b, 0.25).approx_eq(&Angle::radians(1.25)));
    assert!(a.lerp(b, 0.5).approx_eq(&Angle::radians(1.5)));
    assert!(a.lerp(b, 0.75).approx_eq(&Angle::radians(1.75)));
    assert!(a.lerp(b + A::two_pi(), 0.75).approx_eq(&Angle::radians(1.75)));
    assert!(a.lerp(b - A::two_pi(), 0.75).approx_eq(&Angle::radians(1.75)));
    assert!(a.lerp(b + A::two_pi() * 5.0, 0.75).approx_eq(&Angle::radians(1.75)));
}
<commit_msg>Auto merge of #436 - barsoosayque:master, r=nical<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use num_traits::{Float, FloatConst, Zero, One};
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, Sub, SubAssign};
use core::cmp::{Eq, PartialEq};
use core::hash::{Hash};
use crate::trig::Trig;
use crate::approxeq::ApproxEq;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

/// An angle in radians
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Angle<T> {
    pub radians: T,
}

impl<T> Angle<T> {
    #[inline]
    pub fn radians(radians: T) -> Self {
        Angle { radians }
    }

    #[inline]
    pub fn get(self) -> T {
        self.radians
    }
}

impl<T> Angle<T>
where
    T: Trig,
{
    #[inline]
    pub fn degrees(deg: T) -> Self {
        Angle {
            radians: T::degrees_to_radians(deg),
        }
    }

    #[inline]
    pub fn to_degrees(self) -> T {
        T::radians_to_degrees(self.radians)
    }
}

impl<T> Angle<T>
where
    T: Rem<Output = T> + Sub<Output = T> + Add<Output = T> + Zero + FloatConst + PartialOrd + Copy,
{
    /// Returns this angle in the [0..2*PI[ range.
    pub fn positive(&self) -> Self {
        let two_pi = T::PI() + T::PI();
        let mut a = self.radians % two_pi;
        if a < T::zero() {
            a = a + two_pi;
        }
        Angle::radians(a)
    }

    /// Returns this angle in the ]-PI..PI] range.
    pub fn signed(&self) -> Self {
        Angle::pi() - (Angle::pi() - *self).positive()
    }

}

impl<T> Angle<T>
where
    T: Rem<Output = T> + Mul<Output = T> + Sub<Output = T> + Add<Output = T> + One + FloatConst + Copy,
{
    /// Returns the shortest signed angle between two angles.
    ///
    /// Takes wrapping and signs into account.
    pub fn angle_to(&self, to: Self) -> Self {
        let two = T::one() + T::one();
        let max = T::PI() * two;
        let d = (to.radians - self.radians) % max;

        Angle::radians(two * d % max - d)
    }

    /// Linear interpolation between two angles, using the shortest path.
    pub fn lerp(&self, other: Self, t: T) -> Self {
        *self + self.angle_to(other) * t
    }
}

impl<T> Angle<T>
where
    T: Float,
{
    /// Returns (sin(self), cos(self)).
    pub fn sin_cos(self) -> (T, T) {
        self.radians.sin_cos()
    }
}

impl<T> Angle<T>
where
    T: Zero,
{
    pub fn zero() -> Self {
        Angle::radians(T::zero())
    }
}

impl<T> Angle<T>
where
    T: FloatConst + Add<Output = T>,
{
    pub fn pi() -> Self {
        Angle::radians(T::PI())
    }

    pub fn two_pi() -> Self {
        Angle::radians(T::PI() + T::PI())
    }

    pub fn frac_pi_2() -> Self {
        Angle::radians(T::FRAC_PI_2())
    }

    pub fn frac_pi_3() -> Self {
        Angle::radians(T::FRAC_PI_3())
    }

    pub fn frac_pi_4() -> Self {
        Angle::radians(T::FRAC_PI_4())
    }
}

impl<T: Add<T, Output = T>> Add for Angle<T> {
    type Output = Angle<T>;
    fn add(self, other: Angle<T>) -> Angle<T> {
        Angle::radians(self.radians + other.radians)
    }
}

impl<T: AddAssign<T>> AddAssign for Angle<T> {
    fn add_assign(&mut self, other: Angle<T>) {
        self.radians += other.radians;
    }
}

impl<T: Sub<T, Output = T>> Sub<Angle<T>> for Angle<T> {
    type Output = Angle<T>;
    fn sub(self, other: Angle<T>) -> <Self as Sub>::Output {
        Angle::radians(self.radians - other.radians)
    }
}

impl<T: SubAssign<T>> SubAssign for Angle<T> {
    fn sub_assign(&mut self, other: Angle<T>) {
        self.radians -= other.radians;
    }
}

impl<T: Div<T, Output = T>> Div<Angle<T>> for Angle<T> {
    type Output = T;
    #[inline]
    fn div(self, other: Angle<T>) -> T {
        self.radians / other.radians
    }
}

impl<T: Div<T, Output = T>> Div<T> for Angle<T> {
    type Output = Angle<T>;
    #[inline]
    fn div(self, factor: T) -> Angle<T> {
        Angle::radians(self.radians / factor)
    }
}

impl<T: DivAssign<T>> DivAssign<T> for Angle<T> {
    fn div_assign(&mut self, factor: T) {
        self.radians /= factor;
    }
}

impl<T: Mul<T, Output = T>> Mul<T> for Angle<T> {
    type Output = Angle<T>;
    #[inline]
    fn mul(self, factor: T) -> Angle<T> {
        Angle::radians(self.radians * factor)
    }
}

impl<T: MulAssign<T>> MulAssign<T> for Angle<T> {
    fn mul_assign(&mut self, factor: T) {
        self.radians *= factor;
    }
}

impl<T: Neg<Output = T>> Neg for Angle<T> {
    type Output = Self;
    fn neg(self) -> Self {
        Angle::radians(-self.radians)
    }
}

impl<T: ApproxEq<T>> ApproxEq<T> for Angle<T> {
    #[inline]
    fn approx_epsilon() -> T {
        T::approx_epsilon()
    }

    #[inline]
    fn approx_eq_eps(&self, other: &Angle<T>, approx_epsilon: &T) -> bool {
        self.radians.approx_eq_eps(&other.radians, approx_epsilon)
    }
}

#[test]
fn wrap_angles() {
    use core::f32::consts::{FRAC_PI_2, PI};

    assert!(Angle::radians(0.0).positive().approx_eq(&Angle::zero()));
    assert!(
        Angle::radians(FRAC_PI_2)
            .positive()
            .approx_eq(&Angle::frac_pi_2())
    );
    assert!(
        Angle::radians(-FRAC_PI_2)
            .positive()
            .approx_eq(&Angle::radians(3.0 * FRAC_PI_2))
    );
    assert!(
        Angle::radians(3.0 * FRAC_PI_2)
            .positive()
            .approx_eq(&Angle::radians(3.0 * FRAC_PI_2))
    );
    assert!(
        Angle::radians(5.0 * FRAC_PI_2)
            .positive()
            .approx_eq(&Angle::frac_pi_2())
    );
    assert!(Angle::radians(2.0 * PI).positive().approx_eq(&Angle::zero()));
    assert!(Angle::radians(-2.0 * PI).positive().approx_eq(&Angle::zero()));
    assert!(Angle::radians(PI).positive().approx_eq(&Angle::pi()));
    assert!(Angle::radians(-PI).positive().approx_eq(&Angle::pi()));

    assert!(
        Angle::radians(FRAC_PI_2)
            .signed()
            .approx_eq(&Angle::frac_pi_2())
    );
    assert!(
        Angle::radians(3.0 * FRAC_PI_2)
            .signed()
            .approx_eq(&-Angle::frac_pi_2())
    );
    assert!(
        Angle::radians(5.0 * FRAC_PI_2)
            .signed()
            .approx_eq(&Angle::frac_pi_2())
    );
    assert!(Angle::radians(2.0 * PI).signed().approx_eq(&Angle::zero()));
    assert!(Angle::radians(-2.0 * PI).signed().approx_eq(&Angle::zero()));
    assert!(Angle::radians(-PI).signed().approx_eq(&Angle::pi()));
    assert!(Angle::radians(PI).signed().approx_eq(&Angle::pi()));
}

#[test]
fn lerp() {
    type A = Angle<f32>;

    let a = A::radians(1.0);
    let b = A::radians(2.0);
    assert!(a.lerp(b, 0.25).approx_eq(&Angle::radians(1.25)));
    assert!(a.lerp(b, 0.5).approx_eq(&Angle::radians(1.5)));
    assert!(a.lerp(b, 0.75).approx_eq(&Angle::radians(1.75)));
    assert!(a.lerp(b + A::two_pi(), 0.75).approx_eq(&Angle::radians(1.75)));
    assert!(a.lerp(b - A::two_pi(), 0.75).approx_eq(&Angle::radians(1.75)));
    assert!(a.lerp(b + A::two_pi() * 5.0, 0.75).approx_eq(&Angle::radians(1.75)));
}
<|endoftext|>