<commit_before>//! Materials represent a shader and its configurable properties.
//!
//! # Shader Properties
//!
//! Shaders can have three kinds of
//! input values: Vertex attributes, varying attributes, and uniform attributes. Vertex attributes
//! are values that are different for each vertex of the mesh being rendered, e.g. the position of
//! the vertex. Varying attributes are values that calculated per vertex and then are blended
//! together per pixel. Uniform attributes are values that are set once and are the same for every
//! vertex and every pixel of the mesh. For the most part vertex attributes and varying attributes
//! cannot be changed by the developer at runtime because they are baked into the mesh when it is
//! made, but uniform attributes can used to configure a shader and change its output on the fly.
//!
//! Some uniform attributes are configured automatically and are the same for all meshes being
//! rendered, such as the ambient color, but shaders can also have custom properties that don't get
//! handled by polygon automatically. These properties become material properties and can be set by
//! the programmer. For example, let's say we want a shader that always renders a flat color and we
//! want both red and blue objects in our scene. Materials allow us to write one shader that takes
//! the color as a property. Then we can make two materials, both using the same shader but one set
//! to show red and the other set to show blue.

use math::*;
use shader::Shader;
use std::collections::HashMap;
use std::collections::hash_map::Iter as HashMapIter;
use texture::GpuTexture;

pub use polygon_material::material_source::{Error as MaterialSourceError, MaterialSource};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MaterialId(usize);
derive_Counter!(MaterialId);

/// Represents combination of a shader and set values for its uniform properties.
#[derive(Debug, Clone)]
pub struct Material {
    shader: Shader,
    properties: HashMap<String, MaterialProperty>,
}

impl Material {
    /// Creates a new material using the specified shader.
    pub fn new(shader: Shader) -> Material {
        Material {
            shader: shader,
            properties: HashMap::new(),
        }
    }

    /// Gets a reference to the shader used by the material.
    pub fn shader(&self) -> &Shader {
        &self.shader
    }

    /// Gets an iterator yielding the the current material properties.
    pub fn properties(&self) -> HashMapIter<String, MaterialProperty> {
        self.properties.iter()
    }

    /// Gets the value of a material property.
    pub fn get_property(&self, name: &str) -> Option<&MaterialProperty> {
        self.properties.get(name)
    }

    /// Sets a property value to be the specified color.
    pub fn set_color<S: Into<String>>(&mut self, name: S, color: Color) {
        self.properties.insert(name.into(), MaterialProperty::Color(color));
    }

    /// Gets the value of a color property.
    pub fn get_color(&self, name: &str) -> Option<&Color> {
        match self.properties.get(name) {
            Some(&MaterialProperty::Color(ref color)) => Some(color),
            _ => None,
        }
    }

    /// Sets a property value to be the specified `f32` value.
    pub fn set_f32<S: Into<String>>(&mut self, name: S, value: f32) {
        self.properties.insert(name.into(), MaterialProperty::f32(value));
    }

    /// Gets the value of a `f32` material property.
    pub fn get_f32(&self, name: &str) -> Option<&f32> {
        match self.properties.get(name) {
            Some(&MaterialProperty::f32(ref value)) => Some(value),
            _ => None,
        }
    }

    /// Sets a property value to be the specified `Vector3` value.
    pub fn set_vector3<S: Into<String>>(&mut self, name: S, value: Vector3) {
        self.properties.insert(name.into(), MaterialProperty::Vector3(value));
    }

    /// Gets the value of a `Vector3` material property.
    pub fn get_vector3(&self, name: &str) -> Option<&Vector3> {
        match self.properties.get(name) {
            Some(&MaterialProperty::Vector3(ref value)) => Some(value),
            _ => None,
        }
    }

    /// Sets a property value to be the specified texture.
    pub fn set_texture<S: Into<String>>(&mut self, name: S, texture: GpuTexture) {
        self.properties.insert(name.into(), MaterialProperty::Texture(texture));
    }

    /// Removes a property from the material.
    ///
    /// The existing property is returned if any.
    pub fn clear_property(&mut self, name: &str) -> Option<MaterialProperty> {
        self.properties.remove(name)
    }
}

/// Represents a value that can be sent to the GPU and used in shader programs.
#[derive(Debug, Clone)]
#[allow(bad_style)]
pub enum MaterialProperty {
    Color(Color),
    Texture(GpuTexture),
    f32(f32),
    Vector3(Vector3),
}
<commit_msg>Add notes about current state of material system<commit_after>//! Materials represent a shader and its configurable properties.
//!
//! # Shader Properties
//!
//! Shaders can have three kinds of
//! input values: Vertex attributes, varying attributes, and uniform attributes. Vertex attributes
//! are values that are different for each vertex of the mesh being rendered, e.g. the position of
//! the vertex. Varying attributes are values that calculated per vertex and then are blended
//! together per pixel. Uniform attributes are values that are set once and are the same for every
//! vertex and every pixel of the mesh. For the most part vertex attributes and varying attributes
//! cannot be changed by the developer at runtime because they are baked into the mesh when it is
//! made, but uniform attributes can used to configure a shader and change its output on the fly.
//!
//! Some uniform attributes are configured automatically and are the same for all meshes being
//! rendered, such as the ambient color, but shaders can also have custom properties that don't get
//! handled by polygon automatically. These properties become material properties and can be set by
//! the programmer. For example, let's say we want a shader that always renders a flat color and we
//! want both red and blue objects in our scene. Materials allow us to write one shader that takes
//! the color as a property. Then we can make two materials, both using the same shader but one set
//! to show red and the other set to show blue.
//!
//! # Writing Materials
//!
//! > NOTE: This information is incomplete, and will likely not be for a long time. It's meant
//! > more as reference information about the current material syntax than as a proper tutorial.
//!
//! ## Programs
//!
//! TODO: How do you specify vertex and frag shaders. What are their inputs and outputs?
//!
//! ## Vertex attributes
//!
//! TODO: What are the input and output vertex attributes?
//!
//! ## Built-In Uniforms and Attributes
//!
//! Polygon injects a number of uniforms and vertex attributes into your materials automatically
//! in order to handle things like transforms and lighting. The following are the uniforms
//! currently injected by the OpenGL renderer:
//!
//! Transforms:
//!
//! - `model_transform: Matrix4` - The transform converting points in model space to world space.
//! - `normal_transform: Matrix3` - The transform converting normals in model space to world space.
//! - `view_transform: Matrix4` - The transform converting points in world space to view space.
//! - `view_normal_transform: Matrix3` - The transform converting normals in world space to view space.
//! - `model_view_transform: Matrix4` - The transform converting points in model space to view space.
//! - `projection_transform: Matrix4` - The transform converting points in view space to projection space.
//! - `model_view_project: Matrix4` - The transform converting points in model space to projection space.
//!
//! Lighting:
//!
//! - `global_ambient: Color` - The ambient light given as a color.
//! - `camera_position: Point` - The position of the camera in world space. In view space the
//!   camera is at `(0.0, 0.0, 0.0)`.
//! - `light_position: Point` - The position of the current light in world space.
//! - `light_position_view: Point` - The position of the current light in view space.
//! - `light_strength: f32` - The strength of the current light.
//! - `light_color: Color` - The color of the current light.
//! - `light_type: u32` - An integer constant specifying the type of the current light: 0 means
//!   point light, 1 means directional light. All light-related uniforms will be present
//!   regardless of the light type, but uniforms not used for the current light type will not be
//!   set, so reading them will yield some kind of garbage.
//! - `light_radius: f32` - The radius of the current light (only for point lights).
//! - `light_direction: Vector3` - The normalized direction in world space of the current light (only
//!   for directional lights).
//! - `light_direction_view` - The normalized direction in view space of the current light (only
//!   for directional lights).

use math::*;
use shader::Shader;
use std::collections::HashMap;
use std::collections::hash_map::Iter as HashMapIter;
use texture::GpuTexture;

pub use polygon_material::material_source::{Error as MaterialSourceError, MaterialSource};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MaterialId(usize);
derive_Counter!(MaterialId);

/// Represents combination of a shader and set values for its uniform properties.
#[derive(Debug, Clone)]
pub struct Material {
    shader: Shader,
    properties: HashMap<String, MaterialProperty>,
}

impl Material {
    /// Creates a new material using the specified shader.
    pub fn new(shader: Shader) -> Material {
        Material {
            shader: shader,
            properties: HashMap::new(),
        }
    }

    /// Gets a reference to the shader used by the material.
    pub fn shader(&self) -> &Shader {
        &self.shader
    }

    /// Gets an iterator yielding the the current material properties.
    pub fn properties(&self) -> HashMapIter<String, MaterialProperty> {
        self.properties.iter()
    }

    /// Gets the value of a material property.
    pub fn get_property(&self, name: &str) -> Option<&MaterialProperty> {
        self.properties.get(name)
    }

    /// Sets a property value to be the specified color.
    pub fn set_color<S: Into<String>>(&mut self, name: S, color: Color) {
        self.properties.insert(name.into(), MaterialProperty::Color(color));
    }

    /// Gets the value of a color property.
    pub fn get_color(&self, name: &str) -> Option<&Color> {
        match self.properties.get(name) {
            Some(&MaterialProperty::Color(ref color)) => Some(color),
            _ => None,
        }
    }

    /// Sets a property value to be the specified `f32` value.
    pub fn set_f32<S: Into<String>>(&mut self, name: S, value: f32) {
        self.properties.insert(name.into(), MaterialProperty::f32(value));
    }

    /// Gets the value of a `f32` material property.
    pub fn get_f32(&self, name: &str) -> Option<&f32> {
        match self.properties.get(name) {
            Some(&MaterialProperty::f32(ref value)) => Some(value),
            _ => None,
        }
    }

    /// Sets a property value to be the specified `Vector3` value.
    pub fn set_vector3<S: Into<String>>(&mut self, name: S, value: Vector3) {
        self.properties.insert(name.into(), MaterialProperty::Vector3(value));
    }

