<commit_before>use std::collections;
use std::fmt;
use std::error::Error as ErrorTrait;

use rustc_serialize::json;
use rustc_serialize::json::ToJson;

use hyper::header;

use url;

use iron::prelude::*;
use iron::modifiers::Header;
use iron::status;

use urlencoded;

// FIXME: oauth module should not be concerned with serialization
#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct OauthRequest {
    pub session: Session,
    pub state: Option<String>,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct Session {
    pub client_id: String,
    pub uri: url::Url,
    pub permissions: collections::HashMap<String, CategoryPermissions>
}

impl Session {
    pub fn permissions_for_category(&self, category: &str) -> Option<&CategoryPermissions> {
        match self.permissions.get(category) {
            Some(x) => Some(x),
            None => self.permissions.get("")
        }
    }

    pub fn identifier(&self) -> String {
        match self.uri.origin() {
            url::Origin::Tuple(scheme, host, port) => format!("{}://{}:{}", scheme, host, port),
            _ => panic!("Invalid URL: {:?}", self.uri)
        }
    }
}

impl ToJson for Session {
    fn to_json(&self) -> json::Json {
        json::Json::Object({
            let mut rv = collections::BTreeMap::new();
            rv.insert("client_id".to_owned(), self.client_id.to_json());
            rv.insert("uri".to_owned(), self.uri.serialize().to_json());
            rv.insert("permissions".to_owned(), self.permissions.to_json());
            rv
        })
    }
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone, Copy)]
pub struct CategoryPermissions {
    pub can_read: bool,
    pub can_write: bool
}

impl ToJson for CategoryPermissions {
    // ToJson for passing to template
    fn to_json(&self) -> json::Json {
        json::Json::Object({
            let mut rv = collections::BTreeMap::new();
            rv.insert("can_read".to_owned(), self.can_read.to_json());
            rv.insert("can_write".to_owned(), self.can_write.to_json());
            rv
        })
    }
}

impl ToJson for OauthRequest {
    // ToJson for passing to template
    fn to_json(&self) -> json::Json {
        self.session.to_json()
    }
}

fn expect_param(query: &urlencoded::QueryMap, key: &str) -> Result<String, Error> {
    match query.get(key) {
        Some(x) if x.len() == 1 => Ok(x[0].clone()),
        _ => Err({
            let mut rv = Error::new(ErrorKind::InvalidRequest);
            rv.msg = Some(format!("Missing query parameter: {:?}", key));
            rv
        })
    }
}

impl OauthRequest {
    pub fn from_http(request: &mut Request) -> Result<Self, Error> {
        let query = match request.get_ref::<urlencoded::UrlEncodedQuery>().ok() {
            Some(x) => x,
            None => return Err({
                let mut e = Error::new(ErrorKind::InvalidRequest);
                e.msg = Some("No query parameters.".to_owned());
                e
            })
        };

        let mut rv = OauthRequest {
            session: Session {
                client_id: "".to_owned(),
                uri: match url::Url::parse(&try!(expect_param(query, "redirect_uri"))[..]) {
                    Ok(x) => x,
                    Err(e) => return Err({
                        let mut ne = Error::new(ErrorKind::InvalidRequest);
                        ne.msg = Some(format!("{}", e));
                        ne
                    })
                },
                permissions: collections::HashMap::new()
            },
            state: expect_param(query, "state").ok()
        };

        rv.session.client_id = match expect_param(query, "client_id") {
            Ok(x) => x,
            Err(mut e) => {
                e.request = Some(rv);
                return Err(e);
            }
        };

        let scope = match expect_param(query, "scope") {
            Ok(x) => x,
            Err(mut e) => {
                e.request = Some(rv);
                return Err(e);
            }
        };

        let scope_err = |x| { Err({
            let mut e = Error::new(ErrorKind::InvalidScope);
            e.msg = Some("Invalid scope.".to_owned());
            e.request = Some(x);
            e
        }) };

        for category_permission in scope.split(' ') {
            let parts = category_permission.split(':').collect::<Vec<_>>();
            if parts.len() != 2 { return scope_err(rv); }

            let (category, permission) = (parts[0], parts[1]);
            if category.len() == 0 || permission.len() == 0 { return scope_err(rv); }

            let key = (if category == "*" { "" } else { category }).to_owned();
            if rv.session.permissions.get(&key).is_some() { return scope_err(rv); }

            rv.session.permissions.insert(key, CategoryPermissions {
                can_read: permission.contains("r"),
                can_write: permission.contains("w")
            });
        }

        Ok(rv)
    }

    pub fn grant(self, token: String) -> Grant {
        Grant { request: self, token: token }
    }

    pub fn reject(self) -> Error {
        let mut e = Error::new(ErrorKind::AccessDenied);
        e.request = Some(self);
        e
    }
}

pub struct Grant {
    pub request: OauthRequest,
    pub token: String
}

impl HttpResponder for Grant {
    fn get_redirect_uri(&self) -> Option<url::Url> {
        Some(self.request.session.uri.clone())
    }

    fn get_redirect_uri_params(&self) -> collections::BTreeMap<String, String> {
        let mut rv = collections::BTreeMap::new();
        rv.insert("access_token".to_owned(), self.token.clone());
        self.request.state.as_ref().map(|x| rv.insert("state".to_owned(), x.clone()));
        rv
    }
}

#[derive(Debug)]
pub struct Error {
    pub kind: ErrorKind,
    pub request: Option<OauthRequest>,
    pub error_uri: Option<url::Url>,
    pub msg: Option<String>
}

impl Error {
    pub fn new(kind: ErrorKind) -> Self {
        Error {
            kind: kind,
            request: None,
            error_uri: None,
            msg: None
        }
    }
}

#[derive(Debug)]
#[allow(dead_code)]
pub enum ErrorKind {
    InvalidRequest,
    UnauthorizedClient,
    AccessDenied,
    UnsupportedResponseType,
    InvalidScope,
    ServerError,
    TemporarilyUnavailable
}

impl ErrorKind {
    fn as_snake_case(&self) -> &str {
        match *self {
            ErrorKind::InvalidRequest => "invalid_request",
            ErrorKind::UnauthorizedClient => "unauthorized_client",
            ErrorKind::AccessDenied => "access_denied",
            ErrorKind::UnsupportedResponseType => "unsupported_response_type",
            ErrorKind::InvalidScope => "invalid_scope",
            ErrorKind::ServerError => "server_error",
            ErrorKind::TemporarilyUnavailable => "temporarily_unavailable"
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.description().fmt(f) }
}

impl ErrorTrait for Error {
    fn description(&self) -> &str {
        match self.msg {
            Some(ref x) => x,
            None => self.kind.as_snake_case()
        }
    }
    fn cause(&self) -> Option<&ErrorTrait> { None }
}

pub trait HttpResponder {
    fn get_redirect_uri(&self) -> Option<url::Url>;
    fn get_redirect_uri_params(&self) -> collections::BTreeMap<String, String>;

    fn get_response(&self) -> Option<Response> {
        self.get_redirect_uri()
            .map(|mut uri| {
                uri.fragment = Some(url::form_urlencoded::serialize(self.get_redirect_uri_params()));
                Response::with(status::Found)
                 // Do not use Redirect modifier here, we need to handle custom URI schemes as well
                 .set(Header(header::Location(uri.serialize())))
            })
    }
}

impl HttpResponder for Error {
    fn get_redirect_uri(&self) -> Option<url::Url> {
        self.request.as_ref().map(|req| req.session.uri.clone())
    }

    fn get_redirect_uri_params(&self) -> collections::BTreeMap<String, String> {
        let mut rv = collections::BTreeMap::new();
        rv.insert("error".to_owned(), self.kind.as_snake_case().to_owned());
        self.msg.as_ref().map(|x| rv.insert("error_description".to_owned(), x.clone()));
        self.request.as_ref().map(|req| req.state.as_ref().map(|state| rv.insert("state".to_owned(), state.clone())));
        rv
    }
}
<commit_msg>better origin formatting<commit_after>use std::collections;
use std::fmt;
use std::error::Error as ErrorTrait;

use rustc_serialize::json;
use rustc_serialize::json::ToJson;

use hyper::header;

use url;

use iron::prelude::*;
use iron::modifiers::Header;
use iron::status;

use urlencoded;

// FIXME: oauth module should not be concerned with serialization
#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct OauthRequest {
    pub session: Session,
    pub state: Option<String>,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct Session {
    pub client_id: String,
    pub uri: url::Url,
    pub permissions: collections::HashMap<String, CategoryPermissions>
}

impl Session {
    pub fn permissions_for_category(&self, category: &str) -> Option<&CategoryPermissions> {
        match self.permissions.get(category) {
            Some(x) => Some(x),
            None => self.permissions.get("")
        }
    }

    pub fn identifier(&self) -> String {
        // FIXME: Ugly
        match self.uri.origin() {
            url::Origin::Tuple(scheme, host, port) => url::Url::parse(
                format!("{}://{}:{}", scheme, host, port)
            ).serialize(),
            _ => panic!("Invalid URL: {:?}", self.uri)
        }
    }
}

impl ToJson for Session {
    fn to_json(&self) -> json::Json {
        json::Json::Object({
            let mut rv = collections::BTreeMap::new();
            rv.insert("client_id".to_owned(), self.client_id.to_json());
            rv.insert("uri".to_owned(), self.uri.serialize().to_json());
            rv.insert("permissions".to_owned(), self.permissions.to_json());
            rv
        })
    }
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone, Copy)]
pub struct CategoryPermissions {
    pub can_read: bool,
    pub can_write: bool
}

impl ToJson for CategoryPermissions {
    // ToJson for passing to template
    fn to_json(&self) -> json::Json {
        json::Json::Object({
            let mut rv = collections::BTreeMap::new();
            rv.insert("can_read".to_owned(), self.can_read.to_json());
            rv.insert("can_write".to_owned(), self.can_write.to_json());
            rv
        })
    }
}

impl ToJson for OauthRequest {
    // ToJson for passing to template
    fn to_json(&self) -> json::Json {
        self.session.to_json()
    }
}

fn expect_param(query: &urlencoded::QueryMap, key: &str) -> Result<String, Error> {
    match query.get(key) {
        Some(x) if x.len() == 1 => Ok(x[0].clone()),
        _ => Err({
            let mut rv = Error::new(ErrorKind::InvalidRequest);
            rv.msg = Some(format!("Missing query parameter: {:?}", key));
            rv
        })
    }
}

impl OauthRequest {
    pub fn from_http(request: &mut Request) -> Result<Self, Error> {
        let query = match request.get_ref::<urlencoded::UrlEncodedQuery>().ok() {
            Some(x) => x,
            None => return Err({
                let mut e = Error::new(ErrorKind::InvalidRequest);
                e.msg = Some("No query parameters.".to_owned());
                e
            })
        };

        let mut rv = OauthRequest {
            session: Session {
                client_id: "".to_owned(),
                uri: match url::Url::parse(&try!(expect_param(query, "redirect_uri"))[..]) {
                    Ok(x) => x,
                    Err(e) => return Err({
                        let mut ne = Error::new(ErrorKind::InvalidRequest);
                        ne.msg = Some(format!("{}", e));
                        ne
                    })
                },
                permissions: collections::HashMap::new()
            },
            state: expect_param(query, "state").ok()
        };

        rv.session.client_id = match expect_param(query, "client_id") {
            Ok(x) => x,
            Err(mut e) => {
                e.request = Some(rv);
                return Err(e);
            }
        };

        let scope = match expect_param(query, "scope") {
            Ok(x) => x,
            Err(mut e) => {
                e.request = Some(rv);
                return Err(e);
            }
        };

        let scope_err = |x| { Err({
            let mut e = Error::new(ErrorKind::InvalidScope);
            e.msg = Some("Invalid scope.".to_owned());
            e.request = Some(x);
            e
        }) };

        for category_permission in scope.split(' ') {
            let parts = category_permission.split(':').collect::<Vec<_>>();
            if parts.len() != 2 { return scope_err(rv); }

            let (category, permission) = (parts[0], parts[1]);
            if category.len() == 0 || permission.len() == 0 { return scope_err(rv); }

            let key = (if category == "*" { "" } else { category }).to_owned();
            if rv.session.permissions.get(&key).is_some() { return scope_err(rv); }

            rv.session.permissions.insert(key, CategoryPermissions {
                can_read: permission.contains("r"),
                can_write: permission.contains("w")
            });
        }

        Ok(rv)
    }

    pub fn grant(self, token: String) -> Grant {
        Grant { request: self, token: token }
    }

    pub fn reject(self) -> Error {
        let mut e = Error::new(ErrorKind::AccessDenied);
        e.request = Some(self);
        e
    }
}

pub struct Grant {
    pub request: OauthRequest,
    pub token: String
}

impl HttpResponder for Grant {
    fn get_redirect_uri(&self) -> Option<url::Url> {
        Some(self.request.session.uri.clone())
    }

    fn get_redirect_uri_params(&self) -> collections::BTreeMap<String, String> {
        let mut rv = collections::BTreeMap::new();
        rv.insert("access_token".to_owned(), self.token.clone());
        self.request.state.as_ref().map(|x| rv.insert("state".to_owned(), x.clone()));
        rv
    }
}

#[derive(Debug)]
pub struct Error {
    pub kind: ErrorKind,
    pub request: Option<OauthRequest>,
    pub error_uri: Option<url::Url>,
    pub msg: Option<String>
}

impl Error {
    pub fn new(kind: ErrorKind) -> Self {
        Error {
            kind: kind,
            request: None,
            error_uri: None,
            msg: None
        }
    }
}

#[derive(Debug)]
#[allow(dead_code)]
pub enum ErrorKind {
    InvalidRequest,
    UnauthorizedClient,
    AccessDenied,
    UnsupportedResponseType,
    InvalidScope,
    ServerError,
    TemporarilyUnavailable
}

impl ErrorKind {
    fn as_snake_case(&self) -> &str {
        match *self {
            ErrorKind::InvalidRequest => "invalid_request",
            ErrorKind::UnauthorizedClient => "unauthorized_client",
            ErrorKind::AccessDenied => "access_denied",
            ErrorKind::UnsupportedResponseType => "unsupported_response_type",
            ErrorKind::InvalidScope => "invalid_scope",
            ErrorKind::ServerError => "server_error",
            ErrorKind::TemporarilyUnavailable => "temporarily_unavailable"
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.description().fmt(f) }
}

impl ErrorTrait for Error {
    fn description(&self) -> &str {
        match self.msg {
            Some(ref x) => x,
            None => self.kind.as_snake_case()
        }
    }
    fn cause(&self) -> Option<&ErrorTrait> { None }
}

pub trait HttpResponder {
    fn get_redirect_uri(&self) -> Option<url::Url>;
    fn get_redirect_uri_params(&self) -> collections::BTreeMap<String, String>;

    fn get_response(&self) -> Option<Response> {
        self.get_redirect_uri()
            .map(|mut uri| {
                uri.fragment = Some(url::form_urlencoded::serialize(self.get_redirect_uri_params()));
                Response::with(status::Found)
                 // Do not use Redirect modifier here, we need to handle custom URI schemes as well
                 .set(Header(header::Location(uri.serialize())))
            })
    }
}

impl HttpResponder for Error {
    fn get_redirect_uri(&self) -> Option<url::Url> {
        self.request.as_ref().map(|req| req.session.uri.clone())
    }

    fn get_redirect_uri_params(&self) -> collections::BTreeMap<String, String> {
        let mut rv = collections::BTreeMap::new();
        rv.insert("error".to_owned(), self.kind.as_snake_case().to_owned());
        self.msg.as_ref().map(|x| rv.insert("error_description".to_owned(), x.clone()));
        self.request.as_ref().map(|req| req.state.as_ref().map(|state| rv.insert("state".to_owned(), state.clone())));
        rv
    }
}
<|endoftext|>


<commit_before>
// Copyright 2017 The gltf Library Developers
//
// 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 std::slice;
use {camera, json, mesh, skin, Gltf};

///  A node in the node hierarchy. When the node contains `skin`, all
/// `mesh.primitives` must contain `JOINTS_0` and `WEIGHTS_0` attributes. A node can
/// have either a `matrix` or any combination of `translation`/`rotation`/`scale`
/// (TRS) properties. TRS properties are converted to matrices and postmultiplied in
/// the `T * R * S` order to compose the transformation matrix; first the scale is
/// applied to the vertices, then the rotation, and then the translation. If none are
/// provided, the transform is the identity. When a node is targeted for animation
/// (referenced by an animation.channel.target), only TRS properties may be present;
/// `matrix` will not be present.
#[derive(Clone, Debug)]
pub struct Node<'a> {
    /// The parent `Gltf` struct.
    gltf: &'a Gltf,

    /// The corresponding JSON index.
    index: usize,

    /// The corresponding JSON struct.
    json: &'a json::scene::Node,
}

/// The root `Node`s of a scene.
#[derive(Clone, Debug)]
pub struct Scene<'a> {
    /// The parent `Gltf` struct.
    #[allow(dead_code)]
    gltf: &'a Gltf,

    /// The corresponding JSON index.
    index: usize,

    /// The corresponding JSON struct.
    json: &'a json::scene::Scene,
}

/// An `Iterator` that visits the nodes in a scene.
#[derive(Clone, Debug)]
pub struct Nodes<'a> {
    /// The parent `Gltf` struct.
    gltf: &'a Gltf,

    /// The internal node index iterIterator.
    iter: slice::Iter<'a, json::Index<json::scene::Node>>,
}

/// An `Iterator` that visits the children of a node.
#[derive(Clone, Debug)]
pub struct Children<'a> {
    /// The parent `Node` struct.
    parent: &'a Node<'a>,

    /// The internal node index iterIterator.
    iter: slice::Iter<'a, json::Index<json::scene::Node>>,
}

impl<'a> Node<'a> {
    /// Constructs a `Node`.
    pub fn new(gltf: &'a Gltf, index: usize, json: &'a json::scene::Node) -> Self {
        Self {
            gltf: gltf,
            index: index,
            json: json,
        }
    }

    /// Returns the internal JSON index.
    pub fn index(&self) -> usize {
        self.index
    }

    /// Returns the internal JSON item.
    pub fn as_json(&self) ->  &json::scene::Node {
        self.json
    }

    /// The camera referenced by this node.
    pub fn camera(&self) -> Option<camera::Camera> {
        self.json.camera.as_ref().map(|index| {
            self.gltf.cameras().nth(index.value()).unwrap()
        })
    }

    /// Returns an `Iterator` that visits the node's children.
    pub fn children(&'a self) -> Children<'a> {
        Children {
            parent: self,
            iter: self.json.children.as_ref().map_or([].iter(), |x| x.iter()),
        }
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras {
        &self.json.extras
    }

    /// 4x4 column-major transformation matrix.
    pub fn matrix(&self) -> [f32; 16] {
        self.json.matrix
    }

    /// The mesh in this node.
    pub fn mesh(&self) -> Option<mesh::Mesh<'a>> {
        self.json.mesh.as_ref().map(|index| {
            self.gltf.meshes().nth(index.value()).unwrap()
        })
    }

    /// Optional user-defined name for this object.
    #[cfg(feature = "names")]
    pub fn name(&self) -> Option<&str> {
        self.json.name.as_ref().map(String::as_str)
    }

    /// The node's unit quaternion rotation in the order (x, y, z, w), where w is
    /// the scalar.
    pub fn rotation(&self) -> [f32; 4] {
        self.json.rotation.0
    }

    /// The node's non-uniform scale.
    pub fn scale(&self) -> [f32; 3] {
        self.json.scale
    }

    /// The node's translation.
    pub fn translation(&self) -> [f32; 3] {
        self.json.translation
    }

    /// The skin referenced by this node.
    pub fn skin(&self) -> Option<skin::Skin<'a>> {
        self.json.skin.as_ref().map(|index| {
            self.gltf.skins().nth(index.value()).unwrap()
        })
    }

    /// The weights of the instantiated Morph Target. Number of elements must match
    /// number of Morph Targets of used mesh.
    pub fn weights(&self) -> Option<&[f32]> {
        self.json.weights.as_ref().map(Vec::as_slice)
    }
}

impl<'a> Scene<'a> {
    /// Constructs a `Scene`.
    pub fn new(gltf: &'a Gltf, index: usize, json: &'a json::scene::Scene) -> Self {
        Self {
            gltf: gltf,
            index: index,
            json: json,
        }
    }

    /// Returns the internal JSON index.
    pub fn index(&self) -> usize {
        self.index
    }

    /// Returns the internal JSON item.
    pub fn as_json(&self) ->  &json::scene::Scene {
        self.json
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras{
        &self.json.extras
    }

    /// Optional user-defined name for this object.
    #[cfg(feature = "names")]
    pub fn name(&self) -> Option<&str> {
        self.json.name.as_ref().map(String::as_str)
    }

    /// The indices of each root node.
    pub fn nodes(&self) -> Nodes<'a> {
        Nodes {
            gltf: self.gltf,
            iter: self.json.nodes.iter(),
        }
    }
}