    /// Gets the value of a `Vector3` material property.
    pub fn get_vector3(&self, name: &str) -> Option<&Vector3> {
        match self.properties.get(name) {
            Some(&MaterialProperty::Vector3(ref value)) => Some(value),
            _ => None,
        }
    }

    /// Sets a property value to be the specified texture.
    pub fn set_texture<S: Into<String>>(&mut self, name: S, texture: GpuTexture) {
        self.properties.insert(name.into(), MaterialProperty::Texture(texture));
    }

    /// Removes a property from the material.
    ///
    /// The existing property is returned if any.
    pub fn clear_property(&mut self, name: &str) -> Option<MaterialProperty> {
        self.properties.remove(name)
    }
}

/// Represents a value that can be sent to the GPU and used in shader programs.
#[derive(Debug, Clone)]
#[allow(bad_style)]
pub enum MaterialProperty {
    Color(Color),
    Texture(GpuTexture),
    f32(f32),
    Vector3(Vector3),
}
<|endoftext|>


<commit_before>use chrono::{DateTime, UTC};
use common::{ApiError, Body, Credentials, Deleted, Query, Status,
             discovery_api};
use hyper::method::Method::{Delete, Get, Post};
use serde_json::de::from_str;
use serde_json::ser::to_string;

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct Capacity {
    pub used_bytes: u64,
    pub total_bytes: u64,
    pub used: String,
    pub total: String,
    pub percent_used: f64,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct IndexCapacity {
    pub disk_usage: Capacity,
    pub memory_usage: Capacity,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct DeletedEnvironment {
    pub environment_id: String,
    pub status: Deleted,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct NewEnvironment {
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    pub size: u64,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct Environment {
    pub environment_id: String,
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    pub created: DateTime<UTC>,
    pub updated: DateTime<UTC>,
    pub status: Status,
    pub read_only: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub size: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub index_capacity: Option<IndexCapacity>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct Environments {
    pub environments: Vec<Environment>,
}

pub fn list(creds: &Credentials) -> Result<Environments, ApiError> {
    let res =
        discovery_api(creds, Get, "/v1/environments", Query::None, Body::None)?;
    Ok(from_str(&res)?)
}

pub fn detail(creds: &Credentials,
              env_id: &str)
              -> Result<Environment, ApiError> {
    let path = "/v1/environments/".to_string() + env_id;
    let res = discovery_api(creds, Get, &path, Query::None, Body::None)?;
    Ok(from_str(&res)?)
}

pub fn create(creds: &Credentials,
              options: &NewEnvironment)
              -> Result<Environment, ApiError> {
    let request_body = to_string(options)
        .expect("Internal error: failed to convert NewEnvironment into JSON");
    let res = discovery_api(creds,
                            Post,
                            "/v1/environments",
                            Query::None,
                            Body::Json(&request_body))?;
    Ok(from_str(&res)?)
}

pub fn delete(creds: &Credentials,
              env_id: &str)
              -> Result<DeletedEnvironment, ApiError> {
    let path = "/v1/environments/".to_string() + env_id;
    let res = discovery_api(creds, Delete, &path, Query::None, Body::None)?;
    Ok(from_str(&res)?)
}
<commit_msg>Half implemented environment::preview<commit_after>use chrono::{DateTime, UTC};
use common::{ApiError, Body, Credentials, Deleted, Query, Status,
             discovery_api};
use hyper::method::Method::{Delete, Get, Post};
use serde_json::Value;
use serde_json::de::from_str;
use serde_json::ser::to_string;

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct Capacity {
    pub used_bytes: u64,
    pub total_bytes: u64,
    pub used: String,
    pub total: String,
    pub percent_used: f64,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct IndexCapacity {
    pub disk_usage: Capacity,
    pub memory_usage: Capacity,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct DeletedEnvironment {
    pub environment_id: String,
    pub status: Deleted,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct NewEnvironment {
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    pub size: u64,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct Environment {
    pub environment_id: String,
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    pub created: DateTime<UTC>,
    pub updated: DateTime<UTC>,
    pub status: Status,
    pub read_only: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub size: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub index_capacity: Option<IndexCapacity>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct Environments {
    pub environments: Vec<Environment>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TestDocument {
    pub configuration_id: String,
    pub status: String,
    pub enriched_field_units: u64,
    pub original_media_type: String,
    pub snapshots: Vec<Value>,
    pub notices: Vec<Value>,
}

pub fn list(creds: &Credentials) -> Result<Environments, ApiError> {
    let res =
        discovery_api(creds, Get, "/v1/environments", Query::None, Body::None)?;
    Ok(from_str(&res)?)
}

pub fn detail(creds: &Credentials,
              env_id: &str)
              -> Result<Environment, ApiError> {
    let path = "/v1/environments/".to_string() + env_id;
    let res = discovery_api(creds, Get, &path, Query::None, Body::None)?;
    Ok(from_str(&res)?)
}

pub fn preview(creds: &Credentials,
               env_id: &str,
               configuration_id: &str)
               -> Result<TestDocument, ApiError> {
    let path = "/v1/environments/".to_string() + env_id;
    let res = discovery_api(creds, Post, &path, Query::None, Body::None)?;
    Ok(from_str(&res)?)
}

pub fn create(creds: &Credentials,
              options: &NewEnvironment)
              -> Result<Environment, ApiError> {
    let request_body = to_string(options)
        .expect("Internal error: failed to convert NewEnvironment into JSON");
    let res = discovery_api(creds,
                            Post,
                            "/v1/environments",
                            Query::None,
                            Body::Json(&request_body))?;
    Ok(from_str(&res)?)
}

pub fn delete(creds: &Credentials,
              env_id: &str)
              -> Result<DeletedEnvironment, ApiError> {
    let path = "/v1/environments/".to_string() + env_id;
    let res = discovery_api(creds, Delete, &path, Query::None, Body::None)?;
    Ok(from_str(&res)?)
}
<|endoftext|>


<commit_before>use rocksdb;
use kite::schema::FieldRef;
use byteorder::{ByteOrder, BigEndian};

use RocksDBIndexReader;
use key_builder::KeyBuilder;
use doc_id_set::DocIdSet;
use term_dictionary::TermRef;
use document_index::DocRef;

pub trait Segment {
    fn load_statistic(&self, stat_name: &[u8]) -> Result<Option<i64>, rocksdb::Error>;
    fn load_stored_field_value_raw(&self, doc_ord: u16, field_ref: FieldRef, value_type: &[u8]) -> Result<Option<rocksdb::DBVector>, rocksdb::Error>;
    fn load_term_directory(&self, field_ref: FieldRef, term_ref: TermRef) -> Result<Option<DocIdSet>, rocksdb::Error>;
    fn load_deletion_list(&self) -> Result<Option<DocIdSet>, rocksdb::Error>;
    fn id(&self) -> u32;

    fn doc_ref(&self, ord: u16) -> DocRef {
        DocRef::from_segment_ord(self.id(), ord)
    }
}

pub struct RocksDBSegment<'a> {
    reader: &'a RocksDBIndexReader<'a>,
    id: u32,
}

impl<'a> RocksDBSegment<'a> {
    pub fn new(reader: &'a RocksDBIndexReader, id: u32) -> RocksDBSegment<'a> {
        RocksDBSegment {
            reader: reader,
            id: id,
        }
    }
}

impl<'a> Segment for RocksDBSegment<'a> {
    fn id(&self) -> u32 {
        self.id
    }

    fn load_statistic(&self, stat_name: &[u8]) -> Result<Option<i64>, rocksdb::Error> {
        let kb = KeyBuilder::segment_stat(self.id, stat_name);
        let val = try!(self.reader.snapshot.get(&kb.key())).map(|val| BigEndian::read_i64(&val));
        Ok(val)
    }

    fn load_stored_field_value_raw(&self, doc_ord: u16, field_ref: FieldRef, value_type: &[u8]) -> Result<Option<rocksdb::DBVector>, rocksdb::Error> {
        let kb = KeyBuilder::stored_field_value(self.id, doc_ord, field_ref.ord(), value_type);
        let val = try!(self.reader.snapshot.get(&kb.key()));
        Ok(val)
    }

    fn load_term_directory(&self, field_ref: FieldRef, term_ref: TermRef) -> Result<Option<DocIdSet>, rocksdb::Error> {
        let kb = KeyBuilder::segment_dir_list(self.id, field_ref.ord(), term_ref.ord());
        let doc_id_set = try!(self.reader.snapshot.get(&kb.key())).map(|doc_id_set| DocIdSet::FromRDB(doc_id_set));
        Ok(doc_id_set)
    }

    fn load_deletion_list(&self) -> Result<Option<DocIdSet>, rocksdb::Error> {
        let kb = KeyBuilder::segment_del_list(self.id);
        let doc_id_set = try!(self.reader.snapshot.get(&kb.key())).map(|doc_id_set| DocIdSet::FromRDB(doc_id_set));
        Ok(doc_id_set)
    }
}
<commit_msg>Use Vec<u8> for stored field values<commit_after>use rocksdb;
use kite::schema::FieldRef;
use byteorder::{ByteOrder, BigEndian};

use RocksDBIndexReader;
use key_builder::KeyBuilder;
use doc_id_set::DocIdSet;
use term_dictionary::TermRef;
use document_index::DocRef;

pub trait Segment {
    fn load_statistic(&self, stat_name: &[u8]) -> Result<Option<i64>, rocksdb::Error>;
    fn load_stored_field_value_raw(&self, doc_ord: u16, field_ref: FieldRef, value_type: &[u8]) -> Result<Option<Vec<u8>>, rocksdb::Error>;
    fn load_term_directory(&self, field_ref: FieldRef, term_ref: TermRef) -> Result<Option<DocIdSet>, rocksdb::Error>;
    fn load_deletion_list(&self) -> Result<Option<DocIdSet>, rocksdb::Error>;
    fn id(&self) -> u32;

    fn doc_ref(&self, ord: u16) -> DocRef {
        DocRef::from_segment_ord(self.id(), ord)
    }
}

pub struct RocksDBSegment<'a> {
    reader: &'a RocksDBIndexReader<'a>,
    id: u32,
}

impl<'a> RocksDBSegment<'a> {
    pub fn new(reader: &'a RocksDBIndexReader, id: u32) -> RocksDBSegment<'a> {
        RocksDBSegment {
            reader: reader,
            id: id,
        }
    }
}

impl<'a> Segment for RocksDBSegment<'a> {
    fn id(&self) -> u32 {
        self.id
    }

    fn load_statistic(&self, stat_name: &[u8]) -> Result<Option<i64>, rocksdb::Error> {
        let kb = KeyBuilder::segment_stat(self.id, stat_name);
        let val = try!(self.reader.snapshot.get(&kb.key())).map(|val| BigEndian::read_i64(&val));
        Ok(val)
    }

    fn load_stored_field_value_raw(&self, doc_ord: u16, field_ref: FieldRef, value_type: &[u8]) -> Result<Option<Vec<u8>>, rocksdb::Error> {
        let kb = KeyBuilder::stored_field_value(self.id, doc_ord, field_ref.ord(), value_type);
        let val = try!(self.reader.snapshot.get(&kb.key()));
        Ok(val.map(|v| v.to_vec()))
    }

    fn load_term_directory(&self, field_ref: FieldRef, term_ref: TermRef) -> Result<Option<DocIdSet>, rocksdb::Error> {
        let kb = KeyBuilder::segment_dir_list(self.id, field_ref.ord(), term_ref.ord());
        let doc_id_set = try!(self.reader.snapshot.get(&kb.key())).map(|doc_id_set| DocIdSet::FromRDB(doc_id_set));
        Ok(doc_id_set)
    }

    fn load_deletion_list(&self) -> Result<Option<DocIdSet>, rocksdb::Error> {
        let kb = KeyBuilder::segment_del_list(self.id);
        let doc_id_set = try!(self.reader.snapshot.get(&kb.key())).map(|doc_id_set| DocIdSet::FromRDB(doc_id_set));
        Ok(doc_id_set)
    }
}
<|endoftext|>


<commit_before>//! Entry point for the CSS filters infrastructure.

use cssparser::{BasicParseError, Parser};
use markup5ever::{expanded_name, local_name, namespace_url, ns};
use std::time::Instant;

use crate::bbox::BoundingBox;
use crate::coord_units::CoordUnits;
use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{Draw, ElementResult, SetAttributes};
use crate::error::{ElementError, ParseError, RenderingError};
use crate::filter::UserSpaceFilter;
use crate::length::*;
use crate::node::{Node, NodeBorrow};
use crate::paint_server::UserSpacePaintSource;
use crate::parsers::{CustomIdent, Parse, ParseValue};
use crate::properties::ComputedValues;
use crate::property_defs::ColorInterpolationFilters;
use crate::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};
use crate::transform::Transform;
use crate::xml::Attributes;

mod bounds;
use self::bounds::BoundsBuilder;

pub mod context;
use self::context::{FilterContext, FilterOutput, FilterResult};

mod error;
use self::error::FilterError;

/// A filter primitive interface.
pub trait FilterEffect: SetAttributes + Draw {
    fn resolve(&self, node: &Node) -> Result<ResolvedPrimitive, FilterError>;
}

// Filter Effects do not need to draw themselves
impl<T: FilterEffect> Draw for T {}

pub mod blend;
pub mod color_matrix;
pub mod component_transfer;
pub mod composite;
pub mod convolve_matrix;
pub mod displacement_map;
pub mod flood;
pub mod gaussian_blur;
pub mod image;
pub mod lighting;
pub mod merge;
pub mod morphology;
pub mod offset;
pub mod tile;
pub mod turbulence;

pub struct FilterSpec {
    user_space_filter: UserSpaceFilter,
    primitives: Vec<UserSpacePrimitive>,
}

/// Resolved parameters for each filter primitive.
///
/// These gather all the data that a primitive may need during rendering:
/// the `feFoo` element's attributes, any computed values from its properties,
/// and parameters extracted from the element's children (for example,
/// `feMerge` gathers info from its `feMergNode` children).
pub enum PrimitiveParams {
    Blend(blend::Blend),
    ColorMatrix(color_matrix::ColorMatrix),
    ComponentTransfer(component_transfer::ComponentTransfer),
    Composite(composite::Composite),
    ConvolveMatrix(convolve_matrix::ConvolveMatrix),
    DiffuseLighting(lighting::DiffuseLighting),
    DisplacementMap(displacement_map::DisplacementMap),
    Flood(flood::Flood),
    GaussianBlur(gaussian_blur::GaussianBlur),
    Image(image::Image),
    Merge(merge::Merge),
    Morphology(morphology::Morphology),
    Offset(offset::Offset),
    SpecularLighting(lighting::SpecularLighting),
    Tile(tile::Tile),
    Turbulence(turbulence::Turbulence),
}

impl PrimitiveParams {
    /// Returns a human-readable name for a primitive.
    #[rustfmt::skip]
    fn name(&self) -> &'static str {
        use PrimitiveParams::*;
        match self {
            Blend(..)             => "feBlend",
            ColorMatrix(..)       => "feColorMatrix",
            ComponentTransfer(..) => "feComponentTransfer",
            Composite(..)         => "feComposite",
            ConvolveMatrix(..)    => "feConvolveMatrix",
            DiffuseLighting(..)   => "feDiffuseLighting",
            DisplacementMap(..)   => "feDisplacementMap",
            Flood(..)             => "feFlood",
            GaussianBlur(..)      => "feGaussianBlur",
            Image(..)             => "feImage",
            Merge(..)             => "feMerge",
            Morphology(..)        => "feMorphology",
            Offset(..)            => "feOffset",
            SpecularLighting(..)  => "feSpecularLighting",
            Tile(..)              => "feTile",
            Turbulence(..)        => "feTurbulence",
        }
    }
}

/// The base filter primitive node containing common properties.
#[derive(Default, Clone)]
pub struct Primitive {
    x: Option<Length<Horizontal>>,
    y: Option<Length<Vertical>>,
    width: Option<ULength<Horizontal>>,
    height: Option<ULength<Vertical>>,
    result: Option<CustomIdent>,
}

pub struct ResolvedPrimitive {
    pub primitive: Primitive,
    pub params: PrimitiveParams,
}

/// A fully resolved filter primitive in user-space coordinates.
pub struct UserSpacePrimitive {
    x: Option<f64>,
    y: Option<f64>,
    width: Option<f64>,
    height: Option<f64>,
    result: Option<CustomIdent>,

    params: PrimitiveParams,
}

/// An enumeration of possible inputs for a filter primitive.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Input {
    Unspecified,
    SourceGraphic,
    SourceAlpha,
    BackgroundImage,
    BackgroundAlpha,
    FillPaint,
    StrokePaint,
    FilterOutput(CustomIdent),
}

enum_default!(Input, Input::Unspecified);

impl Parse for Input {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        parser
            .try_parse(|p| {
                parse_identifiers!(
                    p,
                    "SourceGraphic" => Input::SourceGraphic,
                    "SourceAlpha" => Input::SourceAlpha,
                    "BackgroundImage" => Input::BackgroundImage,
                    "BackgroundAlpha" => Input::BackgroundAlpha,
                    "FillPaint" => Input::FillPaint,
                    "StrokePaint" => Input::StrokePaint,
                )
            })
            .or_else(|_: BasicParseError<'_>| {
                let ident = CustomIdent::parse(parser)?;
                Ok(Input::FilterOutput(ident))
            })
    }
}

impl ResolvedPrimitive {
    fn into_user_space(
        self,
        primitive_units: CoordUnits,
        values: &ComputedValues,
        draw_ctx: &DrawingCtx,
    ) -> UserSpacePrimitive {
        let params = draw_ctx.push_coord_units(primitive_units);

        let x = self.primitive.x.map(|l| l.normalize(values, &params));
        let y = self.primitive.y.map(|l| l.normalize(values, &params));
        let width = self.primitive.width.map(|l| l.normalize(values, &params));
        let height = self.primitive.height.map(|l| l.normalize(values, &params));

        UserSpacePrimitive {
            x,
            y,
            width,
            height,
            result: self.primitive.result,
            params: self.params,
        }
    }
}

impl UserSpacePrimitive {
    /// Validates attributes and returns the `BoundsBuilder` for bounds computation.
    #[inline]
    fn get_bounds(&self, ctx: &FilterContext) -> BoundsBuilder {
        BoundsBuilder::new(self.x, self.y, self.width, self.height, ctx.paffine())
    }
}

impl Primitive {
    fn parse_standard_attributes(
        &mut self,
        attrs: &Attributes,
    ) -> Result<(Input, Input), ElementError> {
        let mut input_1 = Input::Unspecified;
        let mut input_2 = Input::Unspecified;

        for (attr, value) in attrs.iter() {
            match attr.expanded() {
                expanded_name!("", "x") => self.x = attr.parse(value)?,
                expanded_name!("", "y") => self.y = attr.parse(value)?,
                expanded_name!("", "width") => self.width = attr.parse(value)?,
                expanded_name!("", "height") => self.height = attr.parse(value)?,
                expanded_name!("", "result") => self.result = attr.parse(value)?,
                expanded_name!("", "in") => input_1 = attr.parse(value)?,
                expanded_name!("", "in2") => input_2 = attr.parse(value)?,
                _ => (),
            }
        }

        Ok((input_1, input_2))
    }

    pub fn parse_no_inputs(&mut self, attrs: &Attributes) -> ElementResult {
        let (_, _) = self.parse_standard_attributes(attrs)?;
        Ok(())
    }

    pub fn parse_one_input(&mut self, attrs: &Attributes) -> Result<Input, ElementError> {
        let (input_1, _) = self.parse_standard_attributes(attrs)?;
        Ok(input_1)
    }

    pub fn parse_two_inputs(&mut self, attrs: &Attributes) -> Result<(Input, Input), ElementError> {
        self.parse_standard_attributes(attrs)
    }
}

pub fn extract_filter_from_filter_node(
    filter_node: &Node,
    draw_ctx: &DrawingCtx,
) -> Result<FilterSpec, FilterError> {
    let filter_node = &*filter_node;
    assert!(is_element_of_type!(filter_node, Filter));

    let filter_element = filter_node.borrow_element();

    let user_space_filter = {
        let filter_values = filter_element.get_computed_values();

        let filter = borrow_element_as!(filter_node, Filter);

        // This is in a temporary scope so we don't leave the coord_units pushed during
        // the execution of all the filter primitives.
        let params = draw_ctx.push_coord_units(filter.get_filter_units());
        filter.to_user_space(filter_values, &params)
    };

    let primitives = filter_node
        .children()
        .filter(|c| c.is_element())
        // Skip nodes in error.
        .filter(|c| {
            let in_error = c.borrow_element().is_in_error();

            if in_error {
                rsvg_log!("(ignoring filter primitive {} because it is in error)", c);
            }

            !in_error
        })
        // Keep only filter primitives (those that implement the Filter trait)
        .filter(|c| c.borrow_element().as_filter_effect().is_some())
        .map(|primitive_node| {
            let elt = primitive_node.borrow_element();
            let effect = elt.as_filter_effect().unwrap();

            let primitive_values = elt.get_computed_values();

            let primitive_name = format!("{}", primitive_node);

            effect
                .resolve(&primitive_node)
                .map_err(|e| {
                    rsvg_log!(
                        "(filter primitive {} returned an error: {})",
                        primitive_name,
                        e
                    );
                    e
                })
                .and_then(|primitive| {
                    Ok(primitive.into_user_space(
                        user_space_filter.primitive_units,
                        primitive_values,
                        draw_ctx,
                    ))
                })
        })
        .collect::<Result<Vec<UserSpacePrimitive>, FilterError>>()?;

    Ok(FilterSpec {
        user_space_filter,
        primitives,
    })
}

/// Applies a filter and returns the resulting surface.
pub fn render(
    filter_node: &Node,
    stroke_paint_source: UserSpacePaintSource,
    fill_paint_source: UserSpacePaintSource,
    source_surface: SharedImageSurface,
    acquired_nodes: &mut AcquiredNodes<'_>,
    draw_ctx: &mut DrawingCtx,
    transform: Transform,
    node_bbox: BoundingBox,
) -> Result<SharedImageSurface, RenderingError> {
    let filter = match extract_filter_from_filter_node(filter_node, draw_ctx) {
        Err(FilterError::CairoError(status)) => {
            // Exit early on Cairo errors
            return Err(RenderingError::from(status));
        }

        Err(_) => {
            // ignore other filter errors and just return an empty surface
            return Ok(SharedImageSurface::empty(
                source_surface.width(),
                source_surface.height(),
                SurfaceType::AlphaOnly,
            )?);
        }

        Ok(f) => f,
    };

    if let Ok(mut filter_ctx) = FilterContext::new(
        &filter.user_space_filter,
        stroke_paint_source,
        fill_paint_source,
        &source_surface,
        transform,
        node_bbox,
    ) {
        for user_space_primitive in &filter.primitives {
            let start = Instant::now();

            match render_primitive(&user_space_primitive, &filter_ctx, acquired_nodes, draw_ctx) {
                Ok(output) => {
                    let elapsed = start.elapsed();
                    rsvg_log!(
                        "(rendered filter primitive {} in\n    {} seconds)",
                        user_space_primitive.params.name(),
                        elapsed.as_secs() as f64 + f64::from(elapsed.subsec_nanos()) / 1e9
                    );

                    filter_ctx.store_result(FilterResult {
                        name: user_space_primitive.result.clone(),
                        output,
                    });
                }

                Err(err) => {
                    rsvg_log!(
                        "(filter primitive {} returned an error: {})",
                        user_space_primitive.params.name(),
                        err
                    );

                    // Exit early on Cairo errors. Continue rendering otherwise.
                    if let FilterError::CairoError(status) = err {
                        return Err(RenderingError::from(status));
                    }
                }
            }
        }

        Ok(filter_ctx.into_output()?)
    } else {
        // Ignore errors that happened when creating the FilterContext
        Ok(SharedImageSurface::empty(
            source_surface.width(),
            source_surface.height(),
            SurfaceType::AlphaOnly,
        )?)
    }
}

#[rustfmt::skip]
fn render_primitive(
    primitive: &UserSpacePrimitive,
    ctx: &FilterContext,
    acquired_nodes: &mut AcquiredNodes<'_>,
    draw_ctx: &mut DrawingCtx,
) -> Result<FilterOutput, FilterError> {
    use PrimitiveParams::*;

    let bounds_builder = primitive.get_bounds(ctx);

    match primitive.params {
        Blend(ref p)             => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        ColorMatrix(ref p)       => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        ComponentTransfer(ref p) => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Composite(ref p)         => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        ConvolveMatrix(ref p)    => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        DiffuseLighting(ref p)   => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        DisplacementMap(ref p)   => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Flood(ref p)             => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        GaussianBlur(ref p)      => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Image(ref p)             => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Merge(ref p)             => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Morphology(ref p)        => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Offset(ref p)            => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        SpecularLighting(ref p)  => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Tile(ref p)              => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Turbulence(ref p)        => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
    }
}

impl From<ColorInterpolationFilters> for SurfaceType {
    fn from(c: ColorInterpolationFilters) -> Self {
        match c {
            ColorInterpolationFilters::LinearRgb => SurfaceType::LinearRgb,
            _ => SurfaceType::SRgb,
        }
    }
}
<commit_msg>Replace and_then with map, per clippy<commit_after>//! Entry point for the CSS filters infrastructure.

use cssparser::{BasicParseError, Parser};
use markup5ever::{expanded_name, local_name, namespace_url, ns};
use std::time::Instant;

use crate::bbox::BoundingBox;
use crate::coord_units::CoordUnits;
use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{Draw, ElementResult, SetAttributes};
use crate::error::{ElementError, ParseError, RenderingError};
use crate::filter::UserSpaceFilter;
use crate::length::*;
use crate::node::{Node, NodeBorrow};
use crate::paint_server::UserSpacePaintSource;
use crate::parsers::{CustomIdent, Parse, ParseValue};
use crate::properties::ComputedValues;
use crate::property_defs::ColorInterpolationFilters;
use crate::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};
use crate::transform::Transform;
use crate::xml::Attributes;

mod bounds;
use self::bounds::BoundsBuilder;

pub mod context;
use self::context::{FilterContext, FilterOutput, FilterResult};

mod error;
use self::error::FilterError;

/// A filter primitive interface.
pub trait FilterEffect: SetAttributes + Draw {
    fn resolve(&self, node: &Node) -> Result<ResolvedPrimitive, FilterError>;
}

// Filter Effects do not need to draw themselves
impl<T: FilterEffect> Draw for T {}

pub mod blend;
pub mod color_matrix;
pub mod component_transfer;
pub mod composite;
pub mod convolve_matrix;
pub mod displacement_map;
pub mod flood;
pub mod gaussian_blur;
pub mod image;
pub mod lighting;
pub mod merge;
pub mod morphology;
pub mod offset;
pub mod tile;
pub mod turbulence;

pub struct FilterSpec {
    user_space_filter: UserSpaceFilter,
    primitives: Vec<UserSpacePrimitive>,
}

/// Resolved parameters for each filter primitive.
///
/// These gather all the data that a primitive may need during rendering:
/// the `feFoo` element's attributes, any computed values from its properties,
/// and parameters extracted from the element's children (for example,
/// `feMerge` gathers info from its `feMergNode` children).
pub enum PrimitiveParams {
    Blend(blend::Blend),
    ColorMatrix(color_matrix::ColorMatrix),
    ComponentTransfer(component_transfer::ComponentTransfer),
    Composite(composite::Composite),
    ConvolveMatrix(convolve_matrix::ConvolveMatrix),
    DiffuseLighting(lighting::DiffuseLighting),
    DisplacementMap(displacement_map::DisplacementMap),
    Flood(flood::Flood),
    GaussianBlur(gaussian_blur::GaussianBlur),
    Image(image::Image),
    Merge(merge::Merge),
    Morphology(morphology::Morphology),
    Offset(offset::Offset),
    SpecularLighting(lighting::SpecularLighting),
    Tile(tile::Tile),
    Turbulence(turbulence::Turbulence),
}

impl PrimitiveParams {
    /// Returns a human-readable name for a primitive.
    #[rustfmt::skip]
    fn name(&self) -> &'static str {
        use PrimitiveParams::*;
        match self {
            Blend(..)             => "feBlend",
            ColorMatrix(..)       => "feColorMatrix",
            ComponentTransfer(..) => "feComponentTransfer",
            Composite(..)         => "feComposite",
            ConvolveMatrix(..)    => "feConvolveMatrix",
            DiffuseLighting(..)   => "feDiffuseLighting",
            DisplacementMap(..)   => "feDisplacementMap",
            Flood(..)             => "feFlood",
            GaussianBlur(..)      => "feGaussianBlur",
            Image(..)             => "feImage",
            Merge(..)             => "feMerge",
            Morphology(..)        => "feMorphology",
            Offset(..)            => "feOffset",
            SpecularLighting(..)  => "feSpecularLighting",
            Tile(..)              => "feTile",
            Turbulence(..)        => "feTurbulence",
        }
    }
}

/// The base filter primitive node containing common properties.
#[derive(Default, Clone)]
pub struct Primitive {
    x: Option<Length<Horizontal>>,
    y: Option<Length<Vertical>>,
    width: Option<ULength<Horizontal>>,
    height: Option<ULength<Vertical>>,
    result: Option<CustomIdent>,
}

pub struct ResolvedPrimitive {
    pub primitive: Primitive,
    pub params: PrimitiveParams,
}

/// A fully resolved filter primitive in user-space coordinates.
pub struct UserSpacePrimitive {
    x: Option<f64>,
    y: Option<f64>,
    width: Option<f64>,
    height: Option<f64>,
    result: Option<CustomIdent>,

    params: PrimitiveParams,
}

/// An enumeration of possible inputs for a filter primitive.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum Input {
    Unspecified,
    SourceGraphic,
    SourceAlpha,
    BackgroundImage,
    BackgroundAlpha,
    FillPaint,
    StrokePaint,
    FilterOutput(CustomIdent),
}

enum_default!(Input, Input::Unspecified);

impl Parse for Input {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        parser
            .try_parse(|p| {
                parse_identifiers!(
                    p,
                    "SourceGraphic" => Input::SourceGraphic,
                    "SourceAlpha" => Input::SourceAlpha,
                    "BackgroundImage" => Input::BackgroundImage,
                    "BackgroundAlpha" => Input::BackgroundAlpha,
                    "FillPaint" => Input::FillPaint,
                    "StrokePaint" => Input::StrokePaint,
                )
            })
            .or_else(|_: BasicParseError<'_>| {
                let ident = CustomIdent::parse(parser)?;
                Ok(Input::FilterOutput(ident))
            })
    }
}

impl ResolvedPrimitive {
    fn into_user_space(
        self,
        primitive_units: CoordUnits,
        values: &ComputedValues,
        draw_ctx: &DrawingCtx,
    ) -> UserSpacePrimitive {
        let params = draw_ctx.push_coord_units(primitive_units);

        let x = self.primitive.x.map(|l| l.normalize(values, &params));
        let y = self.primitive.y.map(|l| l.normalize(values, &params));
        let width = self.primitive.width.map(|l| l.normalize(values, &params));
        let height = self.primitive.height.map(|l| l.normalize(values, &params));

        UserSpacePrimitive {
            x,
            y,
            width,
            height,
            result: self.primitive.result,
            params: self.params,
        }
    }
}

impl UserSpacePrimitive {
    /// Validates attributes and returns the `BoundsBuilder` for bounds computation.
    #[inline]
    fn get_bounds(&self, ctx: &FilterContext) -> BoundsBuilder {
        BoundsBuilder::new(self.x, self.y, self.width, self.height, ctx.paffine())
    }
}

impl Primitive {
    fn parse_standard_attributes(
        &mut self,
        attrs: &Attributes,
    ) -> Result<(Input, Input), ElementError> {
        let mut input_1 = Input::Unspecified;
        let mut input_2 = Input::Unspecified;

        for (attr, value) in attrs.iter() {
            match attr.expanded() {
                expanded_name!("", "x") => self.x = attr.parse(value)?,
                expanded_name!("", "y") => self.y = attr.parse(value)?,
                expanded_name!("", "width") => self.width = attr.parse(value)?,
                expanded_name!("", "height") => self.height = attr.parse(value)?,
                expanded_name!("", "result") => self.result = attr.parse(value)?,
                expanded_name!("", "in") => input_1 = attr.parse(value)?,
                expanded_name!("", "in2") => input_2 = attr.parse(value)?,
                _ => (),
            }
        }

        Ok((input_1, input_2))
    }

    pub fn parse_no_inputs(&mut self, attrs: &Attributes) -> ElementResult {
        let (_, _) = self.parse_standard_attributes(attrs)?;
        Ok(())
    }

    pub fn parse_one_input(&mut self, attrs: &Attributes) -> Result<Input, ElementError> {
        let (input_1, _) = self.parse_standard_attributes(attrs)?;
        Ok(input_1)
    }

    pub fn parse_two_inputs(&mut self, attrs: &Attributes) -> Result<(Input, Input), ElementError> {
        self.parse_standard_attributes(attrs)
    }
}

pub fn extract_filter_from_filter_node(
    filter_node: &Node,
    draw_ctx: &DrawingCtx,
) -> Result<FilterSpec, FilterError> {
    let filter_node = &*filter_node;
    assert!(is_element_of_type!(filter_node, Filter));

    let filter_element = filter_node.borrow_element();

    let user_space_filter = {
        let filter_values = filter_element.get_computed_values();

        let filter = borrow_element_as!(filter_node, Filter);

        // This is in a temporary scope so we don't leave the coord_units pushed during
        // the execution of all the filter primitives.
        let params = draw_ctx.push_coord_units(filter.get_filter_units());
        filter.to_user_space(filter_values, &params)
    };

    let primitives = filter_node
        .children()
        .filter(|c| c.is_element())
        // Skip nodes in error.
        .filter(|c| {
            let in_error = c.borrow_element().is_in_error();

            if in_error {
                rsvg_log!("(ignoring filter primitive {} because it is in error)", c);
            }

            !in_error
        })
        // Keep only filter primitives (those that implement the Filter trait)
        .filter(|c| c.borrow_element().as_filter_effect().is_some())
        .map(|primitive_node| {
            let elt = primitive_node.borrow_element();
            let effect = elt.as_filter_effect().unwrap();

            let primitive_values = elt.get_computed_values();

            let primitive_name = format!("{}", primitive_node);

            effect
                .resolve(&primitive_node)
                .map_err(|e| {
                    rsvg_log!(
                        "(filter primitive {} returned an error: {})",
                        primitive_name,
                        e
                    );
                    e
                })
                .map(|primitive| {
                    primitive.into_user_space(
                        user_space_filter.primitive_units,
                        primitive_values,
                        draw_ctx,
                    )
                })
        })
        .collect::<Result<Vec<UserSpacePrimitive>, FilterError>>()?;

    Ok(FilterSpec {
        user_space_filter,
        primitives,
    })
}

/// Applies a filter and returns the resulting surface.
pub fn render(
    filter_node: &Node,
    stroke_paint_source: UserSpacePaintSource,
    fill_paint_source: UserSpacePaintSource,
    source_surface: SharedImageSurface,
    acquired_nodes: &mut AcquiredNodes<'_>,
    draw_ctx: &mut DrawingCtx,
    transform: Transform,
    node_bbox: BoundingBox,
) -> Result<SharedImageSurface, RenderingError> {
    let filter = match extract_filter_from_filter_node(filter_node, draw_ctx) {
        Err(FilterError::CairoError(status)) => {
            // Exit early on Cairo errors
            return Err(RenderingError::from(status));
        }

        Err(_) => {
            // ignore other filter errors and just return an empty surface
            return Ok(SharedImageSurface::empty(
                source_surface.width(),
                source_surface.height(),
                SurfaceType::AlphaOnly,
            )?);
        }

        Ok(f) => f,
    };

    if let Ok(mut filter_ctx) = FilterContext::new(
        &filter.user_space_filter,
        stroke_paint_source,
        fill_paint_source,
        &source_surface,
        transform,
        node_bbox,
    ) {
        for user_space_primitive in &filter.primitives {
            let start = Instant::now();

            match render_primitive(&user_space_primitive, &filter_ctx, acquired_nodes, draw_ctx) {
                Ok(output) => {
                    let elapsed = start.elapsed();
                    rsvg_log!(
                        "(rendered filter primitive {} in\n    {} seconds)",
                        user_space_primitive.params.name(),
                        elapsed.as_secs() as f64 + f64::from(elapsed.subsec_nanos()) / 1e9
                    );

                    filter_ctx.store_result(FilterResult {
                        name: user_space_primitive.result.clone(),
                        output,
                    });
                }

                Err(err) => {
                    rsvg_log!(
                        "(filter primitive {} returned an error: {})",
                        user_space_primitive.params.name(),
                        err
                    );

                    // Exit early on Cairo errors. Continue rendering otherwise.
                    if let FilterError::CairoError(status) = err {
                        return Err(RenderingError::from(status));
                    }
                }
            }
        }

        Ok(filter_ctx.into_output()?)
    } else {
        // Ignore errors that happened when creating the FilterContext
        Ok(SharedImageSurface::empty(
            source_surface.width(),
            source_surface.height(),
            SurfaceType::AlphaOnly,
        )?)
    }
}

#[rustfmt::skip]
fn render_primitive(
    primitive: &UserSpacePrimitive,
    ctx: &FilterContext,
    acquired_nodes: &mut AcquiredNodes<'_>,
    draw_ctx: &mut DrawingCtx,
) -> Result<FilterOutput, FilterError> {
    use PrimitiveParams::*;

    let bounds_builder = primitive.get_bounds(ctx);

    match primitive.params {
        Blend(ref p)             => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        ColorMatrix(ref p)       => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        ComponentTransfer(ref p) => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Composite(ref p)         => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        ConvolveMatrix(ref p)    => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        DiffuseLighting(ref p)   => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        DisplacementMap(ref p)   => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Flood(ref p)             => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        GaussianBlur(ref p)      => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Image(ref p)             => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Merge(ref p)             => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Morphology(ref p)        => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Offset(ref p)            => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        SpecularLighting(ref p)  => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Tile(ref p)              => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
        Turbulence(ref p)        => p.render(bounds_builder, ctx, acquired_nodes, draw_ctx),
    }
}

impl From<ColorInterpolationFilters> for SurfaceType {
    fn from(c: ColorInterpolationFilters) -> Self {
        match c {
            ColorInterpolationFilters::LinearRgb => SurfaceType::LinearRgb,
            _ => SurfaceType::SRgb,
        }
    }
}
<|endoftext|>


<commit_before>use super::consts::*;

/// Calculates a vector of match bonuses from the provided string
#[inline]
pub fn compute_bonus(haystack: &str) -> Vec<f64> {
    let mut last_char = '/';
    let bonus = Vec::with_capacity(haystack.chars().count());

    haystack.chars().fold(bonus, |mut vec, ch| {
        vec.push(for_char(last_char, ch));
        last_char = ch;
        vec
    })
}

pub fn for_char(prev: char, current: char) -> f64 {
    match current {
        'a' ... 'z' | '0' ... '9' => bonus_for_prev(prev),
        'A' ... 'Z' => {
            match prev {
                'a' ... 'z' => SCORE_MATCH_CAPITAL,
                _ => bonus_for_prev(prev)
            }
        }
        _ => 0.0
    }
}

fn bonus_for_prev(ch: char) -> f64 {
    match ch {
        '/' => SCORE_MATCH_SLASH,
        '-' | '_' | ' ' => SCORE_MATCH_WORD,
        '.' => SCORE_MATCH_DOT,
        _ => 0.0
    }
}

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

    #[test]
    fn test_compute_bonus() {
        assert_eq!(compute_bonus("a/b/c/d"), vec![0.9, 0.0, 0.9, 0.0, 0.9, 0.0, 0.9]);
        assert_eq!(compute_bonus("aTestString"), vec![0.9, 0.7, 0.0, 0.0, 0.0, 0.7, 0.0, 0.0, 0.0, 0.0, 0.0]);
    }

    #[test]
    fn test_for_char() {
        assert_eq!(for_char('*', '*'), 0.0);
        assert_eq!(for_char('a', 'a'), 0.0);

        assert_eq!(for_char('/', 'a'), SCORE_MATCH_SLASH);
        assert_eq!(for_char('/', 'A'), SCORE_MATCH_SLASH);
        assert_eq!(for_char('/', '0'), SCORE_MATCH_SLASH);

        assert_eq!(for_char('-', 'a'), SCORE_MATCH_WORD);
        assert_eq!(for_char('-', 'A'), SCORE_MATCH_WORD);
        assert_eq!(for_char('-', '0'), SCORE_MATCH_WORD);

        assert_eq!(for_char('_', 'a'), SCORE_MATCH_WORD);
        assert_eq!(for_char('_', 'A'), SCORE_MATCH_WORD);
        assert_eq!(for_char('_', '0'), SCORE_MATCH_WORD);

        assert_eq!(for_char(' ', 'a'), SCORE_MATCH_WORD);
        assert_eq!(for_char(' ', 'A'), SCORE_MATCH_WORD);
        assert_eq!(for_char(' ', '0'), SCORE_MATCH_WORD);

        assert_eq!(for_char('.', 'a'), SCORE_MATCH_DOT);
        assert_eq!(for_char('.', 'A'), SCORE_MATCH_DOT);
        assert_eq!(for_char('.', '0'), SCORE_MATCH_DOT);

        assert_eq!(for_char('a', 'A'), SCORE_MATCH_CAPITAL);
    }
}
<commit_msg>Remove unnecessary `use` statement<commit_after>use super::consts::*;