impl<'a> ExactSizeIterator for Nodes<'a> {}
impl<'a> Iterator for Nodes<'a> {
    type Item = Node<'a>;
    fn next(&mut self) -> Option<Self::Item> {
        self.iter
            .next()
            .map(|index| self.gltf.nodes().nth(index.value()).unwrap())
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

impl<'a> ExactSizeIterator for Children<'a> {}
impl<'a> Iterator for Children<'a> {
    type Item = Node<'a>;
    fn next(&mut self) -> Option<Self::Item> {
        self.iter
            .next()
            .map(|index| self.parent.gltf.nodes().nth(index.value()).unwrap())
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}
<commit_msg>Add loaded iterators to scene module<commit_after>
// Copyright 2017 The gltf Library Developers
//
// 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 json;
use std::slice;

use {Camera, Gltf, Loaded, Mesh, Skin};

///  A node in the node hierarchy. When the node contains `skin`, all
/// `mesh.primitives` must contain `JOINTS_0` and `WEIGHTS_0` attributes. A node can
/// have either a `matrix` or any combination of `translation`/`rotation`/`scale`
/// (TRS) properties. TRS properties are converted to matrices and postmultiplied in
/// the `T * R * S` order to compose the transformation matrix; first the scale is
/// applied to the vertices, then the rotation, and then the translation. If none are
/// provided, the transform is the identity. When a node is targeted for animation
/// (referenced by an animation.channel.target), only TRS properties may be present;
/// `matrix` will not be present.
#[derive(Clone, Debug)]
pub struct Node<'a> {
    /// The parent `Gltf` struct.
    gltf: &'a Gltf,

    /// The corresponding JSON index.
    index: usize,

    /// The corresponding JSON struct.
    json: &'a json::scene::Node,
}

/// The root `Node`s of a scene.
#[derive(Clone, Debug)]
pub struct Scene<'a> {
    /// The parent `Gltf` struct.
    #[allow(dead_code)]
    gltf: &'a Gltf,

    /// The corresponding JSON index.
    index: usize,

    /// The corresponding JSON struct.
    json: &'a json::scene::Scene,
}

/// An `Iterator` that visits the nodes in a scene.
#[derive(Clone, Debug)]
pub struct Nodes<'a> {
    /// The parent `Gltf` struct.
    gltf: &'a Gltf,

    /// The internal node index iterIterator.
    iter: slice::Iter<'a, json::Index<json::scene::Node>>,
}

/// An `Iterator` that visits the children of a node.
#[derive(Clone, Debug)]
pub struct Children<'a> {
    /// The parent `Node` struct.
    parent: &'a Node<'a>,

    /// The internal node index iterIterator.
    iter: slice::Iter<'a, json::Index<json::scene::Node>>,
}

impl<'a> Node<'a> {
    /// Constructs a `Node`.
    pub fn new(gltf: &'a Gltf, index: usize, json: &'a json::scene::Node) -> Self {
        Self {
            gltf: gltf,
            index: index,
            json: json,
        }
    }

    /// Returns the internal JSON index.
    pub fn index(&self) -> usize {
        self.index
    }

    /// Returns the internal JSON item.
    pub fn as_json(&self) ->  &json::scene::Node {
        self.json
    }

    /// Returns the camera referenced by this node.
    pub fn camera(&self) -> Option<Camera<'a>> {
        self.json.camera.as_ref().map(|index| {
            self.gltf.cameras().nth(index.value()).unwrap()
        })
    }

    /// Returns an `Iterator` that visits the node's children.
    pub fn children(&'a self) -> Children<'a> {
        Children {
            parent: self,
            iter: self.json.children.as_ref().map_or([].iter(), |x| x.iter()),
        }
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras {
        &self.json.extras
    }

    /// Returns the 4x4 column-major transformation matrix.
    pub fn matrix(&self) -> [f32; 16] {
        self.json.matrix
    }

    /// Returns the mesh referenced by this node.
    pub fn mesh(&self) -> Option<Mesh<'a>> {
        self.json.mesh.as_ref().map(|index| {
            self.gltf.meshes().nth(index.value()).unwrap()
        })
    }

    /// Optional user-defined name for this object.
    #[cfg(feature = "names")]
    pub fn name(&self) -> Option<&str> {
        self.json.name.as_ref().map(String::as_str)
    }

    /// Returns the node's unit quaternion rotation in the order `[x, y, z, w]`,
    /// where `w` is the scalar.
    pub fn rotation(&self) -> [f32; 4] {
        self.json.rotation.0
    }

    /// Returns the node's non-uniform scale.
    pub fn scale(&self) -> [f32; 3] {
        self.json.scale
    }

    /// Returns the node's translation.
    pub fn translation(&self) -> [f32; 3] {
        self.json.translation
    }

    /// Returns the skin referenced by this node.
    pub fn skin(&self) -> Option<Skin<'a>> {
        self.json.skin.as_ref().map(|index| {
            self.gltf.skins().nth(index.value()).unwrap()
        })
    }

    /// Returns the weights of the instantiated morph target.
    pub fn weights(&self) -> Option<&[f32]> {
        self.json.weights.as_ref().map(Vec::as_slice)
    }
}

impl<'a> Scene<'a> {
    /// Constructs a `Scene`.
    pub fn new(gltf: &'a Gltf, index: usize, json: &'a json::scene::Scene) -> Self {
        Self {
            gltf: gltf,
            index: index,
            json: json,
        }
    }

    /// Returns the internal JSON index.
    pub fn index(&self) -> usize {
        self.index
    }

    /// Returns the internal JSON item.
    pub fn as_json(&self) ->  &json::scene::Scene {
        self.json
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras{
        &self.json.extras
    }

    /// Optional user-defined name for this object.
    #[cfg(feature = "names")]
    pub fn name(&self) -> Option<&str> {
        self.json.name.as_ref().map(String::as_str)
    }

    /// Returns an `Iterator` that visits each root node of the scene.
    pub fn nodes(&self) -> Nodes<'a> {
        Nodes {
            gltf: self.gltf,
            iter: self.json.nodes.iter(),
        }
    }
}

impl<'a> Loaded<'a, Node<'a>> {
    /// Returns the camera referenced by this node.
    pub fn camera(&'a self) -> Option<Loaded<'a, Camera<'a>>> {
        self.item.camera().map(|item| {
            Loaded {
                item,
                source: self.source,
            }
        })
    }

    /// Returns an `Iterator` that visits the node's children.
    pub fn children(&'a self) -> Loaded<'a, Children<'a>> {
        Loaded {
            item: self.item.children(),
            source: self.source,
        }
    }

    /// Returns the mesh referenced by this node.
    pub fn mesh(&'a self) -> Option<Loaded<'a, Mesh<'a>>> {
        self.item.mesh().map(|item| {
            Loaded {
                item,
                source: self.source,
            }
        })
    }

    /// Returns the skin referenced by this node.
    pub fn skin(&self) -> Option<Loaded<'a, Skin<'a>>> {
        self.item.skin().map(|item| {
            Loaded {
                item,
                source: self.source,
            }
        })
    }
}

impl<'a> Loaded<'a, Scene<'a>> {
    /// Returns an `Iterator` that visits each root node of the scene.
    pub fn nodes(&'a self) -> Loaded<'a, Nodes<'a>> {
        Loaded {
            item: self.item.nodes(),
            source: self.source,
        }
    }
}

impl<'a> ExactSizeIterator for Nodes<'a> {}
impl<'a> Iterator for Nodes<'a> {
    type Item = Node<'a>;
    fn next(&mut self) -> Option<Self::Item> {
        self.iter
            .next()
            .map(|index| self.gltf.nodes().nth(index.value()).unwrap())
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

impl<'a> ExactSizeIterator for Loaded<'a, Nodes<'a>> {}
impl<'a> Iterator for Loaded<'a, Nodes<'a>> {
    type Item = Loaded<'a, Node<'a>>;
    fn next(&mut self) -> Option<Self::Item> {
        self.item.next().map(|item| {
            Loaded {
                item,
                source: self.source,
            }
        })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.item.size_hint()
    }
}

impl<'a> ExactSizeIterator for Children<'a> {}
impl<'a> Iterator for Children<'a> {
    type Item = Node<'a>;
    fn next(&mut self) -> Option<Self::Item> {
        self.iter
            .next()
            .map(|index| self.parent.gltf.nodes().nth(index.value()).unwrap())
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

impl<'a> ExactSizeIterator for Loaded<'a, Children<'a>> {}
impl<'a> Iterator for Loaded<'a, Children<'a>> {
    type Item = Loaded<'a, Node<'a>>;
    fn next(&mut self) -> Option<Self::Item> {
        self.item.next().map(|item| {
            Loaded {
                item,
                source: self.source,
            }
        })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.item.size_hint()
    }
}

<|endoftext|>


<commit_before>use std::mem;

#[allow(dead_code)]
#[derive(Clone, Copy)]
struct Point {
    x: f64,
    y: f64,
}

#[allow(dead_code)]
struct Rectangle {
    p1: Point,
    p2: Point,
}

fn origin() -> Point {
    Point { x: 0.0, y: 0.0 }
}

fn boxed_origin() -> Box<Point> {
    // Allocate this point in the heap, and return a pointer to it
    Box::new(Point { x: 0.0, y: 0.0 })
}

fn main() {
    // (all the type annotations are superfluous)
    // Stack allocated variables
    let point: Point = origin();
    let rectangle: Rectangle = Rectangle {
        p1: origin(),
        p2: Point { x: 3.0, y: 4.0 }
    };

    // Heap allocated rectangle
    let boxed_rectangle: Box<Rectangle> = Box::new(Rectangle {
        p1: origin(),
        p2: origin()
    });

    // The output of functions can be boxed
    let boxed_point: Box<Point> = Box::new(origin());

    // Double indirection
    let box_in_a_box: Box<Box<Point>> = Box::new(boxed_origin());

    println!("Point occupies {} bytes in the stack",
             mem::size_of_val(&point));
    println!("Rectangle occupies {} bytes in the stack",
             mem::size_of_val(&rectangle));

    // box size = pointer size
    println!("Boxed point occupies {} bytes in the stack",
             mem::size_of_val(&boxed_point));
    println!("Boxed rectangle occupies {} bytes in the stack",
             mem::size_of_val(&boxed_rectangle));
    println!("Boxed box occupies {} bytes in the stack",
             mem::size_of_val(&box_in_a_box));

    // Copy the data contained in `boxed_point` into `unboxed_point`
    let unboxed_point: Point = *boxed_point;
    println!("Unboxed point occupies {} bytes in the stack",
             mem::size_of_val(&unboxed_point));
}
<commit_msg>std::box: remove a lint that is not needed<commit_after>use std::mem;

#[derive(Clone, Copy)]
struct Point {
    x: f64,
    y: f64,
}

#[allow(dead_code)]
struct Rectangle {
    p1: Point,
    p2: Point,
}

fn origin() -> Point {
    Point { x: 0.0, y: 0.0 }
}

fn boxed_origin() -> Box<Point> {
    // Allocate this point in the heap, and return a pointer to it
    Box::new(Point { x: 0.0, y: 0.0 })
}

fn main() {
    // (all the type annotations are superfluous)
    // Stack allocated variables
    let point: Point = origin();
    let rectangle: Rectangle = Rectangle {
        p1: origin(),
        p2: Point { x: 3.0, y: 4.0 }
    };

    // Heap allocated rectangle
    let boxed_rectangle: Box<Rectangle> = Box::new(Rectangle {
        p1: origin(),
        p2: origin()
    });

    // The output of functions can be boxed
    let boxed_point: Box<Point> = Box::new(origin());

    // Double indirection
    let box_in_a_box: Box<Box<Point>> = Box::new(boxed_origin());

    println!("Point occupies {} bytes in the stack",
             mem::size_of_val(&point));
    println!("Rectangle occupies {} bytes in the stack",
             mem::size_of_val(&rectangle));

    // box size = pointer size
    println!("Boxed point occupies {} bytes in the stack",
             mem::size_of_val(&boxed_point));
    println!("Boxed rectangle occupies {} bytes in the stack",
             mem::size_of_val(&boxed_rectangle));
    println!("Boxed box occupies {} bytes in the stack",
             mem::size_of_val(&box_in_a_box));

    // Copy the data contained in `boxed_point` into `unboxed_point`
    let unboxed_point: Point = *boxed_point;
    println!("Unboxed point occupies {} bytes in the stack",
             mem::size_of_val(&unboxed_point));
}
<|endoftext|>


<commit_before>use rustc_hash::FxHashSet;

use ra_syntax::{
    ast, AstNode, Direction, SourceFile, SyntaxNode, TextRange,
    SyntaxKind::{self, *},
};

#[derive(Debug, PartialEq, Eq)]
pub enum FoldKind {
    Comment,
    Imports,
    Mods,
    Block,
}

#[derive(Debug)]
pub struct Fold {
    pub range: TextRange,
    pub kind: FoldKind,
}

pub fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
    let mut res = vec![];
    let mut visited_comments = FxHashSet::default();
    let mut visited_imports = FxHashSet::default();
    let mut visited_mods = FxHashSet::default();