/// Calculates a vector of match bonuses from the provided string
#[inline]
pub fn compute_bonus(haystack: &str) -> Vec<f64> {
    let mut last_char = '/';
    let bonus = Vec::with_capacity(haystack.chars().count());

    haystack.chars().fold(bonus, |mut vec, ch| {
        vec.push(for_char(last_char, ch));
        last_char = ch;
        vec
    })
}

pub fn for_char(prev: char, current: char) -> f64 {
    match current {
        'a' ... 'z' | '0' ... '9' => bonus_for_prev(prev),
        'A' ... 'Z' => {
            match prev {
                'a' ... 'z' => SCORE_MATCH_CAPITAL,
                _ => bonus_for_prev(prev)
            }
        }
        _ => 0.0
    }
}

fn bonus_for_prev(ch: char) -> f64 {
    match ch {
        '/' => SCORE_MATCH_SLASH,
        '-' | '_' | ' ' => SCORE_MATCH_WORD,
        '.' => SCORE_MATCH_DOT,
        _ => 0.0
    }
}

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

    #[test]
    fn test_compute_bonus() {
        assert_eq!(compute_bonus("a/b/c/d"), vec![0.9, 0.0, 0.9, 0.0, 0.9, 0.0, 0.9]);
        assert_eq!(compute_bonus("aTestString"), vec![0.9, 0.7, 0.0, 0.0, 0.0, 0.7, 0.0, 0.0, 0.0, 0.0, 0.0]);
    }

    #[test]
    fn test_for_char() {
        assert_eq!(for_char('*', '*'), 0.0);
        assert_eq!(for_char('a', 'a'), 0.0);

        assert_eq!(for_char('/', 'a'), SCORE_MATCH_SLASH);
        assert_eq!(for_char('/', 'A'), SCORE_MATCH_SLASH);
        assert_eq!(for_char('/', '0'), SCORE_MATCH_SLASH);

        assert_eq!(for_char('-', 'a'), SCORE_MATCH_WORD);
        assert_eq!(for_char('-', 'A'), SCORE_MATCH_WORD);
        assert_eq!(for_char('-', '0'), SCORE_MATCH_WORD);

        assert_eq!(for_char('_', 'a'), SCORE_MATCH_WORD);
        assert_eq!(for_char('_', 'A'), SCORE_MATCH_WORD);
        assert_eq!(for_char('_', '0'), SCORE_MATCH_WORD);

        assert_eq!(for_char(' ', 'a'), SCORE_MATCH_WORD);
        assert_eq!(for_char(' ', 'A'), SCORE_MATCH_WORD);
        assert_eq!(for_char(' ', '0'), SCORE_MATCH_WORD);

        assert_eq!(for_char('.', 'a'), SCORE_MATCH_DOT);
        assert_eq!(for_char('.', 'A'), SCORE_MATCH_DOT);
        assert_eq!(for_char('.', '0'), SCORE_MATCH_DOT);

        assert_eq!(for_char('a', 'A'), SCORE_MATCH_CAPITAL);
    }
}
<|endoftext|>


<commit_before>extern crate cargo;
extern crate env_logger;
extern crate git2_curl;
extern crate rustc_serialize;
extern crate toml;
#[macro_use] extern crate log;

use std::collections::BTreeSet;
use std::env;
use std::fs;
use std::io;
use std::path::{PathBuf, Path};
use std::process::Command;

use cargo::{execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::{CliError, CliResult, lev_distance, Config};

#[derive(RustcDecodable)]
struct Flags {
    flag_list: bool,
    flag_verbose: bool,
    flag_quiet: bool,
    flag_color: Option<String>,
    arg_command: String,
    arg_args: Vec<String>,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help          Display this message
    -V, --version       Print version info and exit
    --list              List installed commands
    -v, --verbose       Use verbose output
    -q, --quiet         No output printed to stdout
    --color WHEN        Coloring: auto, always, never

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    env_logger::init().unwrap();
    execute_main_without_stdin(execute, true, USAGE)
}

macro_rules! each_subcommand{ ($mac:ident) => ({
    $mac!(bench);
    $mac!(build);
    $mac!(clean);
    $mac!(doc);
    $mac!(fetch);
    $mac!(generate_lockfile);
    $mac!(git_checkout);
    $mac!(help);
    $mac!(install);
    $mac!(locate_project);
    $mac!(login);
    $mac!(new);
    $mac!(owner);
    $mac!(package);
    $mac!(pkgid);
    $mac!(publish);
    $mac!(read_manifest);
    $mac!(run);
    $mac!(rustc);
    $mac!(search);
    $mac!(test);
    $mac!(uninstall);
    $mac!(update);
    $mac!(verify_project);
    $mac!(version);
    $mac!(yank);
}) }

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
    try!(config.shell().set_verbosity(flags.flag_verbose, flags.flag_quiet));
    try!(config.shell().set_color_config(flags.flag_color.as_ref().map(|s| &s[..])));

    init_git_transports(config);

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands().into_iter() {
            println!("    {}", command);
        };
        return Ok(None)
    }

    let args = match &flags.arg_command[..] {
        // For the commands `cargo` and `cargo help`, re-execute ourselves as
        // `cargo -h` so we can go through the normal process of printing the
        // help message.
        "" | "help" if flags.arg_args.is_empty() => {
            config.shell().set_verbose(true);
            let args = &["cargo".to_string(), "-h".to_string()];
            let r = cargo::call_main_without_stdin(execute, config, USAGE, args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }

        // For `cargo help -h` and `cargo help --help`, print out the help
        // message for `cargo help`
        "help" if flags.arg_args[0] == "-h" ||
                  flags.arg_args[0] == "--help" => {
            vec!["cargo".to_string(), "help".to_string(), "-h".to_string()]
        }

        // For `cargo help foo`, print out the usage message for the specified
        // subcommand by executing the command with the `-h` flag.
        "help" => {
            vec!["cargo".to_string(), flags.arg_args[0].clone(),
                 "-h".to_string()]
        }

        // For all other invocations, we're of the form `cargo foo args...`. We
        // use the exact environment arguments to preserve tokens like `--` for
        // example.
        _ => env::args().collect(),
    };

    macro_rules! cmd{ ($name:ident) => (
        if args[1] == stringify!($name).replace("_", "-") {
            mod $name;
            config.shell().set_verbose(true);
            let r = cargo::call_main_without_stdin($name::execute, config,
                                                   $name::USAGE,
                                                   &args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }
    ) }
    each_subcommand!(cmd);

    execute_subcommand(&args[1], &args, &mut config.shell());
    Ok(None)
}

fn find_closest(cmd: &str) -> Option<String> {
    let cmds = list_commands();
    // Only consider candidates with a lev_distance of 3 or less so we don't
    // suggest out-of-the-blue options.
    let mut filtered = cmds.iter().map(|c| (lev_distance(&c, cmd), c))
                                  .filter(|&(d, _)| d < 4)
                                  .collect::<Vec<_>>();
    filtered.sort_by(|a, b| a.0.cmp(&b.0));

    if filtered.len() == 0 {
        None
    } else {
        Some(filtered[0].1.to_string())
    }
}

fn execute_subcommand(cmd: &str, args: &[String], shell: &mut MultiShell) {
    let command = match find_command(cmd) {
        Some(command) => command,
        None => {
            let msg = match find_closest(cmd) {
                Some(closest) => format!("No such subcommand\n\n\t\
                                          Did you mean `{}`?\n", closest),
                None => "No such subcommand".to_string()
            };
            return handle_error(CliError::new(&msg, 127), shell)
        }
    };
    match Command::new(&command).args(&args[1..]).status() {
        Ok(ref status) if status.success() => {}
        Ok(ref status) => {
            match status.code() {
                Some(code) => handle_error(CliError::new("", code), shell),
                None => {
                    let msg = format!("subcommand failed with: {}", status);
                    handle_error(CliError::new(&msg, 101), shell)
                }
            }
        }
        Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
            handle_error(CliError::new("No such subcommand", 127), shell)
        }
        Err(err) => {
            let msg = format!("Subcommand failed to run: {}", err);
            handle_error(CliError::new(&msg, 127), shell)
        }
    }
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands() -> BTreeSet<String> {
    let command_prefix = "cargo-";
    let mut commands = BTreeSet::new();
    for dir in list_command_directory().iter() {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries {
            let entry = match entry { Ok(e) => e, Err(..) => continue };
            let entry = entry.path();
            let filename = match entry.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue
            };
            if filename.starts_with(command_prefix) &&
               filename.ends_with(env::consts::EXE_SUFFIX) &&
               is_executable(&entry) {
                let command = &filename[
                    command_prefix.len()..
                    filename.len() - env::consts::EXE_SUFFIX.len()];
                commands.insert(command.to_string());
            }
        }
    }

    macro_rules! add_cmd{ ($cmd:ident) => ({
        commands.insert(stringify!($cmd).replace("_", "-"));
    }) }
    each_subcommand!(add_cmd);
    commands
}