    for node in file.syntax().descendants() {
        // Fold items that span multiple lines
        if let Some(kind) = fold_kind(node.kind()) {
            if has_newline(node) {
                res.push(Fold {
                    range: node.range(),
                    kind,
                });
            }
        }

        // Fold groups of comments
        if node.kind() == COMMENT && !visited_comments.contains(&node) {
            if let Some(range) = contiguous_range_for_comment(node, &mut visited_comments) {
                res.push(Fold {
                    range,
                    kind: FoldKind::Comment,
                })
            }
        }

        // Fold groups of imports
        if node.kind() == USE_ITEM && !visited_imports.contains(&node) {
            if let Some(range) = contiguous_range_for_group(node, &mut visited_imports) {
                res.push(Fold {
                    range,
                    kind: FoldKind::Imports,
                })
            }
        }

        // Fold groups of mods
        if node.kind() == MODULE && !has_visibility(&node) && !visited_mods.contains(&node) {
            if let Some(range) =
                contiguous_range_for_group_unless(node, has_visibility, &mut visited_mods)
            {
                res.push(Fold {
                    range,
                    kind: FoldKind::Mods,
                })
            }
        }
    }

    res
}

fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
    match kind {
        COMMENT => Some(FoldKind::Comment),
        USE_ITEM => Some(FoldKind::Imports),
        NAMED_FIELD_DEF_LIST | FIELD_PAT_LIST | ITEM_LIST | EXTERN_ITEM_LIST | USE_TREE_LIST
        | BLOCK | ENUM_VARIANT_LIST | TOKEN_TREE => Some(FoldKind::Block),
        _ => None,
    }
}

fn has_visibility(node: &SyntaxNode) -> bool {
    use ast::VisibilityOwner;

    return ast::Module::cast(node)
        .and_then(|m| m.visibility())
        .is_some();
}

fn has_newline(node: &SyntaxNode) -> bool {
    for descendant in node.descendants() {
        if let Some(ws) = ast::Whitespace::cast(descendant) {
            if ws.has_newlines() {
                return true;
            }
        } else if let Some(comment) = ast::Comment::cast(descendant) {
            if comment.has_newlines() {
                return true;
            }
        }
    }

    false
}

fn contiguous_range_for_group<'a>(
    first: &'a SyntaxNode,
    visited: &mut FxHashSet<&'a SyntaxNode>,
) -> Option<TextRange> {
    contiguous_range_for_group_unless(first, |_| false, visited)
}

fn contiguous_range_for_group_unless<'a>(
    first: &'a SyntaxNode,
    unless: impl Fn(&'a SyntaxNode) -> bool,
    visited: &mut FxHashSet<&'a SyntaxNode>,
) -> Option<TextRange> {
    visited.insert(first);

    let mut last = first;
    for node in first.siblings(Direction::Next) {
        if let Some(ws) = ast::Whitespace::cast(node) {
            // There is a blank line, which means that the group ends here
            if ws.count_newlines_lazy().take(2).count() == 2 {
                break;
            }

            // Ignore whitespace without blank lines
            continue;
        }

        // Stop if we find a node that doesn't belong to the group
        if node.kind() != first.kind() || unless(node) {
            break;
        }

        visited.insert(node);
        last = node;
    }

    if first != last {
        Some(TextRange::from_to(
            first.range().start(),
            last.range().end(),
        ))
    } else {
        // The group consists of only one element, therefore it cannot be folded
        None
    }
}

fn contiguous_range_for_comment<'a>(
    first: &'a SyntaxNode,
    visited: &mut FxHashSet<&'a SyntaxNode>,
) -> Option<TextRange> {
    visited.insert(first);

    // Only fold comments of the same flavor
    let group_flavor = ast::Comment::cast(first)?.flavor();

    let mut last = first;
    for node in first.siblings(Direction::Next) {
        if let Some(ws) = ast::Whitespace::cast(node) {
            // There is a blank line, which means the group ends here
            if ws.count_newlines_lazy().take(2).count() == 2 {
                break;
            }

            // Ignore whitespace without blank lines
            continue;
        }

        match ast::Comment::cast(node) {
            Some(next_comment) if next_comment.flavor() == group_flavor => {
                visited.insert(node);
                last = node;
            }
            // The comment group ends because either:
            // * An element of a different kind was reached
            // * A comment of a different flavor was reached
            _ => break,
        }
    }

    if first != last {
        Some(TextRange::from_to(
            first.range().start(),
            last.range().end(),
        ))
    } else {
        // The group consists of only one element, therefore it cannot be folded
        None
    }
}

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

    fn do_check(text: &str, fold_kinds: &[FoldKind]) {
        let (ranges, text) = extract_ranges(text, "fold");
        let file = SourceFile::parse(&text);
        let folds = folding_ranges(&file);

        assert_eq!(
            folds.len(),
            ranges.len(),
            "The amount of folds is different than the expected amount"
        );
        assert_eq!(
            folds.len(),
            fold_kinds.len(),
            "The amount of fold kinds is different than the expected amount"
        );
        for ((fold, range), fold_kind) in folds
            .into_iter()
            .zip(ranges.into_iter())
            .zip(fold_kinds.into_iter())
        {
            assert_eq!(fold.range.start(), range.start());
            assert_eq!(fold.range.end(), range.end());
            assert_eq!(&fold.kind, fold_kind);
        }
    }

    #[test]
    fn test_fold_comments() {
        let text = r#"
<fold>// Hello
// this is a multiline
// comment
//</fold>

// But this is not

fn main() <fold>{
    <fold>// We should
    // also
    // fold
    // this one.</fold>
    <fold>//! But this one is different
    //! because it has another flavor</fold>
    <fold>/* As does this
    multiline comment */</fold>
}</fold>"#;

        let fold_kinds = &[
            FoldKind::Comment,
            FoldKind::Block,
            FoldKind::Comment,
            FoldKind::Comment,
            FoldKind::Comment,
        ];
        do_check(text, fold_kinds);
    }

    #[test]
    fn test_fold_imports() {
        let text = r#"
<fold>use std::<fold>{
    str,
    vec,
    io as iop
}</fold>;</fold>

fn main() <fold>{
}</fold>"#;

        let folds = &[FoldKind::Imports, FoldKind::Block, FoldKind::Block];
        do_check(text, folds);
    }

    #[test]
    fn test_fold_mods() {
        let text = r#"

pub mod foo;
<fold>mod after_pub;
mod after_pub_next;</fold>

<fold>mod before_pub;
mod before_pub_next;</fold>
pub mod bar;

mod not_folding_single;
pub mod foobar;
pub not_folding_single_next;

<fold>#[cfg(test)]
mod with_attribute;
mod with_attribute_next;</fold>

fn main() <fold>{
}</fold>"#;

        let folds = &[
            FoldKind::Mods,
            FoldKind::Mods,
            FoldKind::Mods,
            FoldKind::Block,
        ];
        do_check(text, folds);
    }

    #[test]
    fn test_fold_import_groups() {
        let text = r#"
<fold>use std::str;
use std::vec;
use std::io as iop;</fold>

<fold>use std::mem;
use std::f64;</fold>

use std::collections::HashMap;
// Some random comment
use std::collections::VecDeque;

fn main() <fold>{
}</fold>"#;

        let folds = &[FoldKind::Imports, FoldKind::Imports, FoldKind::Block];
        do_check(text, folds);
    }

    #[test]
    fn test_fold_import_and_groups() {
        let text = r#"
<fold>use std::str;
use std::vec;
use std::io as iop;</fold>

<fold>use std::mem;
use std::f64;</fold>

<fold>use std::collections::<fold>{
    HashMap,
    VecDeque,
}</fold>;</fold>
// Some random comment

fn main() <fold>{
}</fold>"#;

        let folds = &[
            FoldKind::Imports,
            FoldKind::Imports,
            FoldKind::Imports,
            FoldKind::Block,
            FoldKind::Block,
        ];
        do_check(text, folds);
    }

    #[test]
    fn test_folds_macros() {
        let text = r#"
macro_rules! foo <fold>{
    ($($tt:tt)*) => { $($tt)* }
}</fold>
"#;

        let folds = &[FoldKind::Block];
        do_check(text, folds);
    }
}
<commit_msg>minor cleanups<commit_after>use rustc_hash::FxHashSet;

use ra_syntax::{
    AstNode, Direction, SourceFile, SyntaxNode, TextRange,
    SyntaxKind::{self, *},
    ast::{self, VisibilityOwner},
};

#[derive(Debug, PartialEq, Eq)]
pub enum FoldKind {
    Comment,
    Imports,
    Mods,
    Block,
}

#[derive(Debug)]
pub struct Fold {
    pub range: TextRange,
    pub kind: FoldKind,
}