#[cfg(unix)]
fn is_executable(path: &Path) -> bool {
    use std::os::unix::prelude::*;
    fs::metadata(path).map(|m| {
        m.permissions().mode() & 0o001 == 0o001
    }).unwrap_or(false)
}
#[cfg(windows)]
fn is_executable(path: &Path) -> bool {
    fs::metadata(path).map(|m| m.is_file()).unwrap_or(false)
}

/// Get `Command` to run given command.
fn find_command(cmd: &str) -> Option<PathBuf> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let dirs = list_command_directory();
    let mut command_paths = dirs.iter().map(|dir| dir.join(&command_exe));
    command_paths.find(|path| fs::metadata(&path).is_ok())
}

/// List candidate locations where subcommands might be installed.
fn list_command_directory() -> Vec<PathBuf> {
    let mut dirs = vec![];
    if let Ok(mut path) = env::current_exe() {
        path.pop();
        dirs.push(path.join("../lib/cargo"));
        dirs.push(path);
    }
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if a proxy is configured, right now libgit2
    // doesn't support proxies and we have to use a custom transport in this
    // case. The custom transport, however, is not as well battle-tested.
    match cargo::ops::http_proxy_exists(config) {
        Ok(true) => {}
        _ => return
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<commit_msg>add install help<commit_after>extern crate cargo;
extern crate env_logger;
extern crate git2_curl;
extern crate rustc_serialize;
extern crate toml;
#[macro_use] extern crate log;

use std::collections::BTreeSet;
use std::env;
use std::fs;
use std::io;
use std::path::{PathBuf, Path};
use std::process::Command;

use cargo::{execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::{CliError, CliResult, lev_distance, Config};

#[derive(RustcDecodable)]
struct Flags {
    flag_list: bool,
    flag_verbose: bool,
    flag_quiet: bool,
    flag_color: Option<String>,
    arg_command: String,
    arg_args: Vec<String>,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help          Display this message
    -V, --version       Print version info and exit
    --list              List installed commands
    -v, --verbose       Use verbose output
    -q, --quiet         No output printed to stdout
    --color WHEN        Coloring: auto, always, never

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates
    install     Install a Rust binary

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    env_logger::init().unwrap();
    execute_main_without_stdin(execute, true, USAGE)
}

macro_rules! each_subcommand{ ($mac:ident) => ({
    $mac!(bench);
    $mac!(build);
    $mac!(clean);
    $mac!(doc);
    $mac!(fetch);
    $mac!(generate_lockfile);
    $mac!(git_checkout);
    $mac!(help);
    $mac!(install);
    $mac!(locate_project);
    $mac!(login);
    $mac!(new);
    $mac!(owner);
    $mac!(package);
    $mac!(pkgid);
    $mac!(publish);
    $mac!(read_manifest);
    $mac!(run);
    $mac!(rustc);
    $mac!(search);
    $mac!(test);
    $mac!(uninstall);
    $mac!(update);
    $mac!(verify_project);
    $mac!(version);
    $mac!(yank);
}) }

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
    try!(config.shell().set_verbosity(flags.flag_verbose, flags.flag_quiet));
    try!(config.shell().set_color_config(flags.flag_color.as_ref().map(|s| &s[..])));

    init_git_transports(config);

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands().into_iter() {
            println!("    {}", command);
        };
        return Ok(None)
    }

    let args = match &flags.arg_command[..] {
        // For the commands `cargo` and `cargo help`, re-execute ourselves as
        // `cargo -h` so we can go through the normal process of printing the
        // help message.
        "" | "help" if flags.arg_args.is_empty() => {
            config.shell().set_verbose(true);
            let args = &["cargo".to_string(), "-h".to_string()];
            let r = cargo::call_main_without_stdin(execute, config, USAGE, args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }

        // For `cargo help -h` and `cargo help --help`, print out the help
        // message for `cargo help`
        "help" if flags.arg_args[0] == "-h" ||
                  flags.arg_args[0] == "--help" => {
            vec!["cargo".to_string(), "help".to_string(), "-h".to_string()]
        }

        // For `cargo help foo`, print out the usage message for the specified
        // subcommand by executing the command with the `-h` flag.
        "help" => {
            vec!["cargo".to_string(), flags.arg_args[0].clone(),
                 "-h".to_string()]
        }

        // For all other invocations, we're of the form `cargo foo args...`. We
        // use the exact environment arguments to preserve tokens like `--` for
        // example.
        _ => env::args().collect(),
    };

    macro_rules! cmd{ ($name:ident) => (
        if args[1] == stringify!($name).replace("_", "-") {
            mod $name;
            config.shell().set_verbose(true);
            let r = cargo::call_main_without_stdin($name::execute, config,
                                                   $name::USAGE,
                                                   &args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }
    ) }
    each_subcommand!(cmd);

    execute_subcommand(&args[1], &args, &mut config.shell());
    Ok(None)
}

fn find_closest(cmd: &str) -> Option<String> {
    let cmds = list_commands();
    // Only consider candidates with a lev_distance of 3 or less so we don't
    // suggest out-of-the-blue options.
    let mut filtered = cmds.iter().map(|c| (lev_distance(&c, cmd), c))
                                  .filter(|&(d, _)| d < 4)
                                  .collect::<Vec<_>>();
    filtered.sort_by(|a, b| a.0.cmp(&b.0));

    if filtered.len() == 0 {
        None
    } else {
        Some(filtered[0].1.to_string())
    }
}

fn execute_subcommand(cmd: &str, args: &[String], shell: &mut MultiShell) {
    let command = match find_command(cmd) {
        Some(command) => command,
        None => {
            let msg = match find_closest(cmd) {
                Some(closest) => format!("No such subcommand\n\n\t\
                                          Did you mean `{}`?\n", closest),
                None => "No such subcommand".to_string()
            };
            return handle_error(CliError::new(&msg, 127), shell)
        }
    };
    match Command::new(&command).args(&args[1..]).status() {
        Ok(ref status) if status.success() => {}
        Ok(ref status) => {
            match status.code() {
                Some(code) => handle_error(CliError::new("", code), shell),
                None => {
                    let msg = format!("subcommand failed with: {}", status);
                    handle_error(CliError::new(&msg, 101), shell)
                }
            }
        }
        Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
            handle_error(CliError::new("No such subcommand", 127), shell)
        }
        Err(err) => {
            let msg = format!("Subcommand failed to run: {}", err);
            handle_error(CliError::new(&msg, 127), shell)
        }
    }
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands() -> BTreeSet<String> {
    let command_prefix = "cargo-";
    let mut commands = BTreeSet::new();
    for dir in list_command_directory().iter() {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries {
            let entry = match entry { Ok(e) => e, Err(..) => continue };
            let entry = entry.path();
            let filename = match entry.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue
            };
            if filename.starts_with(command_prefix) &&
               filename.ends_with(env::consts::EXE_SUFFIX) &&
               is_executable(&entry) {
                let command = &filename[
                    command_prefix.len()..
                    filename.len() - env::consts::EXE_SUFFIX.len()];
                commands.insert(command.to_string());
            }
        }
    }

    macro_rules! add_cmd{ ($cmd:ident) => ({
        commands.insert(stringify!($cmd).replace("_", "-"));
    }) }
    each_subcommand!(add_cmd);
    commands
}

#[cfg(unix)]
fn is_executable(path: &Path) -> bool {
    use std::os::unix::prelude::*;
    fs::metadata(path).map(|m| {
        m.permissions().mode() & 0o001 == 0o001
    }).unwrap_or(false)
}
#[cfg(windows)]
fn is_executable(path: &Path) -> bool {
    fs::metadata(path).map(|m| m.is_file()).unwrap_or(false)
}

/// Get `Command` to run given command.
fn find_command(cmd: &str) -> Option<PathBuf> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let dirs = list_command_directory();
    let mut command_paths = dirs.iter().map(|dir| dir.join(&command_exe));
    command_paths.find(|path| fs::metadata(&path).is_ok())
}

/// List candidate locations where subcommands might be installed.
fn list_command_directory() -> Vec<PathBuf> {
    let mut dirs = vec![];
    if let Ok(mut path) = env::current_exe() {
        path.pop();
        dirs.push(path.join("../lib/cargo"));
        dirs.push(path);
    }
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if a proxy is configured, right now libgit2
    // doesn't support proxies and we have to use a custom transport in this
    // case. The custom transport, however, is not as well battle-tested.
    match cargo::ops::http_proxy_exists(config) {
        Ok(true) => {}
        _ => return
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate num;
use std::ptr;
use std::str;
use std::ffi::CStr;
use std::fmt::{Display, Debug, Formatter, Error};
use ffi::cs_free;
use num::FromPrimitive;
use constants::*;

/// Representation of the array of instructions returned by disasm
pub struct Instructions {
    ptr: *const Insn,
    len: isize,
}

impl Instructions {
    pub unsafe fn from_raw_parts(ptr: *const Insn, len: isize) -> Instructions {
        Instructions { ptr: ptr, len: len }
    }

    pub fn len(&self) -> isize {
        self.len
    }

    pub fn iter(&self) -> InstructionIterator {
        InstructionIterator {
            insns: &self,
            cur: 0,
        }
    }
}

impl Drop for Instructions {
    fn drop(&mut self) {
        unsafe {
            cs_free(self.ptr, self.len as libc::size_t);
        }
    }
}

/// An iterator over the instructions returned by disasm
///
/// This is currently the only supported interface for reading them.
pub struct InstructionIterator<'a> {
    insns: &'a Instructions,
    cur: isize,
}

impl<'a> Iterator for InstructionIterator<'a> {
    type Item = Insn;

    fn next(&mut self) -> Option<Insn> {
        if self.cur == self.insns.len {
            None
        } else {
            let obj = unsafe { self.insns.ptr.offset(self.cur) };
            self.cur += 1;
            Some(unsafe { ptr::read(obj) })
        }
    }
}

#[repr(C)]
/// A logical instruction disassembled by capstone
pub struct Insn {
    id: ::libc::c_uint,
    pub address: u64,
    pub size: u16,
    bytes: [u8; 16usize],
    mnemonic: [::libc::c_char; 32usize],
    op_str: [::libc::c_char; 160usize],
    detail: *mut CsDetail,
}

impl Insn {
    /// The mnemonic for the instruction
    pub fn mnemonic(&self) -> Option<&str> {
        let cstr = unsafe { CStr::from_ptr(self.mnemonic.as_ptr()) };
        str::from_utf8(cstr.to_bytes()).ok()
    }

    /// The operand string associated with the instruction
    pub fn op_str(&self) -> Option<&str> {
        let cstr = unsafe { CStr::from_ptr(self.op_str.as_ptr()) };
        str::from_utf8(cstr.to_bytes()).ok()
    }

    /// Access instruction id
    pub fn id(&self) -> libc::c_uint {
        self.id
    }

    /// Access instruction bytes
    pub fn bytes(&self) -> &[u8] {
        &self.bytes[0..(self.size as usize)]
    }

    // Should be private, but then we could not access it from other modules
    #[doc(hidden)]
    /// Returns instruction details
    pub fn detail(&self) -> *mut CsDetail {
        self.detail
    }
}

impl Debug for Insn {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        fmt.debug_struct("Insn")
            .field("address", &self.address)
            .field("size", &self.size)
            .field("mnemonic", &self.mnemonic())
            .field("op_str", &self.op_str())
            .finish()
    }
}

impl Display for Insn {
    #[allow(unused_must_use)]
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        write!(fmt, "{:#x}: ", self.address);
        if let Some(mnemonic) = self.mnemonic() {
            write!(fmt, "{} ", mnemonic);
            if let Some(op_str) = self.op_str() {
                write!(fmt, "{}", op_str);
            }
        }
        Ok(())
    }
}