pub fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
    let mut res = vec![];
    let mut visited_comments = FxHashSet::default();
    let mut visited_imports = FxHashSet::default();
    let mut visited_mods = FxHashSet::default();

    for node in file.syntax().descendants() {
        // Fold items that span multiple lines
        if let Some(kind) = fold_kind(node.kind()) {
            if node.text().contains('\n') {
                res.push(Fold {
                    range: node.range(),
                    kind,
                });
            }
        }

        // Fold groups of comments
        if node.kind() == COMMENT && !visited_comments.contains(&node) {
            if let Some(range) = contiguous_range_for_comment(node, &mut visited_comments) {
                res.push(Fold {
                    range,
                    kind: FoldKind::Comment,
                })
            }
        }

        // Fold groups of imports
        if node.kind() == USE_ITEM && !visited_imports.contains(&node) {
            if let Some(range) = contiguous_range_for_group(node, &mut visited_imports) {
                res.push(Fold {
                    range,
                    kind: FoldKind::Imports,
                })
            }
        }

        // Fold groups of mods
        if node.kind() == MODULE && !has_visibility(&node) && !visited_mods.contains(&node) {
            if let Some(range) =
                contiguous_range_for_group_unless(node, has_visibility, &mut visited_mods)
            {
                res.push(Fold {
                    range,
                    kind: FoldKind::Mods,
                })
            }
        }
    }

    res
}

fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
    match kind {
        COMMENT => Some(FoldKind::Comment),
        USE_ITEM => Some(FoldKind::Imports),
        NAMED_FIELD_DEF_LIST | FIELD_PAT_LIST | ITEM_LIST | EXTERN_ITEM_LIST | USE_TREE_LIST
        | BLOCK | ENUM_VARIANT_LIST | TOKEN_TREE => Some(FoldKind::Block),
        _ => None,
    }
}

fn has_visibility(node: &SyntaxNode) -> bool {
    ast::Module::cast(node)
        .and_then(|m| m.visibility())
        .is_some()
}

fn contiguous_range_for_group<'a>(
    first: &'a SyntaxNode,
    visited: &mut FxHashSet<&'a SyntaxNode>,
) -> Option<TextRange> {
    contiguous_range_for_group_unless(first, |_| false, visited)
}

fn contiguous_range_for_group_unless<'a>(
    first: &'a SyntaxNode,
    unless: impl Fn(&'a SyntaxNode) -> bool,
    visited: &mut FxHashSet<&'a SyntaxNode>,
) -> Option<TextRange> {
    visited.insert(first);

    let mut last = first;
    for node in first.siblings(Direction::Next) {
        if let Some(ws) = ast::Whitespace::cast(node) {
            // There is a blank line, which means that the group ends here
            if ws.count_newlines_lazy().take(2).count() == 2 {
                break;
            }

            // Ignore whitespace without blank lines
            continue;
        }

        // Stop if we find a node that doesn't belong to the group
        if node.kind() != first.kind() || unless(node) {
            break;
        }

        visited.insert(node);
        last = node;
    }

    if first != last {
        Some(TextRange::from_to(
            first.range().start(),
            last.range().end(),
        ))
    } else {
        // The group consists of only one element, therefore it cannot be folded
        None
    }
}

fn contiguous_range_for_comment<'a>(
    first: &'a SyntaxNode,
    visited: &mut FxHashSet<&'a SyntaxNode>,
) -> Option<TextRange> {
    visited.insert(first);

    // Only fold comments of the same flavor
    let group_flavor = ast::Comment::cast(first)?.flavor();

    let mut last = first;
    for node in first.siblings(Direction::Next) {
        if let Some(ws) = ast::Whitespace::cast(node) {
            // There is a blank line, which means the group ends here
            if ws.count_newlines_lazy().take(2).count() == 2 {
                break;
            }

            // Ignore whitespace without blank lines
            continue;
        }

        match ast::Comment::cast(node) {
            Some(next_comment) if next_comment.flavor() == group_flavor => {
                visited.insert(node);
                last = node;
            }
            // The comment group ends because either:
            // * An element of a different kind was reached
            // * A comment of a different flavor was reached
            _ => break,
        }
    }

    if first != last {
        Some(TextRange::from_to(
            first.range().start(),
            last.range().end(),
        ))
    } else {
        // The group consists of only one element, therefore it cannot be folded
        None
    }
}

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

    fn do_check(text: &str, fold_kinds: &[FoldKind]) {
        let (ranges, text) = extract_ranges(text, "fold");
        let file = SourceFile::parse(&text);
        let folds = folding_ranges(&file);

        assert_eq!(
            folds.len(),
            ranges.len(),
            "The amount of folds is different than the expected amount"
        );
        assert_eq!(
            folds.len(),
            fold_kinds.len(),
            "The amount of fold kinds is different than the expected amount"
        );
        for ((fold, range), fold_kind) in folds
            .into_iter()
            .zip(ranges.into_iter())
            .zip(fold_kinds.into_iter())
        {
            assert_eq!(fold.range.start(), range.start());
            assert_eq!(fold.range.end(), range.end());
            assert_eq!(&fold.kind, fold_kind);
        }
    }

    #[test]
    fn test_fold_comments() {
        let text = r#"
<fold>// Hello
// this is a multiline
// comment
//</fold>

// But this is not

fn main() <fold>{
    <fold>// We should
    // also
    // fold
    // this one.</fold>
    <fold>//! But this one is different
    //! because it has another flavor</fold>
    <fold>/* As does this
    multiline comment */</fold>
}</fold>"#;

        let fold_kinds = &[
            FoldKind::Comment,
            FoldKind::Block,
            FoldKind::Comment,
            FoldKind::Comment,
            FoldKind::Comment,
        ];
        do_check(text, fold_kinds);
    }

    #[test]
    fn test_fold_imports() {
        let text = r#"
<fold>use std::<fold>{
    str,
    vec,
    io as iop
}</fold>;</fold>

fn main() <fold>{
}</fold>"#;

        let folds = &[FoldKind::Imports, FoldKind::Block, FoldKind::Block];
        do_check(text, folds);
    }

    #[test]
    fn test_fold_mods() {
        let text = r#"

pub mod foo;
<fold>mod after_pub;
mod after_pub_next;</fold>

<fold>mod before_pub;
mod before_pub_next;</fold>
pub mod bar;

mod not_folding_single;
pub mod foobar;
pub not_folding_single_next;

<fold>#[cfg(test)]
mod with_attribute;
mod with_attribute_next;</fold>

fn main() <fold>{
}</fold>"#;

        let folds = &[
            FoldKind::Mods,
            FoldKind::Mods,
            FoldKind::Mods,
            FoldKind::Block,
        ];
        do_check(text, folds);
    }

    #[test]
    fn test_fold_import_groups() {
        let text = r#"
<fold>use std::str;
use std::vec;
use std::io as iop;</fold>

<fold>use std::mem;
use std::f64;</fold>

use std::collections::HashMap;
// Some random comment
use std::collections::VecDeque;

fn main() <fold>{
}</fold>"#;

        let folds = &[FoldKind::Imports, FoldKind::Imports, FoldKind::Block];
        do_check(text, folds);
    }

    #[test]
    fn test_fold_import_and_groups() {
        let text = r#"
<fold>use std::str;
use std::vec;
use std::io as iop;</fold>

<fold>use std::mem;
use std::f64;</fold>

<fold>use std::collections::<fold>{
    HashMap,
    VecDeque,
}</fold>;</fold>
// Some random comment

fn main() <fold>{
}</fold>"#;

        let folds = &[
            FoldKind::Imports,
            FoldKind::Imports,
            FoldKind::Imports,
            FoldKind::Block,
            FoldKind::Block,
        ];
        do_check(text, folds);
    }

    #[test]
    fn test_folds_macros() {
        let text = r#"
macro_rules! foo <fold>{
    ($($tt:tt)*) => { $($tt)* }
}</fold>
"#;

        let folds = &[FoldKind::Block];
        do_check(text, folds);
    }
}
<|endoftext|>


<commit_before>// extern crate libc;

// use libc::types;
use std::io::File;
use std::mem;
use std::os;

// https://stackoverflow.com/questions/24633784/is-there-a-gzip-library-available-for-rust

// #[link(name = "z")]
// extern {
//     fn gzopen(path: *const types::os::arch::c95::c_char,
//               mode: *const types::os::arch::c95::c_char)
//               -> types::common::c95::c_void;
// }

// #[link(name = "z")]
// extern {
//     fn gzread(file: types::common::c95::c_void,
//               buf:  types::common::c95::c_void,
//               len:  uint)
//               -> int;
// }

// #[link(name = "z")]
// extern {
//     fn gzclose(file: types::common::c95::c_void) -> int;
// }

fn pointer_size() -> uint {
    let tmp = 0u8;
    let boxed = box tmp;
    mem::size_of_val(&boxed)
}

fn main() {
    let args = os::args();
    if args.len() != 2 {
        println!("usage: read_blend_file /path/to/file.blend");
    } else {
        let slice: &str = args[1].as_slice();
        println!("open \"{}\" ...", slice);
        {
            // read 12 bytes from the Blender file
            let path = Path::new(slice);
            let display = path.display();
            let mut file = match File::open(&path) {
                Err(why) => fail!("couldn't open {}: {}", display, why.desc),
                Ok(file) => file,
            };
            let mut buf = [0u8, ..12];
            match file.read(buf) {
                Err(why) => fail!("couldn't open {}: {}", display, why.desc),
                Ok(_) => (),
            }
            // pack those 12 bytes into a string ...
            let mut header = String::new();
            for n in range(0u, 12) {
                header.push(buf[n] as char);
            }
            // ... to be able to compare them
            let slice = header.as_slice();
            let blender: &str = slice.slice(0, 7); // first 7 chars
            if blender == "BLENDER" {
                println!("INFO: a Blender file.");
                let ptr_size = pointer_size();
                println!("size of pointer in bytes: {}", ptr_size);
                println!("Header (12 chars): {}", header);
                let mut ptr_size_differs = false;
                if buf[7] as char == '_' {
                    // 32-bit pointers expected
                    if ptr_size != 4 {
                        ptr_size_differs = true;
                    }
                    println!("32-bit pointers in file, pointer size differs? {}", ptr_size_differs);
                } else {
                    // 64-bit pointers expected
                    if ptr_size != 8 {
                        ptr_size_differs = true;
                    }
                    println!("64-bit pointers in file, pointer size differs? {}", ptr_size_differs);
                }
                // little endian or big endian?
                let mut l_endian;
                let endian_test = 1u16; // value one stored in two bytes
                if endian_test.to_le() != endian_test {
                    l_endian = false;
                } else {
                    // if we are on a little endian machine to_le() is a no-op
                    l_endian = true;
                }
                println!("l_endian = {}", l_endian);
                let mut switch_endian;
                if buf[8] as char == 'v' {
                    // file stores little endian
                    if !l_endian {
                        switch_endian = true;
                    } else {
                        switch_endian = false;
                    }
                } else {
                    // file stores big endian
                    if l_endian {
                        switch_endian = true;
                    } else {
                        switch_endian = false;
                    }
                }
                println!("switch_endian = {}", switch_endian);
                // get the version number
                let mut num = String::new();
                for n in range(9u, 12) {
                    num.push(buf[n] as char);
                }
                println!("num = {}", num);
            } else {
                println!("ERROR: not a Blender file.");
            }
        } // file gets closed here
    }
}
<commit_msg>Read all 24 bytes of a BHead8 struct, but use only code (4 chars) and len.<commit_after>// extern crate libc;