#[repr(C)]
/// Represents details for instruction
///
/// Only available if disassembled with details.
pub struct CsDetail {
    regs_read: [u8; 12usize], // list of implicit registers read by this insn
    regs_read_count: u8, // number of implicit registers read by this insn
    regs_write: [u8; 20usize], // list of implicit registers modified by this insn
    regs_write_count: u8, // number of implicit registers modified by this insn
    groups: [u8; 8usize], // list of group this instruction belong to
    groups_count: u8, // number of groups this insn belongs to
}

impl CsDetail {
    /// Return ids of implicit read registers
    pub fn regs_read_ids(&self) -> &[u8] {
        &self.regs_read[..self.regs_read_count as usize]
    }

    /// Return ids of implicit write registers
    pub fn regs_write_ids(&self) -> &[u8] {
        &self.regs_write[..self.regs_write_count as usize]
    }

    /// Return ids of instruction groups to which instructions belong
    pub fn groups_ids(&self) -> &[u8] {
        &self.groups[..self.groups_count as usize]
    }

    /// Return architecture-independent instruction groups
    pub fn groups(&self) -> Vec<CsGroupType> {
        // Ignore integer values for which there is no CsGroupType because they are
        // architecture-specific
        self.groups_ids()
            .iter()
            .filter_map(|&x| CsGroupType::from_u8(x))
            .collect()
    }
}
<commit_msg>Add struct field doc comments<commit_after>extern crate libc;
extern crate num;
use std::ptr;
use std::str;
use std::ffi::CStr;
use std::fmt::{Display, Debug, Formatter, Error};
use ffi::cs_free;
use num::FromPrimitive;
use constants::*;