// use libc::types;
use std::io::File;
use std::mem;
use std::os;

// https://stackoverflow.com/questions/24633784/is-there-a-gzip-library-available-for-rust

// #[link(name = "z")]
// extern {
//     fn gzopen(path: *const types::os::arch::c95::c_char,
//               mode: *const types::os::arch::c95::c_char)
//               -> types::common::c95::c_void;
// }

// #[link(name = "z")]
// extern {
//     fn gzread(file: types::common::c95::c_void,
//               buf:  types::common::c95::c_void,
//               len:  uint)
//               -> int;
// }

// #[link(name = "z")]
// extern {
//     fn gzclose(file: types::common::c95::c_void) -> int;
// }

fn pointer_size() -> uint {
    let tmp = 0u8;
    let boxed = box tmp;
    mem::size_of_val(&boxed)
}

fn main() {
    let args = os::args();
    if args.len() != 2 {
        println!("usage: read_blend_file /path/to/file.blend");
    } else {
        let slice: &str = args[1].as_slice();
        println!("open \"{}\" ...", slice);
        {
            // read 12 bytes from the Blender file
            let path = Path::new(slice);
            let display = path.display();
            let mut file = match File::open(&path) {
                Err(why) => fail!("couldn't open {}: {}", display, why.desc),
                Ok(file) => file,
            };
            let mut buf = [0u8, ..12];
            match file.read(buf) {
                Err(why) => fail!("couldn't open {}: {}", display, why.desc),
                Ok(_) => (),
            }
            // pack those 12 bytes into a string ...
            let mut header = String::new();
            for n in range(0u, 12) {
                header.push(buf[n] as char);
            }
            // ... to be able to compare them
            let slice = header.as_slice();
            let blender: &str = slice.slice(0, 7); // first 7 chars
            if blender == "BLENDER" {
                println!("INFO: a Blender file.");
                let ptr_size = pointer_size();
                println!("size of pointer in bytes: {}", ptr_size);
                println!("Header (12 chars): {}", header);
                let mut ptr_size_differs = false;
                if buf[7] as char == '_' {
                    // 32-bit pointers expected
                    if ptr_size != 4 {
                        ptr_size_differs = true;
                    }
                    println!("32-bit pointers in file, pointer size differs? {}", ptr_size_differs);
                } else {
                    // 64-bit pointers expected
                    if ptr_size != 8 {
                        ptr_size_differs = true;
                    }
                    println!("64-bit pointers in file, pointer size differs? {}", ptr_size_differs);
                }
                // little endian or big endian?
                let mut l_endian;
                let endian_test = 1u16; // value one stored in two bytes
                if endian_test.to_le() != endian_test {
                    l_endian = false;
                } else {
                    // if we are on a little endian machine to_le() is a no-op
                    l_endian = true;
                }
                println!("l_endian = {}", l_endian);
                let mut switch_endian;
                if buf[8] as char == 'v' {
                    // file stores little endian
                    if !l_endian {
                        switch_endian = true;
                    } else {
                        switch_endian = false;
                    }
                } else {
                    // file stores big endian
                    if l_endian {
                        switch_endian = true;
                    } else {
                        switch_endian = false;
                    }
                }
                println!("switch_endian = {}", switch_endian);
                // get the version number
                let mut num = String::new();
                for n in range(9u, 12) {
                    num.push(buf[n] as char);
                }
                println!("num = {}", num);
                // read_file_dna
                let mut bhead8 = [0u8, ..24]; // 4 * int + 64-bit pointer
                match file.read(bhead8) {
                    Err(why) => fail!("couldn't open {}: {}", display, why.desc),
                    Ok(_) => (),
                }
                // pack those 12 bytes into a string ...
                let mut bhead = String::new();
                for n in range(0u, 24) {
                    bhead.push(bhead8[n] as char);
                }
                let slice = bhead.as_slice();
                let code: &str = slice.slice(0, 4); // first 4 chars
                println!("code = {}", code);
                let mut len: int = 0;
                println!("bhead8[4] = {}", bhead8[4] as int);
                println!("bhead8[5] = {}", bhead8[5] as int);
                println!("bhead8[6] = {}", bhead8[6] as int);
                println!("bhead8[7] = {}", bhead8[7] as int);
                len += (bhead8[4] as int) <<  0;
                len += (bhead8[5] as int) <<  8;
                len += (bhead8[6] as int) << 16;
                len += (bhead8[7] as int) << 24;
                println!("len = {}", len);
            } else {
                println!("ERROR: not a Blender file.");
            }
        } // file gets closed here
    }
}
<|endoftext|>


<commit_before>// This file is part of rgtk.
//
// rgtk is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// rgtk is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

#![feature(slicing_syntax, env, path, io, collections)]

extern crate gcc;
extern crate "pkg-config" as pkg_config;

use std::old_io::process::Command;
use gcc::Config;
use std::env;

fn main() {
    env::set_var("PKG_CONFIG_ALLOW_CROSS", "1");

    // try to find gtk+-3.0 library
    match pkg_config::find_library("gtk+-3.0") {
        Ok(_) => {},
        Err(e) => panic!("{}", e)
    };

    // call native pkg-config, there is no way to do this with pkg-config for now
    let cmd = match Command::new("pkg-config").arg("--cflags").arg("gtk+-3.0").output() {
        Ok(r) => r,
        Err(e) => panic!("{}", e)
    };

    // make the vector of path to set to gcc::Config
    let output: String = unsafe { String::from_utf8_unchecked(cmd.output) };
    let res: Vec<&str> = output.split(' ').collect();
    let paths: Vec<Path> = res.iter().filter_map(|s| {
        if s.len() > 1 && s.char_at(1) == 'I' { Some(Path::new(&s[2..])) }
        else { None }
    }).collect();

    // build include path
    let mut gcc_conf = Config::new();
    for path in paths {
        gcc_conf.include(path);
    }
    gcc_conf.file("./gtk_glue/gtk_glue.c");

    // build library
    gcc_conf.compile("librgtk_glue.a");
}
<commit_msg>Pass path by reference<commit_after>// This file is part of rgtk.
//
// rgtk is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// rgtk is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

#![feature(slicing_syntax, env, path, io, collections)]

extern crate gcc;
extern crate "pkg-config" as pkg_config;

use std::old_io::process::Command;
use gcc::Config;
use std::env;

fn main() {
    env::set_var("PKG_CONFIG_ALLOW_CROSS", "1");

    // try to find gtk+-3.0 library
    match pkg_config::find_library("gtk+-3.0") {
        Ok(_) => {},
        Err(e) => panic!("{}", e)
    };

    // call native pkg-config, there is no way to do this with pkg-config for now
    let cmd = match Command::new("pkg-config").arg("--cflags").arg("gtk+-3.0").output() {
        Ok(r) => r,
        Err(e) => panic!("{}", e)
    };

    // make the vector of path to set to gcc::Config
    let output: String = unsafe { String::from_utf8_unchecked(cmd.output) };
    let res: Vec<&str> = output.split(' ').collect();
    let paths: Vec<Path> = res.iter().filter_map(|s| {
        if s.len() > 1 && s.char_at(1) == 'I' { Some(Path::new(&s[2..])) }
        else { None }
    }).collect();

    // build include path
    let mut gcc_conf = Config::new();
    for path in paths {
        gcc_conf.include(&path);
    }
    gcc_conf.file("./gtk_glue/gtk_glue.c");

    // build library
    gcc_conf.compile("librgtk_glue.a");
}
<|endoftext|>


<commit_before>#[cfg(feature="gnustep_runtime")]
extern crate gcc;

#[cfg(not(feature="gnustep_runtime"))]
fn compile() {
}

#[cfg(feature="gnustep_runtime")]
fn compile() {
    gcc::Config::new().flag("-lobjc")
                      .flag("-fobjc-runtime=gnustep-1.8")
                      .flag("-fno-objc-legacy-dispatch")
                      .file("extern/NSObject.m")
                      .link(false)
                      .compile("libNSObject.a");
}
fn main() {
    compile();
}
<commit_msg>Update to track proposed gcc-rs API<commit_after>#[cfg(feature="gnustep_runtime")]
extern crate gcc;
#[cfg(feature="gnustep_runtime")]
use std::path::PathBuf;

#[cfg(not(feature="gnustep_runtime"))]
fn compile() {
}

#[cfg(feature="gnustep_runtime")]
fn compile() {
    gcc::Config::new().flag("-lobjc")
                      .flag("-fobjc-runtime=gnustep-1.8")
                      .flag("-fno-objc-legacy-dispatch")
                      .file("extern/NSObject.m")
                      .cargo_metadata(false)
                      .compile("libNSObject.a");
    let path = ::std::env::var_os("OUT_DIR").map(PathBuf::from).unwrap();
    println!("cargo:rustc-link-search=native={}", path.display());
}
fn main() {
    compile();
}
<|endoftext|>


<commit_before>use std::env::{
	var,
	var_os,
};

fn cfg_arch() -> String {
	var("CARGO_CFG_TARGET_ARCH").expect("couldn't find target architecture")
}

fn cfg_family_is(family: &str) -> bool {
	var_os("CARGO_CFG_TARGET_FAMILY").unwrap() == *family
}

fn cfg_os_is(family: &str) -> bool {
	var_os("CARGO_CFG_TARGET_OS").unwrap() == *family
}

fn find_avahi_compat_dns_sd() {
	// on unix but not darwin link avahi compat
	if cfg_family_is("unix") && !(cfg_os_is("macos") || cfg_os_is("ios")) {
		pkg_config::probe_library("avahi-compat-libdns_sd").unwrap();
	}
}

fn find_windows_dns_sd() {
	if cfg_family_is("windows") {
		let platform = match cfg_arch().as_str() {
			"x86_64" => "x64",
			"x86" => "Win32",
			arch => panic!("unsupported target architecture: {:?}", arch),
		};

		match var("BONJOUR_SDK_HOME") {
			Ok(path) => println!("cargo:rustc-link-search=native={}\\Lib\\{}", path, platform),
			Err(e) => panic!("Can't find Bonjour SDK (download from https://developer.apple.com/opensource/) at BONJOUR_SDK_HOME: {}", e),
		}
		println!("cargo:rustc-link-lib=dnssd");
	}
}

fn main() {
	println!("cargo:rerun-if-changed=build.rs");
	find_avahi_compat_dns_sd();
	find_windows_dns_sd();
}
<commit_msg>support cross-compiling windows by using proper path separators<commit_after>use std::env::{
	var,
	var_os,
};