/// Representation of the array of instructions returned by disasm
pub struct Instructions {
    ptr: *const Insn,
    len: isize,
}

impl Instructions {
    pub unsafe fn from_raw_parts(ptr: *const Insn, len: isize) -> Instructions {
        Instructions { ptr: ptr, len: len }
    }

    pub fn len(&self) -> isize {
        self.len
    }

    pub fn iter(&self) -> InstructionIterator {
        InstructionIterator {
            insns: &self,
            cur: 0,
        }
    }
}

impl Drop for Instructions {
    fn drop(&mut self) {
        unsafe {
            cs_free(self.ptr, self.len as libc::size_t);
        }
    }
}

/// An iterator over the instructions returned by disasm
///
/// This is currently the only supported interface for reading them.
pub struct InstructionIterator<'a> {
    insns: &'a Instructions,
    cur: isize,
}

impl<'a> Iterator for InstructionIterator<'a> {
    type Item = Insn;

    fn next(&mut self) -> Option<Insn> {
        if self.cur == self.insns.len {
            None
        } else {
            let obj = unsafe { self.insns.ptr.offset(self.cur) };
            self.cur += 1;
            Some(unsafe { ptr::read(obj) })
        }
    }
}

#[repr(C)]
/// A logical instruction disassembled by capstone
pub struct Insn {
    /// Instruction ID (numeric ID for the instruction mnemonic)
    ///
    /// This information is available when Detail is disabled.
    /// NOTE: in Skipdata mode, "data" instruction has 0 for this id field.
    id: ::libc::c_uint,