fn cfg_arch() -> String {
	var("CARGO_CFG_TARGET_ARCH").expect("couldn't find target architecture")
}

fn cfg_family_is(family: &str) -> bool {
	var_os("CARGO_CFG_TARGET_FAMILY").unwrap() == *family
}

fn cfg_os_is(family: &str) -> bool {
	var_os("CARGO_CFG_TARGET_OS").unwrap() == *family
}

fn find_avahi_compat_dns_sd() {
	// on unix but not darwin link avahi compat
	if cfg_family_is("unix") && !(cfg_os_is("macos") || cfg_os_is("ios")) {
		pkg_config::probe_library("avahi-compat-libdns_sd").unwrap();
	}
}

fn find_windows_dns_sd() {
	if cfg_family_is("windows") {
		let platform = match cfg_arch().as_str() {
			"x86_64" => "x64",
			"x86" => "Win32",
			arch => panic!("unsupported target architecture: {:?}", arch),
		};

		match var("BONJOUR_SDK_HOME") {
			Ok(path) => println!("cargo:rustc-link-search=native={}{sep}Lib{sep}{}", path, platform, sep=std::path::MAIN_SEPARATOR),
			Err(e) => panic!("Can't find Bonjour SDK (download from https://developer.apple.com/opensource/) at BONJOUR_SDK_HOME: {}", e),
		}
		println!("cargo:rustc-link-lib=dnssd");
	}
}

fn main() {
	println!("cargo:rerun-if-changed=build.rs");
	find_avahi_compat_dns_sd();
	find_windows_dns_sd();
}
<|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 app_units::Au;
use std::collections::HashMap;
use webrender_traits::{FontKey, ColorU, FontRenderMode, GlyphDimensions, GlyphOptions};
use gamma_lut::{GammaLut, Color as ColorLut};

use dwrote;

lazy_static! {
    static ref DEFAULT_FONT_DESCRIPTOR: dwrote::FontDescriptor = dwrote::FontDescriptor {
        family_name: "Arial".to_owned(),
        weight: dwrote::FontWeight::Regular,
        stretch: dwrote::FontStretch::Normal,
        style: dwrote::FontStyle::Normal,
    };
}

#[allow(dead_code)]
pub struct FontContext {
    fonts: HashMap<FontKey, dwrote::FontFace>,
    gamma_lut: GammaLut,
    gdi_gamma_lut: GammaLut,
}

pub struct RasterizedGlyph {
    pub width: u32,
    pub height: u32,
    pub bytes: Vec<u8>,
}

fn dwrite_texture_type(render_mode: FontRenderMode) ->
                       dwrote::DWRITE_TEXTURE_TYPE {
    match render_mode {
        FontRenderMode::Mono => dwrote::DWRITE_TEXTURE_ALIASED_1x1 ,
        FontRenderMode::Alpha |
        FontRenderMode::Subpixel => dwrote::DWRITE_TEXTURE_CLEARTYPE_3x1,
    }
}

fn dwrite_measure_mode(render_mode: FontRenderMode) ->
                       dwrote::DWRITE_MEASURING_MODE {
    match render_mode {
        FontRenderMode::Mono => dwrote::DWRITE_MEASURING_MODE_GDI_NATURAL,
        FontRenderMode::Alpha => dwrote::DWRITE_MEASURING_MODE_GDI_NATURAL,
        FontRenderMode::Subpixel => dwrote::DWRITE_MEASURING_MODE_GDI_CLASSIC,
    }
}

fn dwrite_render_mode(render_mode: FontRenderMode) ->
                      dwrote::DWRITE_RENDERING_MODE {
    match render_mode {
        FontRenderMode::Mono => dwrote::DWRITE_RENDERING_MODE_ALIASED,
        FontRenderMode::Alpha => dwrote::DWRITE_RENDERING_MODE_GDI_NATURAL,
        FontRenderMode::Subpixel => dwrote::DWRITE_RENDERING_MODE_GDI_CLASSIC,
    }
}

fn get_glyph_dimensions_with_analysis(analysis: dwrote::GlyphRunAnalysis,
                                      texture_type: dwrote::DWRITE_TEXTURE_TYPE)
                                      -> GlyphDimensions {
    let bounds = analysis.get_alpha_texture_bounds(texture_type);

    let width = (bounds.right - bounds.left) as u32;
    let height = (bounds.bottom - bounds.top) as u32;
    GlyphDimensions {
        left: bounds.left,
        top: -bounds.top,
        width: width,
        height: height,
    }
}

impl FontContext {
    pub fn new() -> FontContext {
        // These are the default values we use in Gecko.
        // We use a gamma value of 2.3 for gdi fonts
        // TODO: Fetch this data from Gecko itself.
        let contrast = 1.0;
        let gamma = 1.8;
        let gdi_gamma = 2.3;
        FontContext {
            fonts: HashMap::new(),
            gamma_lut: GammaLut::new(contrast, gamma, gamma),
            gdi_gamma_lut: GammaLut::new(contrast, gdi_gamma, gdi_gamma),
        }
    }

    pub fn add_raw_font(&mut self, font_key: &FontKey, data: &[u8]) {
        if self.fonts.contains_key(font_key) {
            return
        }

        if let Some(font_file) = dwrote::FontFile::new_from_data(data) {
            let face = font_file.create_face(0, dwrote::DWRITE_FONT_SIMULATIONS_NONE);
            self.fonts.insert((*font_key).clone(), face);
        } else {
            // XXX add_raw_font needs to have a way to return an error
            debug!("DWrite WR failed to load font from data, using Arial instead");
            self.add_native_font(font_key, DEFAULT_FONT_DESCRIPTOR.clone());
        }
    }

    pub fn add_native_font(&mut self, font_key: &FontKey, font_handle: dwrote::FontDescriptor) {
        if self.fonts.contains_key(font_key) {
            return
        }

        let system_fc = dwrote::FontCollection::system();
        let font = system_fc.get_font_from_descriptor(&font_handle).unwrap();
        let face = font.create_font_face();
        self.fonts.insert((*font_key).clone(), face);
    }

    // Assumes RGB format from dwrite, which is 3 bytes per pixel as dwrite
    // doesn't output an alpha value via GlyphRunAnalysis::CreateAlphaTexture
    #[allow(dead_code)]
    fn print_glyph_data(&self, data: &Vec<u8>, width: usize, height: usize) {
        // Rust doesn't have step_by support on stable :(
        for i in 0..height {
            let current_height = i * width * 3;

            for pixel in data[current_height .. current_height + (width * 3)].chunks(3) {
                let r = pixel[0];
                let g = pixel[1];
                let b = pixel[2];
                print!("({}, {}, {}) ", r, g, b, );
            }
            println!("");
        }
    }

    fn create_glyph_analysis(&self, font_key: FontKey,
                            size: Au, glyph: u32,
                            render_mode: FontRenderMode) ->
                            dwrote::GlyphRunAnalysis {
        let face = self.fonts.get(&font_key).unwrap();
        let glyph = glyph as u16;

        let glyph = glyph as u16;
        let advance = 0.0f32;
        let offset = dwrote::GlyphOffset { advanceOffset: 0.0, ascenderOffset: 0.0 };

        let glyph_run = dwrote::DWRITE_GLYPH_RUN {
            fontFace: unsafe { face.as_ptr() },
            fontEmSize: size.to_f32_px(), // size in DIPs (1/96", same as CSS pixels)
            glyphCount: 1,
            glyphIndices: &glyph,
            glyphAdvances: &advance,
            glyphOffsets: &offset,
            isSideways: 0,
            bidiLevel: 0,
        };

        let dwrite_render_mode = dwrite_render_mode(render_mode);
        let dwrite_measure_mode = dwrite_measure_mode(render_mode);

        // XX use the xform to handle subpixel positioning (what skia does), I believe that keeps
        //let xform = dwrote::DWRITE_MATRIX { m11: 1.0, m12: 0.0, m21: 0.0, m22: 1.0, dx: 0.0, dy: 0.0 };
        dwrote::GlyphRunAnalysis::create(&glyph_run, 1.0, None,
                                         dwrite_render_mode,
                                         dwrite_measure_mode,
                                         0.0, 0.0)
    }

    pub fn get_glyph_dimensions(&self,
                                font_key: FontKey,
                                size: Au,
                                glyph: u32) -> Option<GlyphDimensions> {
        // Probably have to default to something else here.
        let render_mode = FontRenderMode::Subpixel;
        let analysis = self.create_glyph_analysis(font_key, size, glyph, render_mode);

        let texture_type = dwrite_texture_type(render_mode);
        Some(get_glyph_dimensions_with_analysis(analysis, texture_type))
    }

    // DWRITE gives us values in RGB. WR doesn't really touch it after. Note, CG returns in BGR
    // TODO: Decide whether all fonts should return RGB or BGR
    fn convert_to_rgba(&self, pixels: &Vec<u8>, render_mode: FontRenderMode) -> Vec<u8> {
        match render_mode {
            FontRenderMode::Mono => {
                let mut rgba_pixels: Vec<u8> = Vec::with_capacity(pixels.len() * 4);
                for i in 0..pixels.len() {
                    rgba_pixels[i*4+0] = pixels[i];
                    rgba_pixels[i*4+1] = pixels[i];
                    rgba_pixels[i*4+2] = pixels[i];
                    rgba_pixels[i*4+3] = pixels[i];
                }
                rgba_pixels
            }
            FontRenderMode::Alpha => {
                let length = pixels.len() / 3;
                let mut rgba_pixels: Vec<u8> = Vec::with_capacity(length * 4);
                for i in 0..length {
                    // TODO(vlad): we likely need to do something smarter
                    // This is what skia does
                    let alpha = ((pixels[i*3+0] as u32 +
                                pixels[i*3+1] as u32 +
                                pixels[i*3+2] as u32)
                                / 3) as u8;

                    rgba_pixels[i*4+0] = alpha;
                    rgba_pixels[i*4+1] = alpha;
                    rgba_pixels[i*4+2] = alpha;
                    rgba_pixels[i*4+3] = alpha;
                }
                rgba_pixels
            }
            FontRenderMode::Subpixel => {
                let length = pixels.len() / 3;
                let mut rgba_pixels: Vec<u8> = Vec::with_capacity(length * 4);
                for i in 0..length {
                    rgba_pixels[i*4+0] = pixels[i*3+0];
                    rgba_pixels[i*4+1] = pixels[i*3+1];
                    rgba_pixels[i*4+2] = pixels[i*3+2];
                    rgba_pixels[i*4+3] = 0xff;
                }
                rgba_pixels
            }
        }
    }

    pub fn rasterize_glyph(&mut self,
                           font_key: FontKey,
                           size: Au,
                           color: ColorU,
                           glyph: u32,
                           render_mode: FontRenderMode,
                           glyph_options: Option<GlyphOptions>) -> Option<RasterizedGlyph> {
        let analysis = self.create_glyph_analysis(font_key, size, glyph, render_mode);
        let texture_type = dwrite_texture_type(render_mode);

        let bounds = analysis.get_alpha_texture_bounds(texture_type);
        let width = (bounds.right - bounds.left) as usize;
        let height = (bounds.bottom - bounds.top) as usize;

        let mut pixels = analysis.create_alpha_texture(texture_type, bounds);
        self.gamma_lut.preblend_rgb(&mut pixels, width, height,
                                    ColorLut::new(color.r, color.g, color.b, color.a));

        let rgba_pixels = self.convert_to_rgba(&mut pixels, render_mode);

        Some(RasterizedGlyph {
            width: width as u32,
            height: height as u32,
            bytes: rgba_pixels,
        })
    }
}
<commit_msg>Auto merge of #787 - changm:dwrite, r=vvuk<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 app_units::Au;
use std::collections::HashMap;
use webrender_traits::{FontKey, ColorU, FontRenderMode, GlyphDimensions, GlyphOptions};
use gamma_lut::{GammaLut, Color as ColorLut};

use dwrote;

lazy_static! {
    static ref DEFAULT_FONT_DESCRIPTOR: dwrote::FontDescriptor = dwrote::FontDescriptor {
        family_name: "Arial".to_owned(),
        weight: dwrote::FontWeight::Regular,
        stretch: dwrote::FontStretch::Normal,
        style: dwrote::FontStyle::Normal,
    };
}

#[allow(dead_code)]
pub struct FontContext {
    fonts: HashMap<FontKey, dwrote::FontFace>,
    gamma_lut: GammaLut,
    gdi_gamma_lut: GammaLut,
}

pub struct RasterizedGlyph {
    pub width: u32,
    pub height: u32,
    pub bytes: Vec<u8>,
}

fn dwrite_texture_type(render_mode: FontRenderMode) ->
                       dwrote::DWRITE_TEXTURE_TYPE {
    match render_mode {
        FontRenderMode::Mono => dwrote::DWRITE_TEXTURE_ALIASED_1x1 ,
        FontRenderMode::Alpha |
        FontRenderMode::Subpixel => dwrote::DWRITE_TEXTURE_CLEARTYPE_3x1,
    }
}

fn dwrite_measure_mode(render_mode: FontRenderMode) ->
                       dwrote::DWRITE_MEASURING_MODE {
    match render_mode {
        FontRenderMode::Mono => dwrote::DWRITE_MEASURING_MODE_GDI_NATURAL,
        FontRenderMode::Alpha => dwrote::DWRITE_MEASURING_MODE_GDI_NATURAL,
        FontRenderMode::Subpixel => dwrote::DWRITE_MEASURING_MODE_GDI_CLASSIC,
    }
}

fn dwrite_render_mode(render_mode: FontRenderMode) ->
                      dwrote::DWRITE_RENDERING_MODE {
    match render_mode {
        FontRenderMode::Mono => dwrote::DWRITE_RENDERING_MODE_ALIASED,
        FontRenderMode::Alpha => dwrote::DWRITE_RENDERING_MODE_GDI_NATURAL,
        FontRenderMode::Subpixel => dwrote::DWRITE_RENDERING_MODE_GDI_CLASSIC,
    }
}

fn get_glyph_dimensions_with_analysis(analysis: dwrote::GlyphRunAnalysis,
                                      texture_type: dwrote::DWRITE_TEXTURE_TYPE)
                                      -> GlyphDimensions {
    let bounds = analysis.get_alpha_texture_bounds(texture_type);

    let width = (bounds.right - bounds.left) as u32;
    let height = (bounds.bottom - bounds.top) as u32;
    GlyphDimensions {
        left: bounds.left,
        top: -bounds.top,
        width: width,
        height: height,
    }
}

impl FontContext {
    pub fn new() -> FontContext {
        // These are the default values we use in Gecko.
        // We use a gamma value of 2.3 for gdi fonts
        // TODO: Fetch this data from Gecko itself.
        let contrast = 1.0;
        let gamma = 1.8;
        let gdi_gamma = 2.3;
        FontContext {
            fonts: HashMap::new(),
            gamma_lut: GammaLut::new(contrast, gamma, gamma),
            gdi_gamma_lut: GammaLut::new(contrast, gdi_gamma, gdi_gamma),
        }
    }

    pub fn add_raw_font(&mut self, font_key: &FontKey, data: &[u8]) {
        if self.fonts.contains_key(font_key) {
            return
        }

        if let Some(font_file) = dwrote::FontFile::new_from_data(data) {
            let face = font_file.create_face(0, dwrote::DWRITE_FONT_SIMULATIONS_NONE);
            self.fonts.insert((*font_key).clone(), face);
        } else {
            // XXX add_raw_font needs to have a way to return an error
            debug!("DWrite WR failed to load font from data, using Arial instead");
            self.add_native_font(font_key, DEFAULT_FONT_DESCRIPTOR.clone());
        }
    }

    pub fn add_native_font(&mut self, font_key: &FontKey, font_handle: dwrote::FontDescriptor) {
        if self.fonts.contains_key(font_key) {
            return
        }

        let system_fc = dwrote::FontCollection::system();
        let font = system_fc.get_font_from_descriptor(&font_handle).unwrap();
        let face = font.create_font_face();
        self.fonts.insert((*font_key).clone(), face);
    }

    // Assumes RGB format from dwrite, which is 3 bytes per pixel as dwrite
    // doesn't output an alpha value via GlyphRunAnalysis::CreateAlphaTexture
    #[allow(dead_code)]
    fn print_glyph_data(&self, data: &Vec<u8>, width: usize, height: usize) {
        // Rust doesn't have step_by support on stable :(
        for i in 0..height {
            let current_height = i * width * 3;

            for pixel in data[current_height .. current_height + (width * 3)].chunks(3) {
                let r = pixel[0];
                let g = pixel[1];
                let b = pixel[2];
                print!("({}, {}, {}) ", r, g, b, );
            }
            println!("");
        }
    }

    fn create_glyph_analysis(&self, font_key: FontKey,
                            size: Au, glyph: u32,
                            render_mode: FontRenderMode) ->
                            dwrote::GlyphRunAnalysis {
        let face = self.fonts.get(&font_key).unwrap();
        let glyph = glyph as u16;

        let glyph = glyph as u16;
        let advance = 0.0f32;
        let offset = dwrote::GlyphOffset { advanceOffset: 0.0, ascenderOffset: 0.0 };

        let glyph_run = dwrote::DWRITE_GLYPH_RUN {
            fontFace: unsafe { face.as_ptr() },
            fontEmSize: size.to_f32_px(), // size in DIPs (1/96", same as CSS pixels)
            glyphCount: 1,
            glyphIndices: &glyph,
            glyphAdvances: &advance,
            glyphOffsets: &offset,
            isSideways: 0,
            bidiLevel: 0,
        };

        let dwrite_render_mode = dwrite_render_mode(render_mode);
        let dwrite_measure_mode = dwrite_measure_mode(render_mode);

        // XX use the xform to handle subpixel positioning (what skia does), I believe that keeps
        //let xform = dwrote::DWRITE_MATRIX { m11: 1.0, m12: 0.0, m21: 0.0, m22: 1.0, dx: 0.0, dy: 0.0 };
        dwrote::GlyphRunAnalysis::create(&glyph_run, 1.0, None,
                                         dwrite_render_mode,
                                         dwrite_measure_mode,
                                         0.0, 0.0)
    }

    pub fn get_glyph_dimensions(&self,
                                font_key: FontKey,
                                size: Au,
                                glyph: u32) -> Option<GlyphDimensions> {
        // Probably have to default to something else here.
        let render_mode = FontRenderMode::Subpixel;
        let analysis = self.create_glyph_analysis(font_key, size, glyph, render_mode);

        let texture_type = dwrite_texture_type(render_mode);
        Some(get_glyph_dimensions_with_analysis(analysis, texture_type))
    }

    // DWRITE gives us values in RGB. WR doesn't really touch it after. Note, CG returns in BGR
    // TODO: Decide whether all fonts should return RGB or BGR
    fn convert_to_rgba(&self, pixels: &Vec<u8>, render_mode: FontRenderMode) -> Vec<u8> {
        match render_mode {
            FontRenderMode::Mono => {
                let mut rgba_pixels: Vec<u8> = vec![0; pixels.len() * 4];
                for i in 0..pixels.len() {
                    rgba_pixels[i*4+0] = pixels[i];
                    rgba_pixels[i*4+1] = pixels[i];
                    rgba_pixels[i*4+2] = pixels[i];
                    rgba_pixels[i*4+3] = pixels[i];
                }
                rgba_pixels
            }
            FontRenderMode::Alpha => {
                let length = pixels.len() / 3;
                let mut rgba_pixels: Vec<u8> = vec![0; length * 4];
                for i in 0..length {
                    // TODO(vlad): we likely need to do something smarter
                    // This is what skia does
                    let alpha = ((pixels[i*3+0] as u32 +
                                pixels[i*3+1] as u32 +
                                pixels[i*3+2] as u32)
                                / 3) as u8;

                    rgba_pixels[i*4+0] = alpha;
                    rgba_pixels[i*4+1] = alpha;
                    rgba_pixels[i*4+2] = alpha;
                    rgba_pixels[i*4+3] = alpha;
                }
                rgba_pixels
            }
            FontRenderMode::Subpixel => {
                let length = pixels.len() / 3;
                let mut rgba_pixels: Vec<u8> = vec![0; length * 4];
                for i in 0..length {
                    rgba_pixels[i*4+0] = pixels[i*3+0];
                    rgba_pixels[i*4+1] = pixels[i*3+1];
                    rgba_pixels[i*4+2] = pixels[i*3+2];
                    rgba_pixels[i*4+3] = 0xff;
                }
                rgba_pixels
            }
        }
    }

    pub fn rasterize_glyph(&mut self,
                           font_key: FontKey,
                           size: Au,
                           color: ColorU,
                           glyph: u32,
                           render_mode: FontRenderMode,
                           glyph_options: Option<GlyphOptions>) -> Option<RasterizedGlyph> {
        let analysis = self.create_glyph_analysis(font_key, size, glyph, render_mode);
        let texture_type = dwrite_texture_type(render_mode);

        let bounds = analysis.get_alpha_texture_bounds(texture_type);
        let width = (bounds.right - bounds.left) as usize;
        let height = (bounds.bottom - bounds.top) as usize;

        let mut pixels = analysis.create_alpha_texture(texture_type, bounds);
        self.gamma_lut.preblend_rgb(&mut pixels, width, height,
                                    ColorLut::new(color.r, color.g, color.b, color.a));

        let rgba_pixels = self.convert_to_rgba(&mut pixels, render_mode);

        Some(RasterizedGlyph {
            width: width as u32,
            height: height as u32,
            bytes: rgba_pixels,
        })
    }
}
<|endoftext|>