    /// Address of this instruction
    ///
    /// This information is available when Detail is disabled.
    pub address: u64,

    /// Size of this instruction
    ///
    /// This information is available when Detail is disabled.
    pub size: u16,

    /// Machine bytes of this instruction, with number of bytes indicated by @size above.
    ///
    /// This information is available when Detail is disabled.
    bytes: [u8; 16usize],

    /// Ascii text of instruction mnemonic
    ///
    /// This information is available when Detail is disabled.
    mnemonic: [::libc::c_char; 32usize],

    /// Ascii text of instruction operands
    ///
    /// This information is available when Detail is disabled.
    op_str: [::libc::c_char; 160usize],

    /// Pointer to `CsDetail`
    ///
    /// NOTE 1: detail pointer is only valid when both requirements below are met:
    ///     1. Detail is enabled
    ///     2. Engine is not in Skipdata mode
    ///
    /// NOTE 2: when in Skipdata mode, or when detail mode is OFF, even if this pointer is not
    /// NULL, its content is still irrelevant.
    detail: *mut CsDetail,
}

impl Insn {
    /// The mnemonic for the instruction
    pub fn mnemonic(&self) -> Option<&str> {
        let cstr = unsafe { CStr::from_ptr(self.mnemonic.as_ptr()) };
        str::from_utf8(cstr.to_bytes()).ok()
    }

    /// The operand string associated with the instruction
    pub fn op_str(&self) -> Option<&str> {
        let cstr = unsafe { CStr::from_ptr(self.op_str.as_ptr()) };
        str::from_utf8(cstr.to_bytes()).ok()
    }

    /// Access instruction id
    pub fn id(&self) -> libc::c_uint {
        self.id
    }

    /// Access instruction bytes
    pub fn bytes(&self) -> &[u8] {
        &self.bytes[0..(self.size as usize)]
    }

    // Should be private, but then we could not access it from other modules
    #[doc(hidden)]
    /// Returns instruction details
    pub fn detail(&self) -> *mut CsDetail {
        self.detail
    }
}

impl Debug for Insn {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        fmt.debug_struct("Insn")
            .field("address", &self.address)
            .field("size", &self.size)
            .field("mnemonic", &self.mnemonic())
            .field("op_str", &self.op_str())
            .finish()
    }
}

impl Display for Insn {
    #[allow(unused_must_use)]
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        write!(fmt, "{:#x}: ", self.address);
        if let Some(mnemonic) = self.mnemonic() {
            write!(fmt, "{} ", mnemonic);
            if let Some(op_str) = self.op_str() {
                write!(fmt, "{}", op_str);
            }
        }
        Ok(())
    }
}

#[repr(C)]
/// Represents details for instruction
///
/// Only available if disassembled with details.
pub struct CsDetail {
    /// Ids of implicit registers read by this instruction
    regs_read: [u8; 12usize],

    /// Number of implicit registers read by this instruction
    regs_read_count: u8,

    /// Ids of implicit registers modified by this instruction
    regs_write: [u8; 20usize],

    /// Number of implicit registers modified by this instruction
    regs_write_count: u8,

    /// Ids of groups this instruction belongs to
    groups: [u8; 8usize],

    /// Number of groups this instruction belongs to
    groups_count: u8,
}

impl CsDetail {
    /// Return ids of implicit read registers
    pub fn regs_read_ids(&self) -> &[u8] {
        &self.regs_read[..self.regs_read_count as usize]
    }

    /// Return ids of implicit write registers
    pub fn regs_write_ids(&self) -> &[u8] {
        &self.regs_write[..self.regs_write_count as usize]
    }

    /// Return ids of instruction groups to which instructions belong
    pub fn groups_ids(&self) -> &[u8] {
        &self.groups[..self.groups_count as usize]
    }

    /// Return architecture-independent instruction groups
    pub fn groups(&self) -> Vec<CsGroupType> {
        // Ignore integer values for which there is no CsGroupType because they are
        // architecture-specific
        self.groups_ids()
            .iter()
            .filter_map(|&x| CsGroupType::from_u8(x))
            .collect()
    }
}
<|endoftext|>