<commit_before>use std::ops;
use std::{f64, i32};

use glib::object::ObjectClass;
use glib::subclass;
use glib::subclass::object::ObjectClassSubclassExt;
use glib::subclass::prelude::*;
use glib::translate::*;
use glib::{ParamFlags, ParamSpec};

use glib_sys;
use gobject_sys;

use handle::Handle;

extern "C" {
    fn rsvg_handle_flags_get_type() -> glib_sys::GType;
}

// Keep this in sync with rsvg.h:RsvgHandleClass
#[repr(C)]
pub struct RsvgHandleClass {
    parent: gobject_sys::GObjectClass,

    _abi_padding: [glib_sys::gpointer; 15],
}

// Keep this in sync with rsvg.h:RsvgHandle
#[repr(C)]
pub struct RsvgHandle {
    parent: gobject_sys::GObject,

    _abi_padding: [glib_sys::gpointer; 16],
}

unsafe impl ClassStruct for RsvgHandleClass {
    type Type = Handle;
}

unsafe impl InstanceStruct for RsvgHandle {
    type Type = Handle;
}

impl ops::Deref for RsvgHandleClass {
    type Target = ObjectClass;

    fn deref(&self) -> &Self::Target {
        unsafe { &*(self as *const _ as *const Self::Target) }
    }
}

impl ops::DerefMut for RsvgHandleClass {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { &mut *(self as *mut _ as *mut Self::Target) }
    }
}

static PROPERTIES: [subclass::Property; 11] = [
    subclass::Property("flags", |name| {
        ParamSpec::flags(
            name,
            "Flags",
            "Loading flags",
            from_glib(unsafe { rsvg_handle_flags_get_type() }),
            0,
            ParamFlags::READWRITE | ParamFlags::CONSTRUCT_ONLY,
        )
    }),
    subclass::Property("dpi-x", |name| {
        ParamSpec::double(
            name,
            "Horizontal DPI",
            "Horizontal resolution in dots per inch",
            0.0,
            f64::MAX,
            0.0,
            ParamFlags::READWRITE | ParamFlags::CONSTRUCT,
        )
    }),
    subclass::Property("dpi-y", |name| {
        ParamSpec::double(
            name,
            "Vertical DPI",
            "Vertical resolution in dots per inch",
            0.0,
            f64::MAX,
            0.0,
            ParamFlags::READWRITE | ParamFlags::CONSTRUCT,
        )
    }),
    subclass::Property("base-uri", |name| {
        ParamSpec::string(
            name,
            "Base URI",
            "Base URI for resolving relative references",
            None,
            ParamFlags::READWRITE | ParamFlags::CONSTRUCT,
        )
    }),
    subclass::Property("width", |name| {
        ParamSpec::int(
            name,
            "Image width",
            "Image width",
            0,
            i32::MAX,
            0,
            ParamFlags::READABLE,
        )
    }),
    subclass::Property("height", |name| {
        ParamSpec::int(
            name,
            "Image height",
            "Image height",
            0,
            i32::MAX,
            0,
            ParamFlags::READABLE,
        )
    }),
    subclass::Property("em", |name| {
        ParamSpec::double(name, "em", "em", 0.0, f64::MAX, 0.0, ParamFlags::READABLE)
    }),
    subclass::Property("ex", |name| {
        ParamSpec::double(name, "ex", "ex", 0.0, f64::MAX, 0.0, ParamFlags::READABLE)
    }),
    subclass::Property("title", |name| {
        ParamSpec::string(name, "deprecated", "deprecated", None, ParamFlags::READABLE)
    }),
    subclass::Property("desc", |name| {
        ParamSpec::string(name, "deprecated", "deprecated", None, ParamFlags::READABLE)
    }),
    subclass::Property("metadata", |name| {
        ParamSpec::string(name, "deprecated", "deprecated", None, ParamFlags::READABLE)
    }),
];

impl ObjectSubclass for Handle {
    const NAME: &'static str = "RsvgHandle";

    type ParentType = glib::Object;

    // We don't use subclass:simple::InstanceStruct and ClassStruct
    // because we need to maintain the respective _abi_padding of each
    // of RsvgHandleClass and RsvgHandle.

    type Instance = RsvgHandle;
    type Class = RsvgHandleClass;

    glib_object_subclass!();

    fn class_init(klass: &mut RsvgHandleClass) {
        klass.install_properties(&PROPERTIES);
    }

    fn new() -> Self {
        Handle::new()
    }
}

impl ObjectImpl for Handle {
    glib_object_impl!();

    fn set_property(&self, _obj: &glib::Object, id: usize, value: &glib::Value) {
        let prop = &PROPERTIES[id];

        match *prop {
            subclass::Property("flags", ..) => {
                self.set_load_flags(value.get().expect("flags value has incorrect type"));
            }

            subclass::Property("dpi-x", ..) => {
                self.set_dpi_x(value.get().expect("dpi-x value has incorrect type"));
            }

            subclass::Property("dpi-y", ..) => {
                self.set_dpi_y(value.get().expect("dpi-y value has incorrect type"));
            }

            subclass::Property("base-uri", ..) => {
                self.set_base_url(value.get().expect("base-uri should be a non-NULL string"));
            }

            _ => unreachable!("invalid property id {}", id),
        }
    }

    fn get_property(&self, _obj: &glib::Object, id: usize) -> Result<glib::Value, ()> {
        //         let prop = &PROPERTIES[id];
        //
        //         match *prop {
        //             subclass::Property("name", ..) => Ok(self.name.borrow().to_value()),
        //             _ => unimplemented!(),
        //         }
        unimplemented!();
    }

    fn constructed(&self, obj: &glib::Object) {
        //         // Chain up to the parent type's implementation of this virtual
        //         // method.
        //         self.parent_constructed(obj);
        //
        //         // And here we could do our own initialization.
        unimplemented!();
    }
}
<commit_msg>Handle::get_property() - Implement<commit_after>use std::ops;
use std::{f64, i32};

use glib::object::ObjectClass;
use glib::subclass;
use glib::subclass::object::ObjectClassSubclassExt;
use glib::subclass::prelude::*;
use glib::translate::*;
use glib::{ParamFlags, ParamSpec, ToValue};

use glib_sys;
use gobject_sys;

use handle::Handle;

extern "C" {
    fn rsvg_handle_flags_get_type() -> glib_sys::GType;
}

// Keep this in sync with rsvg.h:RsvgHandleClass
#[repr(C)]
pub struct RsvgHandleClass {
    parent: gobject_sys::GObjectClass,

    _abi_padding: [glib_sys::gpointer; 15],
}

// Keep this in sync with rsvg.h:RsvgHandle
#[repr(C)]
pub struct RsvgHandle {
    parent: gobject_sys::GObject,

    _abi_padding: [glib_sys::gpointer; 16],
}

unsafe impl ClassStruct for RsvgHandleClass {
    type Type = Handle;
}

unsafe impl InstanceStruct for RsvgHandle {
    type Type = Handle;
}

impl ops::Deref for RsvgHandleClass {
    type Target = ObjectClass;

    fn deref(&self) -> &Self::Target {
        unsafe { &*(self as *const _ as *const Self::Target) }
    }
}

impl ops::DerefMut for RsvgHandleClass {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { &mut *(self as *mut _ as *mut Self::Target) }
    }
}

static PROPERTIES: [subclass::Property; 11] = [
    subclass::Property("flags", |name| {
        ParamSpec::flags(
            name,
            "Flags",
            "Loading flags",
            from_glib(unsafe { rsvg_handle_flags_get_type() }),
            0,
            ParamFlags::READWRITE | ParamFlags::CONSTRUCT_ONLY,
        )
    }),
    subclass::Property("dpi-x", |name| {
        ParamSpec::double(
            name,
            "Horizontal DPI",
            "Horizontal resolution in dots per inch",
            0.0,
            f64::MAX,
            0.0,
            ParamFlags::READWRITE | ParamFlags::CONSTRUCT,
        )
    }),
    subclass::Property("dpi-y", |name| {
        ParamSpec::double(
            name,
            "Vertical DPI",
            "Vertical resolution in dots per inch",
            0.0,
            f64::MAX,
            0.0,
            ParamFlags::READWRITE | ParamFlags::CONSTRUCT,
        )
    }),
    subclass::Property("base-uri", |name| {
        ParamSpec::string(
            name,
            "Base URI",
            "Base URI for resolving relative references",
            None,
            ParamFlags::READWRITE | ParamFlags::CONSTRUCT,
        )
    }),
    subclass::Property("width", |name| {
        ParamSpec::int(
            name,
            "Image width",
            "Image width",
            0,
            i32::MAX,
            0,
            ParamFlags::READABLE,
        )
    }),
    subclass::Property("height", |name| {
        ParamSpec::int(
            name,
            "Image height",
            "Image height",
            0,
            i32::MAX,
            0,
            ParamFlags::READABLE,
        )
    }),
    subclass::Property("em", |name| {
        ParamSpec::double(name, "em", "em", 0.0, f64::MAX, 0.0, ParamFlags::READABLE)
    }),
    subclass::Property("ex", |name| {
        ParamSpec::double(name, "ex", "ex", 0.0, f64::MAX, 0.0, ParamFlags::READABLE)
    }),
    subclass::Property("title", |name| {
        ParamSpec::string(name, "deprecated", "deprecated", None, ParamFlags::READABLE)
    }),
    subclass::Property("desc", |name| {
        ParamSpec::string(name, "deprecated", "deprecated", None, ParamFlags::READABLE)
    }),
    subclass::Property("metadata", |name| {
        ParamSpec::string(name, "deprecated", "deprecated", None, ParamFlags::READABLE)
    }),
];

impl ObjectSubclass for Handle {
    const NAME: &'static str = "RsvgHandle";

    type ParentType = glib::Object;

    // We don't use subclass:simple::InstanceStruct and ClassStruct
    // because we need to maintain the respective _abi_padding of each
    // of RsvgHandleClass and RsvgHandle.

    type Instance = RsvgHandle;
    type Class = RsvgHandleClass;

    glib_object_subclass!();

    fn class_init(klass: &mut RsvgHandleClass) {
        klass.install_properties(&PROPERTIES);
    }

    fn new() -> Self {
        Handle::new()
    }
}

impl ObjectImpl for Handle {
    glib_object_impl!();

    fn set_property(&self, _obj: &glib::Object, id: usize, value: &glib::Value) {
        let prop = &PROPERTIES[id];

        match *prop {
            subclass::Property("flags", ..) => {
                self.set_load_flags(value.get().expect("flags value has incorrect type"));
            }

            subclass::Property("dpi-x", ..) => {
                self.set_dpi_x(value.get().expect("dpi-x value has incorrect type"));
            }

            subclass::Property("dpi-y", ..) => {
                self.set_dpi_y(value.get().expect("dpi-y value has incorrect type"));
            }

            subclass::Property("base-uri", ..) => {
                self.set_base_url(value.get().expect("base-uri should be a non-NULL string"));
            }

            _ => unreachable!("invalid property id {}", id),
        }
    }

    fn get_property(&self, _obj: &glib::Object, id: usize) -> Result<glib::Value, ()> {
        let prop = &PROPERTIES[id];

        match *prop {
            subclass::Property("flags", ..) => Ok(self.load_flags.get().to_flags().to_value()),
            subclass::Property("dpi-x", ..) => Ok(self.dpi.get().x().to_value()),
            subclass::Property("dpi-y", ..) => Ok(self.dpi.get().y().to_value()),

            subclass::Property("base-uri", ..) => Ok(self
                .base_url
               .borrow()
                .as_ref()
                .map(|url| url.as_str())
                .to_value()),

            subclass::Property("width", ..) => Ok(self.get_dimensions_no_error().width.to_value()),
            subclass::Property("height", ..) => {
                Ok(self.get_dimensions_no_error().height.to_value())
            }

            subclass::Property("em", ..) => Ok(self.get_dimensions_no_error().em.to_value()),
            subclass::Property("ex", ..) => Ok(self.get_dimensions_no_error().ex.to_value()),

            subclass::Property("title", ..) => Ok("".to_value()), // deprecated
            subclass::Property("desc", ..) => Ok("".to_value()),  // deprecated
            subclass::Property("metadata", ..) => Ok("".to_value()), // deprecated

            _ => unreachable!("invalid property id={} for RsvgHandle", id),
        }
    }

    fn constructed(&self, obj: &glib::Object) {
        //         // Chain up to the parent type's implementation of this virtual
        //         // method.
        //         self.parent_constructed(obj);
        //
        //         // And here we could do our own initialization.
        unimplemented!();
    }
}
<|endoftext|>


<commit_before>//! FIXME: write short doc here

use std::path::{Path, PathBuf};

use cargo_metadata::{CargoOpt, MetadataCommand};
use ra_arena::{impl_arena_id, Arena, RawId};
use ra_db::Edition;
use rustc_hash::FxHashMap;
use serde::Deserialize;

use crate::Result;

/// `CargoWorkspace` represents the logical structure of, well, a Cargo
/// workspace. It pretty closely mirrors `cargo metadata` output.
///
/// Note that internally, rust analyzer uses a different structure:
/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates,
/// while this knows about `Packages` & `Targets`: purely cargo-related
/// concepts.
#[derive(Debug, Clone)]
pub struct CargoWorkspace {
    packages: Arena<Package, PackageData>,
    targets: Arena<Target, TargetData>,
    pub(crate) workspace_root: PathBuf,
}

#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
#[serde(rename_all = "camelCase", default)]
pub struct CargoFeatures {
    /// Do not activate the `default` feature.
    pub no_default_features: bool,

    /// Activate all available features
    pub all_features: bool,

    /// List of features to activate.
    /// This will be ignored if `cargo_all_features` is true.
    pub features: Vec<String>,
}

impl Default for CargoFeatures {
    fn default() -> Self {
        CargoFeatures { no_default_features: false, all_features: true, features: Vec::new() }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Package(RawId);
impl_arena_id!(Package);

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Target(RawId);
impl_arena_id!(Target);

#[derive(Debug, Clone)]
struct PackageData {
    name: String,
    manifest: PathBuf,
    targets: Vec<Target>,
    is_member: bool,
    dependencies: Vec<PackageDependency>,
    edition: Edition,
    features: Vec<String>,
}

#[derive(Debug, Clone)]
pub struct PackageDependency {
    pub pkg: Package,
    pub name: String,
}

#[derive(Debug, Clone)]
struct TargetData {
    pkg: Package,
    name: String,
    root: PathBuf,
    kind: TargetKind,
    is_proc_macro: bool,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TargetKind {
    Bin,
    /// Any kind of Cargo lib crate-type (dylib, rlib, proc-macro, ...).
    Lib,
    Example,
    Test,
    Bench,
    Other,
}

impl TargetKind {
    fn new(kinds: &[String]) -> TargetKind {
        for kind in kinds {
            return match kind.as_str() {
                "bin" => TargetKind::Bin,
                "test" => TargetKind::Test,
                "bench" => TargetKind::Bench,
                "example" => TargetKind::Example,
                "proc-macro" => TargetKind::Lib,
                _ if kind.contains("lib") => TargetKind::Lib,
                _ => continue,
            };
        }
        TargetKind::Other
    }
}

impl Package {
    pub fn name(self, ws: &CargoWorkspace) -> &str {
        ws.packages[self].name.as_str()
    }
    pub fn root(self, ws: &CargoWorkspace) -> &Path {
        ws.packages[self].manifest.parent().unwrap()
    }
    pub fn edition(self, ws: &CargoWorkspace) -> Edition {
        ws.packages[self].edition
    }
    pub fn features(self, ws: &CargoWorkspace) -> &[String] {
        &ws.packages[self].features
    }
    pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator<Item = Target> + 'a {
        ws.packages[self].targets.iter().cloned()
    }
    #[allow(unused)]
    pub fn is_member(self, ws: &CargoWorkspace) -> bool {
        ws.packages[self].is_member
    }
    pub fn dependencies<'a>(
        self,
        ws: &'a CargoWorkspace,
    ) -> impl Iterator<Item = &'a PackageDependency> + 'a {
        ws.packages[self].dependencies.iter()
    }
}

impl Target {
    pub fn package(self, ws: &CargoWorkspace) -> Package {
        ws.targets[self].pkg
    }
    pub fn name(self, ws: &CargoWorkspace) -> &str {
        ws.targets[self].name.as_str()
    }
    pub fn root(self, ws: &CargoWorkspace) -> &Path {
        ws.targets[self].root.as_path()
    }
    pub fn kind(self, ws: &CargoWorkspace) -> TargetKind {
        ws.targets[self].kind
    }
    pub fn is_proc_macro(self, ws: &CargoWorkspace) -> bool {
        ws.targets[self].is_proc_macro
    }
}

impl CargoWorkspace {
    pub fn from_cargo_metadata(
        cargo_toml: &Path,
        cargo_features: &CargoFeatures,
    ) -> Result<CargoWorkspace> {
        let mut meta = MetadataCommand::new();
        meta.manifest_path(cargo_toml);
        if cargo_features.all_features {
            meta.features(CargoOpt::AllFeatures);
        } else if cargo_features.no_default_features {
            // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
            // https://github.com/oli-obk/cargo_metadata/issues/79
            meta.features(CargoOpt::NoDefaultFeatures);
        } else {
            meta.features(CargoOpt::SomeFeatures(cargo_features.features.clone()));
        }
        if let Some(parent) = cargo_toml.parent() {
            meta.current_dir(parent);
        }
        let meta = meta.exec().map_err(|e| format!("cargo metadata failed: {}", e))?;
        let mut pkg_by_id = FxHashMap::default();
        let mut packages = Arena::default();
        let mut targets = Arena::default();

        let ws_members = &meta.workspace_members;

        for meta_pkg in meta.packages {
            let cargo_metadata::Package { id, edition, name, manifest_path, .. } = meta_pkg;
            let is_member = ws_members.contains(&id);
            let edition = edition.parse::<Edition>()?;
            let pkg = packages.alloc(PackageData {
                name,
                manifest: manifest_path,
                targets: Vec::new(),
                is_member,
                edition,
                dependencies: Vec::new(),
                features: Vec::new(),
            });
            let pkg_data = &mut packages[pkg];
            pkg_by_id.insert(id, pkg);
            for meta_tgt in meta_pkg.targets {
                let is_proc_macro = meta_tgt.kind.as_slice() == &["proc-macro"];
                let tgt = targets.alloc(TargetData {
                    pkg,
                    name: meta_tgt.name,
                    root: meta_tgt.src_path.clone(),
                    kind: TargetKind::new(meta_tgt.kind.as_slice()),
                    is_proc_macro,
                });
                pkg_data.targets.push(tgt);
            }
        }
        let resolve = meta.resolve.expect("metadata executed with deps");
        for node in resolve.nodes {
            let source = pkg_by_id[&node.id];
            for dep_node in node.deps {
                let dep = PackageDependency { name: dep_node.name, pkg: pkg_by_id[&dep_node.pkg] };
                packages[source].dependencies.push(dep);
            }
            packages[source].features.extend(node.features);
        }

        Ok(CargoWorkspace { packages, targets, workspace_root: meta.workspace_root })
    }

    pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + ExactSizeIterator + 'a {
        self.packages.iter().map(|(id, _pkg)| id)
    }

    pub fn target_by_root(&self, root: &Path) -> Option<Target> {
        self.packages().filter_map(|pkg| pkg.targets(self).find(|it| it.root(self) == root)).next()
    }
}
<commit_msg>Only add features flags if non-empty<commit_after>//! FIXME: write short doc here

use std::path::{Path, PathBuf};

use cargo_metadata::{CargoOpt, MetadataCommand};
use ra_arena::{impl_arena_id, Arena, RawId};
use ra_db::Edition;
use rustc_hash::FxHashMap;
use serde::Deserialize;

use crate::Result;

/// `CargoWorkspace` represents the logical structure of, well, a Cargo
/// workspace. It pretty closely mirrors `cargo metadata` output.
///
/// Note that internally, rust analyzer uses a different structure:
/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates,
/// while this knows about `Packages` & `Targets`: purely cargo-related
/// concepts.
#[derive(Debug, Clone)]
pub struct CargoWorkspace {
    packages: Arena<Package, PackageData>,
    targets: Arena<Target, TargetData>,
    pub(crate) workspace_root: PathBuf,
}

#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
#[serde(rename_all = "camelCase", default)]
pub struct CargoFeatures {
    /// Do not activate the `default` feature.
    pub no_default_features: bool,

    /// Activate all available features
    pub all_features: bool,

    /// List of features to activate.
    /// This will be ignored if `cargo_all_features` is true.
    pub features: Vec<String>,
}

impl Default for CargoFeatures {
    fn default() -> Self {
        CargoFeatures { no_default_features: false, all_features: true, features: Vec::new() }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Package(RawId);
impl_arena_id!(Package);

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Target(RawId);
impl_arena_id!(Target);

#[derive(Debug, Clone)]
struct PackageData {
    name: String,
    manifest: PathBuf,
    targets: Vec<Target>,
    is_member: bool,
    dependencies: Vec<PackageDependency>,
    edition: Edition,
    features: Vec<String>,
}

#[derive(Debug, Clone)]
pub struct PackageDependency {
    pub pkg: Package,
    pub name: String,
}

#[derive(Debug, Clone)]
struct TargetData {
    pkg: Package,
    name: String,
    root: PathBuf,
    kind: TargetKind,
    is_proc_macro: bool,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TargetKind {
    Bin,
    /// Any kind of Cargo lib crate-type (dylib, rlib, proc-macro, ...).
    Lib,
    Example,
    Test,
    Bench,
    Other,
}

impl TargetKind {
    fn new(kinds: &[String]) -> TargetKind {
        for kind in kinds {
            return match kind.as_str() {
                "bin" => TargetKind::Bin,
                "test" => TargetKind::Test,
                "bench" => TargetKind::Bench,
                "example" => TargetKind::Example,
                "proc-macro" => TargetKind::Lib,
                _ if kind.contains("lib") => TargetKind::Lib,
                _ => continue,
            };
        }
        TargetKind::Other
    }
}

impl Package {
    pub fn name(self, ws: &CargoWorkspace) -> &str {
        ws.packages[self].name.as_str()
    }
    pub fn root(self, ws: &CargoWorkspace) -> &Path {
        ws.packages[self].manifest.parent().unwrap()
    }
    pub fn edition(self, ws: &CargoWorkspace) -> Edition {
        ws.packages[self].edition
    }
    pub fn features(self, ws: &CargoWorkspace) -> &[String] {
        &ws.packages[self].features
    }
    pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator<Item = Target> + 'a {
        ws.packages[self].targets.iter().cloned()
    }
    #[allow(unused)]
    pub fn is_member(self, ws: &CargoWorkspace) -> bool {
        ws.packages[self].is_member
    }
    pub fn dependencies<'a>(
        self,
        ws: &'a CargoWorkspace,
    ) -> impl Iterator<Item = &'a PackageDependency> + 'a {
        ws.packages[self].dependencies.iter()
    }
}

impl Target {
    pub fn package(self, ws: &CargoWorkspace) -> Package {
        ws.targets[self].pkg
    }
    pub fn name(self, ws: &CargoWorkspace) -> &str {
        ws.targets[self].name.as_str()
    }
    pub fn root(self, ws: &CargoWorkspace) -> &Path {
        ws.targets[self].root.as_path()
    }
    pub fn kind(self, ws: &CargoWorkspace) -> TargetKind {
        ws.targets[self].kind
    }
    pub fn is_proc_macro(self, ws: &CargoWorkspace) -> bool {
        ws.targets[self].is_proc_macro
    }
}

impl CargoWorkspace {
    pub fn from_cargo_metadata(
        cargo_toml: &Path,
        cargo_features: &CargoFeatures,
    ) -> Result<CargoWorkspace> {
        let mut meta = MetadataCommand::new();
        meta.manifest_path(cargo_toml);
        if cargo_features.all_features {
            meta.features(CargoOpt::AllFeatures);
        } else if cargo_features.no_default_features {
            // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
            // https://github.com/oli-obk/cargo_metadata/issues/79
            meta.features(CargoOpt::NoDefaultFeatures);
        } else if cargo_features.features.len() > 0 {
            meta.features(CargoOpt::SomeFeatures(cargo_features.features.clone()));
        }
        if let Some(parent) = cargo_toml.parent() {
            meta.current_dir(parent);
        }
        let meta = meta.exec().map_err(|e| format!("cargo metadata failed: {}", e))?;
        let mut pkg_by_id = FxHashMap::default();
        let mut packages = Arena::default();
        let mut targets = Arena::default();

        let ws_members = &meta.workspace_members;

        for meta_pkg in meta.packages {
            let cargo_metadata::Package { id, edition, name, manifest_path, .. } = meta_pkg;
            let is_member = ws_members.contains(&id);
            let edition = edition.parse::<Edition>()?;
            let pkg = packages.alloc(PackageData {
                name,
                manifest: manifest_path,
                targets: Vec::new(),
                is_member,
                edition,
                dependencies: Vec::new(),
                features: Vec::new(),
            });
            let pkg_data = &mut packages[pkg];
            pkg_by_id.insert(id, pkg);
            for meta_tgt in meta_pkg.targets {
                let is_proc_macro = meta_tgt.kind.as_slice() == &["proc-macro"];
                let tgt = targets.alloc(TargetData {
                    pkg,
                    name: meta_tgt.name,
                    root: meta_tgt.src_path.clone(),
                    kind: TargetKind::new(meta_tgt.kind.as_slice()),
                    is_proc_macro,
                });
                pkg_data.targets.push(tgt);
            }
        }
        let resolve = meta.resolve.expect("metadata executed with deps");
        for node in resolve.nodes {
            let source = pkg_by_id[&node.id];
            for dep_node in node.deps {
                let dep = PackageDependency { name: dep_node.name, pkg: pkg_by_id[&dep_node.pkg] };
                packages[source].dependencies.push(dep);
            }
            packages[source].features.extend(node.features);
        }

        Ok(CargoWorkspace { packages, targets, workspace_root: meta.workspace_root })
    }

    pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + ExactSizeIterator + 'a {
        self.packages.iter().map(|(id, _pkg)| id)
    }

    pub fn target_by_root(&self, root: &Path) -> Option<Target> {
        self.packages().filter_map(|pkg| pkg.targets(self).find(|it| it.root(self) == root)).next()
    }
}
<|endoftext|>


<commit_before>use std::error;
use std::fmt;

use cairo;
use cssparser::BasicParseError;

use attributes::Attribute;
use parsers::ParseError;

#[derive(Debug, Clone, PartialEq)]
pub enum AttributeError {
    // parse error
    Parse(ParseError),

    // invalid value
    Value(String),
}

#[derive(Debug, Clone, PartialEq)]
pub struct NodeError {
    attr: Attribute,
    err: AttributeError,
}

impl NodeError {
    pub fn parse_error(attr: Attribute, error: ParseError) -> NodeError {
        NodeError {
            attr,
            err: AttributeError::Parse(error),
        }
    }

    pub fn value_error(attr: Attribute, description: &str) -> NodeError {
        NodeError {
            attr,
            err: AttributeError::Value(description.to_string()),
        }
    }

    pub fn attribute_error(attr: Attribute, error: AttributeError) -> NodeError {
        NodeError { attr, err: error }
    }
}

impl error::Error for NodeError {
    fn description(&self) -> &str {
        match self.err {
            AttributeError::Parse(_) => "parse error",
            AttributeError::Value(_) => "invalid attribute value",
        }
    }
}

impl fmt::Display for NodeError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.err {
            AttributeError::Parse(ref n) => write!(
                f,
                "error parsing value for attribute \"{}\": {}",
                self.attr.to_string(),
                n.display
            ),

            AttributeError::Value(ref s) => write!(
                f,
                "invalid value for attribute \"{}\": {}",
                self.attr.to_string(),
                s
            ),
        }
    }
}

impl From<ParseError> for AttributeError {
    fn from(pe: ParseError) -> AttributeError {
        AttributeError::Parse(pe)
    }
}

impl<'a> From<BasicParseError<'a>> for AttributeError {
    fn from(e: BasicParseError<'_>) -> AttributeError {
        AttributeError::from(ParseError::from(e))
    }
}

#[derive(Clone)]
pub enum RenderingError {
    Cairo(cairo::Status),
    CircularReference,
    InstancingLimit,
}

impl From<cairo::Status> for RenderingError {
    fn from(e: cairo::Status) -> RenderingError {
        assert!(e != cairo::Status::Success);

        RenderingError::Cairo(e)
    }
}

#[cfg(test)]
pub fn is_parse_error<T>(r: &Result<T, AttributeError>) -> bool {
    match *r {
        Err(AttributeError::Parse(_)) => true,
        _ => false,
    }
}

#[cfg(test)]
pub fn is_value_error<T>(r: &Result<T, AttributeError>) -> bool {
    match *r {
        Err(AttributeError::Value(_)) => true,
        _ => false,
    }
}
<commit_msg>Minimal docs for AttributeError and NodeError<commit_after>use std::error;
use std::fmt;

use cairo;
use cssparser::BasicParseError;

use attributes::Attribute;
use parsers::ParseError;

/// A simple error which refers to an attribute's value
#[derive(Debug, Clone, PartialEq)]
pub enum AttributeError {
    /// The value could not be parsed
    Parse(ParseError),

    // The value could be parsed, but is invalid
    Value(String),
}

/// A complete error for an attribute and its erroneous value
#[derive(Debug, Clone, PartialEq)]
pub struct NodeError {
    attr: Attribute,
    err: AttributeError,
}

impl NodeError {
    pub fn parse_error(attr: Attribute, error: ParseError) -> NodeError {
        NodeError {
            attr,
            err: AttributeError::Parse(error),
        }
    }

    pub fn value_error(attr: Attribute, description: &str) -> NodeError {
        NodeError {
            attr,
            err: AttributeError::Value(description.to_string()),
        }
    }

    pub fn attribute_error(attr: Attribute, error: AttributeError) -> NodeError {
        NodeError { attr, err: error }
    }
}

impl error::Error for NodeError {
    fn description(&self) -> &str {
        match self.err {
            AttributeError::Parse(_) => "parse error",
            AttributeError::Value(_) => "invalid attribute value",
        }
    }
}

impl fmt::Display for NodeError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.err {
            AttributeError::Parse(ref n) => write!(
                f,
                "error parsing value for attribute \"{}\": {}",
                self.attr.to_string(),
                n.display
            ),

            AttributeError::Value(ref s) => write!(
                f,
                "invalid value for attribute \"{}\": {}",
                self.attr.to_string(),
                s
            ),
        }
    }
}

impl From<ParseError> for AttributeError {
    fn from(pe: ParseError) -> AttributeError {
        AttributeError::Parse(pe)
    }
}

impl<'a> From<BasicParseError<'a>> for AttributeError {
    fn from(e: BasicParseError<'_>) -> AttributeError {
        AttributeError::from(ParseError::from(e))
    }
}

#[derive(Clone)]
pub enum RenderingError {
    Cairo(cairo::Status),
    CircularReference,
    InstancingLimit,
}

impl From<cairo::Status> for RenderingError {
    fn from(e: cairo::Status) -> RenderingError {
        assert!(e != cairo::Status::Success);

        RenderingError::Cairo(e)
    }
}

#[cfg(test)]
pub fn is_parse_error<T>(r: &Result<T, AttributeError>) -> bool {
    match *r {
        Err(AttributeError::Parse(_)) => true,
        _ => false,
    }
}

#[cfg(test)]
pub fn is_value_error<T>(r: &Result<T, AttributeError>) -> bool {
    match *r {
        Err(AttributeError::Value(_)) => true,
        _ => false,
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, hash_map};
use tensor::Tensor;
use autograd::Variable;
use std::vec::IntoIter;
use nn;

// placeholder
struct TorchBackend {}

pub trait ModuleStruct {
    fn init_module(self) -> Self;
}

pub struct Module<T: Copy> {
    pub _name: String,
    pub training: bool,
    _backend: TorchBackend,

    _buffers: HashMap<String, Tensor<T>>,
    //	_backward_hooks:
    //	_forward_hooks:
    _params: HashMap<String, *mut nn::Parameter<T>>,
    _modules: HashMap<String, *mut Module<T>>,
}
pub struct PtrIterMut<'a, T: 'a> {
    //mod_iter: linked_hash_map::IterMut<'a, &'a str, *mut T>,
    mod_iter: hash_map::IterMut<'a, String, *mut T>,
}
pub struct PtrIter<'a, T: 'a> {
    //mod_iter: linked_hash_map::IterMut<'a, &'a str, *mut T>,
    mod_iter: hash_map::Iter<'a, String, *mut T>,
}

impl<'a, T> Iterator for PtrIter<'a, T> {
    type Item = (&'a str, &'a T);
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((name, t)) = self.mod_iter.next() {
            Some((name, unsafe { &**t as &T }))
        } else {
            None
        }
    }
}

impl<'a, T> Iterator for PtrIterMut<'a, T> {
    type Item = (&'a String, &'a mut T);
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((name, t)) = self.mod_iter.next() {
            Some((name, unsafe { &mut **t as &mut T }))
        } else {
            None
        }
    }
}

pub struct ModIter<'a, T: 'a + Copy> {
    pub modules: IntoIter<*mut Module<T>>,
    pub iter: PtrIterMut<'a, nn::Parameter<T>>,
}
fn mod_accum<TMod: Copy>(module: &mut Module<TMod>, arg: &mut Vec<*mut Module<TMod>>) {
    arg.push((module));
}
impl<'a, TMod: 'a + Copy> ModIter<'a, TMod> {
    pub fn new(root: &'a mut Module<TMod>) -> Self {
        let mut mods = Vec::new();
        root.apply_arg(&mut mods, mod_accum);
        // XXX assert is root
        mods.pop();
        ModIter {
            modules: mods.into_iter(),
            iter: root.params_iter_mut(),
        }
    }
}

impl<'a, T: Copy> Iterator for ModIter<'a, T> {
    type Item = &'a mut nn::Parameter<T>;
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((_, t)) = self.iter.next() {
            Some(t)
        } else if let Some(modulep) = self.modules.next() {
            let mut module = unsafe { &mut *modulep as &mut Module<T> };
            self.iter = module.params_iter_mut();
            self.next()
        } else {
            None
        }
    }
}

impl<T: Copy> Module<T> {
    pub fn new() -> Module<T> {
        Module {
            _name: String::from(""),
            _backend: TorchBackend {},
            _buffers: HashMap::new(),
            _params: HashMap::new(),
            _modules: HashMap::new(),
            training: true,
        }
    }
    #[inline]
    fn as_mut_ptr(&mut self) -> *mut Module<T> {
        self as *mut Module<T>
    }
    pub fn add_module(&mut self, module: &mut ModIntf<T>) {
        let m = module.delegate();
        self._modules.insert(m._name.clone(), m.as_mut_ptr());

    }
    pub fn add_param(&mut self, name: &str, param: &mut nn::Parameter<T>) {
        let s = String::from(name);
        self._params.insert(s, param.as_mut_ptr());

    }
    pub fn modules_iter_mut(&mut self) -> PtrIterMut<Module<T>> {
        PtrIterMut { mod_iter: self._modules.iter_mut() }
    }
    pub fn modules_iter(&mut self) -> PtrIter<Module<T>> {
        PtrIter { mod_iter: self._modules.iter() }
    }
    pub fn params_iter_mut(&mut self) -> PtrIterMut<nn::Parameter<T>> {
        PtrIterMut { mod_iter: self._params.iter_mut() }
    }
    pub fn register_buffer(&mut self, name: &str, tensor: &mut Tensor<T>) {
        self._buffers.insert(String::from(name), tensor.clone());
    }
    pub fn parameters(&mut self) -> ModIter<T> {
        ModIter::new(self)
    }
    fn _apply(&mut self, callback: fn(&mut Tensor<T>)) {
        for (_, module) in self.modules_iter_mut() {
            module._apply(callback)
        }
        for (_, param) in self.params_iter_mut() {
            param.apply(callback)
            /*
			if let Some(g) = p._grad {
					callback(g.data)
			}
			*/
            /* see also _buffers */
        }
    }
    pub fn apply(&mut self, callback: fn(&mut Self)) {
        for (_, module) in self.modules_iter_mut() {
            module.apply(callback)
        }
        callback(self)
    }
    fn apply_arg<Ta>(&mut self, arg: &mut Ta, callback: fn(&mut Self, &mut Ta)) {
        for (_, module) in self.modules_iter_mut() {
            module.apply_arg(arg, callback)
        }
        callback(self, arg)
    }
    pub fn repr(&mut self) -> String {
        let mut tmpstr = format!("{} (\n", self._name);
        for (key, module) in self.modules_iter_mut() {
            let modstr = module.repr();
            let modstr = format!("  {}", modstr);
            tmpstr = format!("{} ({}): {}\n", tmpstr, key, modstr);
        }
        tmpstr = format!("{})", tmpstr);
        tmpstr
    }
    pub fn eval(&mut self) {
        self.train(false)
    }
    fn train(&mut self, mode: bool) {
        self.training = mode;
        for (_, module) in self.modules_iter_mut() {
            module.train(mode)
        }

    }
}

pub trait ModDelegate<T: Copy> {
    fn delegate(&mut self) -> &mut Module<T>;
}

pub trait ModIntf<T: Copy>: ModDelegate<T> {
    fn forward(&mut self, input: &mut Variable<T>) -> Variable<T>;
    fn f(&mut self, input: &mut Variable<T>) -> Variable<T> {
        {
            let mut m = self.delegate();
            // do pre-forward hooks
        }
        let output = self.forward(input);
        {
            let mut m = self.delegate();
            // do post-forward hooks
        }
        output
    }
    fn train(&mut self) {
        self.delegate().train(true)
    }
    fn eval(&mut self) {
        self.delegate().train(false)
    }
}

pub trait ModIntfV<T: Copy>: ModDelegate<T> {
    fn forwardv(&mut self, input: &mut Vec<Variable<T>>) -> Vec<Variable<T>>;
    fn fv(&mut self, input: &mut Vec<Variable<T>>) -> Vec<Variable<T>> {
        {
            let mut m = self.delegate();
            // do pre-forward hooks
        }
        let output = self.forwardv(input);
        {
            let mut m = self.delegate();
            // do post-forward hooks
        }
        output
    }
}
<commit_msg>make ParamIter cloneable<commit_after>use std::collections::{HashMap, hash_map};
use tensor::Tensor;
use autograd::Variable;
use std::vec::IntoIter;
use nn;

// placeholder
struct TorchBackend {}

pub trait ModuleStruct {
    fn init_module(self) -> Self;
}

pub struct Module<T: Copy> {
    pub _name: String,
    pub training: bool,
    _backend: TorchBackend,

    _buffers: HashMap<String, Tensor<T>>,
    //	_backward_hooks:
    //	_forward_hooks:
    _params: HashMap<String, *mut nn::Parameter<T>>,
    _modules: HashMap<String, *mut Module<T>>,
}
pub struct PtrIterMut<'a, T: 'a> {
    //mod_iter: linked_hash_map::IterMut<'a, &'a str, *mut T>,
    mod_iter: hash_map::IterMut<'a, String, *mut T>,
}
pub struct PtrIter<'a, T: 'a> {
    //mod_iter: linked_hash_map::IterMut<'a, &'a str, *mut T>,
    mod_iter: hash_map::Iter<'a, String, *mut T>,
}

impl<'a, T> Iterator for PtrIter<'a, T> {
    type Item = (&'a str, &'a T);
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((name, t)) = self.mod_iter.next() {
            Some((name, unsafe { &**t as &T }))
        } else {
            None
        }
    }
}

impl<'a, T> Iterator for PtrIterMut<'a, T> {
    type Item = (&'a String, &'a mut T);
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((name, t)) = self.mod_iter.next() {
            Some((name, unsafe { &mut **t as &mut T }))
        } else {
            None
        }
    }
}

pub struct ParamIter<'a, T: 'a + Copy> {
    pub modules: Vec<*mut Module<T>>,
    pub mod_iter: IntoIter<*mut Module<T>>,
    pub iter: PtrIterMut<'a, nn::Parameter<T>>,
}
fn mod_accum<T: Copy>(module: &mut Module<T>, arg: &mut Vec<*mut Module<T>>) {
    arg.push((module));
}
impl<'a, T: 'a + Copy> ParamIter<'a, T> {
    pub fn new(root: &'a mut Module<T>) -> Self {
        let mut mods = Vec::new();
        root.apply_arg(&mut mods, mod_accum);
        ParamIter {
            modules: mods.clone(),
            mod_iter: mods.into_iter(),
            iter: root.params_iter_mut(),
        }
    }
}

impl<'a, T: Copy> Iterator for ParamIter<'a, T> {
    type Item = &'a mut nn::Parameter<T>;
    fn next(&mut self) -> Option<Self::Item> {
        if let Some((_, t)) = self.iter.next() {
            Some(t)
        } else if let Some(modulep) = self.mod_iter.next() {
            let mut module = unsafe { &mut *modulep as &mut Module<T> };
            self.iter = module.params_iter_mut();
            self.next()
        } else {
            None
        }
    }
}

impl<'a, T: Copy> Clone for ParamIter<'a, T> {
    fn clone(&self) -> Self {
        let mut new_mod_list = self.modules.clone();
        let param_iter = unsafe { &mut *new_mod_list[0] }.params_iter_mut();
        ParamIter {
            modules: new_mod_list,
            mod_iter: self.modules.clone().into_iter(),
            iter: param_iter,
        }
    }
}

impl<T: Copy> Module<T> {
    pub fn new() -> Module<T> {
        Module {
            _name: String::from(""),
            _backend: TorchBackend {},
            _buffers: HashMap::new(),
            _params: HashMap::new(),
            _modules: HashMap::new(),
            training: true,
        }
    }
    #[inline]
    fn as_mut_ptr(&mut self) -> *mut Module<T> {
        self as *mut Module<T>
    }
    pub fn add_module(&mut self, module: &mut ModIntf<T>) {
        let m = module.delegate();
        self._modules.insert(m._name.clone(), m.as_mut_ptr());

    }
    pub fn add_param(&mut self, name: &str, param: &mut nn::Parameter<T>) {
        let s = String::from(name);
        self._params.insert(s, param.as_mut_ptr());

    }
    pub fn modules_iter_mut(&mut self) -> PtrIterMut<Module<T>> {
        PtrIterMut { mod_iter: self._modules.iter_mut() }
    }
    pub fn modules_iter(&mut self) -> PtrIter<Module<T>> {
        PtrIter { mod_iter: self._modules.iter() }
    }
    pub fn params_iter_mut(&mut self) -> PtrIterMut<nn::Parameter<T>> {
        PtrIterMut { mod_iter: self._params.iter_mut() }
    }
    pub fn register_buffer(&mut self, name: &str, tensor: &mut Tensor<T>) {
        self._buffers.insert(String::from(name), tensor.clone());
    }
    pub fn parameters(&mut self) -> ParamIter<T> {
        ParamIter::new(self)
    }
    fn _apply(&mut self, callback: fn(&mut Tensor<T>)) {
        for (_, module) in self.modules_iter_mut() {
            module._apply(callback)
        }
        for (_, param) in self.params_iter_mut() {
            param.apply(callback)
            /*
			if let Some(g) = p._grad {
					callback(g.data)
			}
			*/
            /* see also _buffers */
        }
    }
    pub fn apply(&mut self, callback: fn(&mut Self)) {
        for (_, module) in self.modules_iter_mut() {
            module.apply(callback)
        }
        callback(self)
    }
    fn apply_arg<Ta>(&mut self, arg: &mut Ta, callback: fn(&mut Self, &mut Ta)) {
        for (_, module) in self.modules_iter_mut() {
            module.apply_arg(arg, callback)
        }
        callback(self, arg)
    }
    pub fn repr(&mut self) -> String {
        let mut tmpstr = format!("{} (\n", self._name);
        for (key, module) in self.modules_iter_mut() {
            let modstr = module.repr();
            let modstr = format!("  {}", modstr);
            tmpstr = format!("{} ({}): {}\n", tmpstr, key, modstr);
        }
        tmpstr = format!("{})", tmpstr);
        tmpstr
    }
    pub fn eval(&mut self) {
        self.train(false)
    }
    fn train(&mut self, mode: bool) {
        self.training = mode;
        for (_, module) in self.modules_iter_mut() {
            module.train(mode)
        }

    }
}

pub trait ModDelegate<T: Copy> {
    fn delegate(&mut self) -> &mut Module<T>;
}

pub trait ModIntf<T: Copy>: ModDelegate<T> {
    fn forward(&mut self, input: &mut Variable<T>) -> Variable<T>;
    fn f(&mut self, input: &mut Variable<T>) -> Variable<T> {
        {
            let mut m = self.delegate();
            // do pre-forward hooks
        }
        let output = self.forward(input);
        {
            let mut m = self.delegate();
            // do post-forward hooks
        }
        output
    }
    fn train(&mut self) {
        self.delegate().train(true)
    }
    fn eval(&mut self) {
        self.delegate().train(false)
    }
}

pub trait ModIntfV<T: Copy>: ModDelegate<T> {
    fn forwardv(&mut self, input: &mut Vec<Variable<T>>) -> Vec<Variable<T>>;
    fn fv(&mut self, input: &mut Vec<Variable<T>>) -> Vec<Variable<T>> {
        {
            let mut m = self.delegate();
            // do pre-forward hooks
        }
        let output = self.forwardv(input);
        {
            let mut m = self.delegate();
            // do post-forward hooks
        }
        output
    }
}
<|endoftext|>


<commit_before>extern crate protobuf;
extern crate rand;
extern crate time;

use std::io::File;
use std::io::MemWriter;
use std::default::Default;
use std::os;

use std::rand::Rng;
use std::rand::StdRng;
use std::rand::SeedableRng;

use protobuf::Message;
use protobuf::MessageStatic;
use perftest_data::PerftestData;

mod perftest_data;

fn measure_ns<R>(f: || -> R) -> (u64, R) {
    let start = time::precise_time_ns();
    let r = f();
    (time::precise_time_ns() - start, r)
}

fn measure_and_print<R>(title: &str, iter: u64, f: || -> R) -> R {
    let (ns, r) = measure_ns(f);
    let ns_per_iter = ns / iter;
    println!("{}: {} ns per iter", title, ns_per_iter);
    r
}

fn run_test<M : Message + MessageStatic>(name: &str, data: &[M]) {
    let mut rng: StdRng = SeedableRng::from_seed([10, 20, 30, 40].as_slice());
    let mut random_data: Vec<M> = Vec::new();

    let mut total_size = 0;
    while total_size < 1000000 {
        let ref item = data[rng.gen_range(0, data.len())];
        random_data.push(item.clone());
        total_size += item.compute_size();
    }

    let mut writer = MemWriter::new();
    measure_and_print(format!("{}: write", name).as_slice(), random_data.len() as u64, || {
        for m in random_data.iter() {
            m.write_length_delimited_to_writer(&mut writer).unwrap();
        }
    });

    let buf = writer.into_inner();

    let read_data = measure_and_print(format!("{}: read", name).as_slice(), random_data.len() as u64, || {
        let mut r = Vec::new();
        let mut coded_input_stream = protobuf::CodedInputStream::from_bytes(buf.as_slice());
        while !coded_input_stream.eof().unwrap() {
            r.push(protobuf::parse_length_delimited_from::<M>(&mut coded_input_stream).unwrap());
        }
        r
    });

    assert_eq!(random_data, read_data);

    let merged = measure_and_print(format!("{}: read reuse", name).as_slice(), random_data.len() as u64, || {
        let mut coded_input_stream = protobuf::CodedInputStream::from_bytes(buf.as_slice());
        let mut msg: M = Default::default();
        let mut count = 0;
        while !coded_input_stream.eof().unwrap() {
            msg.clear();
            coded_input_stream.merge_message(&mut msg).unwrap();
            count += 1;
        }
        count
    });

    assert_eq!(random_data.len(), merged);
}

struct TestRunner {
    selected: Option<String>,
    any_matched: bool,
}

impl TestRunner {
    fn test<M : Message + MessageStatic>(&mut self, name: &str, data: &[M]) {
        if self.selected.is_none() || name == self.selected.as_ref().unwrap().as_slice() {
            run_test(name, data);
            self.any_matched = true;
        }
    }

    fn check(&self) {
        if !self.any_matched {
            let name = self.selected.as_ref().map(|s| s.as_slice()).unwrap_or("bug");
            panic!("no tests found with name {}", name);
        }
    }
}

fn main() {
    let selected = match os::args().as_slice() {
        [_] => None,
        [_, ref test] => Some(test.to_string()),
        v => panic!("usage: {} <test>", v[0]),
    };

    let mut runner = TestRunner { selected: selected, any_matched: false };

    let mut is = File::open(&Path::new("perftest_data.pbbin"));
    let test_data = protobuf::parse_from_reader::<PerftestData>(&mut is).unwrap();

    runner.test("test1", test_data.get_test1());
    runner.test("test_repeated_bool", test_data.get_test_repeated_bool());
    runner.test("test_repeated_packed_int32", test_data.get_test_repeated_packed_int32());
    runner.test("test_repeated_messages", test_data.get_test_repeated_messages());
    runner.test("test_optional_messages", test_data.get_test_optional_messages());
    runner.test("test_strings", test_data.get_test_strings());
    runner.check();
}
<commit_msg>fix perftest compilation<commit_after>extern crate protobuf;
extern crate rand;
extern crate time;

use std::io::File;
use std::io::MemWriter;
use std::default::Default;
use std::os;

use std::rand::Rng;
use std::rand::StdRng;
use std::rand::SeedableRng;

use protobuf::Message;
use protobuf::MessageStatic;
use perftest_data::PerftestData;

mod perftest_data;

fn measure_ns<R, F: FnMut() -> R>(mut f: F) -> (u64, R) {
    let start = time::precise_time_ns();
    let r = f();
    (time::precise_time_ns() - start, r)
}

fn measure_and_print<R, F: FnMut() -> R>(title: &str, iter: u64, f: F) -> R {
    let (ns, r) = measure_ns(f);
    let ns_per_iter = ns / iter;
    println!("{}: {} ns per iter", title, ns_per_iter);
    r
}

fn run_test<M : Message + MessageStatic>(name: &str, data: &[M]) {
    let mut rng: StdRng = SeedableRng::from_seed([10, 20, 30, 40].as_slice());
    let mut random_data: Vec<M> = Vec::new();

    let mut total_size = 0;
    while total_size < 1000000 {
        let ref item = data[rng.gen_range(0, data.len())];
        random_data.push(item.clone());
        total_size += item.compute_size();
    }

    let mut writer = MemWriter::new();
    measure_and_print(format!("{}: write", name).as_slice(), random_data.len() as u64, || {
        for m in random_data.iter() {
            m.write_length_delimited_to_writer(&mut writer).unwrap();
        }
    });

    let buf = writer.into_inner();

    let read_data = measure_and_print(format!("{}: read", name).as_slice(), random_data.len() as u64, || {
        let mut r = Vec::new();
        let mut coded_input_stream = protobuf::CodedInputStream::from_bytes(buf.as_slice());
        while !coded_input_stream.eof().unwrap() {
            r.push(protobuf::parse_length_delimited_from::<M>(&mut coded_input_stream).unwrap());
        }
        r
    });

    assert_eq!(random_data, read_data);

    let merged = measure_and_print(format!("{}: read reuse", name).as_slice(), random_data.len() as u64, || {
        let mut coded_input_stream = protobuf::CodedInputStream::from_bytes(buf.as_slice());
        let mut msg: M = Default::default();
        let mut count = 0;
        while !coded_input_stream.eof().unwrap() {
            msg.clear();
            coded_input_stream.merge_message(&mut msg).unwrap();
            count += 1;
        }
        count
    });

    assert_eq!(random_data.len(), merged);
}

struct TestRunner {
    selected: Option<String>,
    any_matched: bool,
}

impl TestRunner {
    fn test<M : Message + MessageStatic>(&mut self, name: &str, data: &[M]) {
        if self.selected.is_none() || name == self.selected.as_ref().unwrap().as_slice() {
            run_test(name, data);
            self.any_matched = true;
        }
    }

    fn check(&self) {
        if !self.any_matched {
            let name = self.selected.as_ref().map(|s| s.as_slice()).unwrap_or("bug");
            panic!("no tests found with name {}", name);
        }
    }
}

fn main() {
    let selected = match os::args().as_slice() {
        [_] => None,
        [_, ref test] => Some(test.to_string()),
        v => panic!("usage: {} <test>", v[0]),
    };

    let mut runner = TestRunner { selected: selected, any_matched: false };

    let mut is = File::open(&Path::new("perftest_data.pbbin"));
    let test_data = protobuf::parse_from_reader::<PerftestData>(&mut is).unwrap();

    runner.test("test1", test_data.get_test1());
    runner.test("test_repeated_bool", test_data.get_test_repeated_bool());
    runner.test("test_repeated_packed_int32", test_data.get_test_repeated_packed_int32());
    runner.test("test_repeated_messages", test_data.get_test_repeated_messages());
    runner.test("test_optional_messages", test_data.get_test_optional_messages());
    runner.test("test_strings", test_data.get_test_strings());
    runner.check();
}
<|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/. */

//! A centralized set of stylesheets for a document.

use dom::TElement;
use invalidation::stylesheets::StylesheetInvalidationSet;
use media_queries::Device;
use shared_lock::SharedRwLockReadGuard;
use std::slice;
use stylesheets::{Origin, OriginSet, PerOrigin, StylesheetInDocument};

/// Entry for a StylesheetSet. We don't bother creating a constructor, because
/// there's no sensible defaults for the member variables.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
struct StylesheetSetEntry<S>
where
    S: StylesheetInDocument + PartialEq + 'static,
{
    sheet: S,
    dirty: bool,
}

impl<S> StylesheetSetEntry<S>
where
    S: StylesheetInDocument + PartialEq + 'static,
{
    fn new(sheet: S) -> Self {
        Self { sheet, dirty: true }
    }
}

/// A iterator over the stylesheets of a list of entries in the StylesheetSet.
#[derive(Clone)]
pub struct StylesheetIterator<'a, S>(slice::Iter<'a, StylesheetSetEntry<S>>)
where
    S: StylesheetInDocument + PartialEq + 'static;

impl<'a, S> Iterator for StylesheetIterator<'a, S>
where
    S: StylesheetInDocument + PartialEq + 'static,
{
    type Item = &'a S;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|entry| &entry.sheet)
    }
}

/// The validity of the data in a given cascade origin.
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum OriginValidity {
    /// The origin is clean, all the data already there is valid, though we may
    /// have new sheets at the end.
    Valid = 0,

    /// The cascade data is invalid, but not the invalidation data (which is
    /// order-independent), and thus only the cascade data should be inserted.
    CascadeInvalid = 1,

    /// Everything needs to be rebuilt.
    FullyInvalid = 2,
}

impl Default for OriginValidity {
    fn default() -> Self {
        OriginValidity::Valid
    }
}

/// A struct to iterate over the different stylesheets to be flushed.
pub struct StylesheetFlusher<'a, 'b, S>
where
    'b: 'a,
    S: StylesheetInDocument + PartialEq + 'static,
{
    iter: slice::IterMut<'a, StylesheetSetEntry<S>>,
    guard: &'a SharedRwLockReadGuard<'b>,
    origins_dirty: OriginSet,
    origin_data_validity: PerOrigin<OriginValidity>,
    author_style_disabled: bool,
    had_invalidations: bool,
}

/// The type of rebuild that we need to do for a given stylesheet.
pub enum SheetRebuildKind {
    /// A full rebuild, of both cascade data and invalidation data.
    Full,
    /// A partial rebuild, of only the cascade data.
    CascadeOnly,
}

impl SheetRebuildKind {
    /// Whether the stylesheet invalidation data should be rebuilt.
    pub fn should_rebuild_invalidation(&self) -> bool {
        matches!(*self, SheetRebuildKind::Full)
    }
}

impl<'a, 'b, S> StylesheetFlusher<'a, 'b, S>
where
    'b: 'a,
    S: StylesheetInDocument + PartialEq + 'static,
{
    /// The data validity for a given origin.
    pub fn origin_validity(&self, origin: Origin) -> OriginValidity {
        *self.origin_data_validity.borrow_for_origin(&origin)
    }

    /// Returns whether running the whole flushing process would be a no-op.
    pub fn nothing_to_do(&self) -> bool {
        self.origins_dirty.is_empty()
    }

    /// Returns whether any DOM invalidations were processed as a result of the
    /// stylesheet flush.
    pub fn had_invalidations(&self) -> bool {
        self.had_invalidations
    }
}

#[cfg(debug_assertions)]
impl<'a, 'b, S> Drop for StylesheetFlusher<'a, 'b, S>
where
    'b: 'a,
    S: StylesheetInDocument + PartialEq + 'static,
{
    fn drop(&mut self) {
        debug_assert!(
            self.iter.next().is_none(),
            "You're supposed to fully consume the flusher"
        );
    }
}

impl<'a, 'b, S> Iterator for StylesheetFlusher<'a, 'b, S>
where
    'b: 'a,
    S: StylesheetInDocument + PartialEq + 'static,
{
    type Item = (&'a S, SheetRebuildKind);

    fn next(&mut self) -> Option<Self::Item> {
        use std::mem;

        loop {
            let potential_sheet = match self.iter.next() {
                None => return None,
                Some(s) => s,
            };

            let dirty = mem::replace(&mut potential_sheet.dirty, false);

            if dirty {
                // If the sheet was dirty, we need to do a full rebuild anyway.
                return Some((&potential_sheet.sheet, SheetRebuildKind::Full))
            }

            let origin = potential_sheet.sheet.contents(self.guard).origin;
            if !self.origins_dirty.contains(origin.into()) {
                continue;
            }

            if self.author_style_disabled && matches!(origin, Origin::Author) {
                continue;
            }

            let rebuild_kind = match self.origin_validity(origin) {
                OriginValidity::Valid => continue,
                OriginValidity::CascadeInvalid => SheetRebuildKind::CascadeOnly,
                OriginValidity::FullyInvalid => SheetRebuildKind::Full,
            };

            return Some((&potential_sheet.sheet, rebuild_kind));
        }
    }
}

/// The set of stylesheets effective for a given document.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct StylesheetSet<S>
where
    S: StylesheetInDocument + PartialEq + 'static,
{
    /// The actual list of all the stylesheets that apply to the given document,
    /// each stylesheet associated with a unique ID.
    ///
    /// This is only a list of top-level stylesheets, and as such it doesn't
    /// include recursive `@import` rules.
    entries: Vec<StylesheetSetEntry<S>>,

    /// The invalidations for stylesheets added or removed from this document.
    invalidations: StylesheetInvalidationSet,

    /// The origins whose stylesheets have changed so far.
    origins_dirty: OriginSet,

    /// The validity of the data that was already there for a given origin.
    ///
    /// Note that an origin may appear on `origins_dirty`, but still have
    /// `OriginValidity::Valid`, if only sheets have been appended into it (in
    /// which case the existing data is valid, but the origin needs to be
    /// rebuilt).
    origin_data_validity: PerOrigin<OriginValidity>,

    /// Has author style been disabled?
    author_style_disabled: bool,
}

impl<S> StylesheetSet<S>
where
    S: StylesheetInDocument + PartialEq + 'static,
{
    /// Create a new empty StylesheetSet.
    pub fn new() -> Self {
        StylesheetSet {
            entries: vec![],
            invalidations: StylesheetInvalidationSet::new(),
            origins_dirty: OriginSet::empty(),
            origin_data_validity: Default::default(),
            author_style_disabled: false,
        }
    }

    /// Returns the number of stylesheets in the set.
    pub fn len(&self) -> usize {
        self.entries.len()
    }

    /// Returns the number of stylesheets in the set.
    pub fn get(&self, index: usize) -> Option<&S> {
        self.entries.get(index).map(|s| &s.sheet)
    }

    /// Returns whether author styles have been disabled for the current
    /// stylesheet set.
    pub fn author_style_disabled(&self) -> bool {
        self.author_style_disabled
    }

    fn remove_stylesheet_if_present(&mut self, sheet: &S) {
        self.entries.retain(|entry| entry.sheet != *sheet);
    }

    fn collect_invalidations_for(
        &mut self,
        device: Option<&Device>,
        sheet: &S,
        guard: &SharedRwLockReadGuard,
    ) {
        if let Some(device) = device {
            self.invalidations.collect_invalidations_for(device, sheet, guard);
        }
        self.origins_dirty |= sheet.contents(guard).origin;
    }

    fn set_data_validity_at_least(
        &mut self,
        origin: Origin,
        validity: OriginValidity,
    ) {
        use std::cmp;

        debug_assert!(
            self.origins_dirty.contains(origin.into()),
            "data_validity should be a subset of origins_dirty"
        );

        let existing_validity =
            self.origin_data_validity.borrow_mut_for_origin(&origin);

        *existing_validity = cmp::max(*existing_validity, validity);
    }

    /// Appends a new stylesheet to the current set.
    ///
    /// No device implies not computing invalidations.
    pub fn append_stylesheet(
        &mut self,
        device: Option<&Device>,
        sheet: S,
        guard: &SharedRwLockReadGuard
    ) {
        debug!("StylesheetSet::append_stylesheet");
        self.remove_stylesheet_if_present(&sheet);
        self.collect_invalidations_for(device, &sheet, guard);
        // Appending sheets doesn't alter the validity of the existing data, so
        // we don't need to change `origin_data_validity` here.
        self.entries.push(StylesheetSetEntry::new(sheet));
    }

    /// Prepend a new stylesheet to the current set.
    pub fn prepend_stylesheet(
        &mut self,
        device: Option<&Device>,
        sheet: S,
        guard: &SharedRwLockReadGuard
    ) {
        debug!("StylesheetSet::prepend_stylesheet");
        self.remove_stylesheet_if_present(&sheet);
        self.collect_invalidations_for(device, &sheet, guard);

        // Inserting stylesheets somewhere but at the end changes the validity
        // of the cascade data, but not the invalidation data.
        self.set_data_validity_at_least(sheet.contents(guard).origin, OriginValidity::CascadeInvalid);

        self.entries.insert(0, StylesheetSetEntry::new(sheet));
    }

    /// Insert a given stylesheet before another stylesheet in the document.
    pub fn insert_stylesheet_before(
        &mut self,
        device: Option<&Device>,
        sheet: S,
        before_sheet: S,
        guard: &SharedRwLockReadGuard,
    ) {
        debug!("StylesheetSet::insert_stylesheet_before");
        self.remove_stylesheet_if_present(&sheet);
        let index = self.entries.iter().position(|entry| {
            entry.sheet == before_sheet
        }).expect("`before_sheet` stylesheet not found");
        self.collect_invalidations_for(device, &sheet, guard);

        // Inserting stylesheets somewhere but at the end changes the validity
        // of the cascade data, but not the invalidation data.
        self.set_data_validity_at_least(sheet.contents(guard).origin, OriginValidity::CascadeInvalid);
        self.entries.insert(index, StylesheetSetEntry::new(sheet));
    }

    /// Remove a given stylesheet from the set.
    pub fn remove_stylesheet(
        &mut self,
        device: Option<&Device>,
        sheet: S,
        guard: &SharedRwLockReadGuard,
    ) {
        debug!("StylesheetSet::remove_stylesheet");
        self.remove_stylesheet_if_present(&sheet);

        self.collect_invalidations_for(device, &sheet, guard);

        // Removing sheets makes us tear down the whole cascade and invalidation
        // data.
        self.set_data_validity_at_least(sheet.contents(guard).origin, OriginValidity::FullyInvalid);
    }

    /// Notes that the author style has been disabled for this document.
    pub fn set_author_style_disabled(&mut self, disabled: bool) {
        debug!("StylesheetSet::set_author_style_disabled");
        if self.author_style_disabled == disabled {
            return;
        }
        self.author_style_disabled = disabled;
        self.invalidations.invalidate_fully();
        self.origins_dirty |= Origin::Author;
    }

    /// Returns whether the given set has changed from the last flush.
    pub fn has_changed(&self) -> bool {
        !self.origins_dirty.is_empty()
    }

    /// Flush the current set, unmarking it as dirty, and returns a
    /// `StylesheetFlusher` in order to rebuild the stylist.
    pub fn flush<'a, 'b, E>(
        &'a mut self,
        document_element: Option<E>,
        guard: &'a SharedRwLockReadGuard<'b>,
    ) -> StylesheetFlusher<'a, 'b, S>
    where
        E: TElement,
    {
        use std::mem;

        debug!("StylesheetSet::flush");

        let had_invalidations = self.invalidations.flush(document_element);
        let origins_dirty = mem::replace(&mut self.origins_dirty, OriginSet::empty());
        let origin_data_validity =
            mem::replace(&mut self.origin_data_validity, Default::default());

        StylesheetFlusher {
            iter: self.entries.iter_mut(),
            author_style_disabled: self.author_style_disabled,
            had_invalidations,
            origins_dirty,
            origin_data_validity,
            guard,
        }
    }

    /// Flush stylesheets, but without running any of the invalidation passes.
    #[cfg(feature = "servo")]
    pub fn flush_without_invalidation(&mut self) -> OriginSet {
        use std::mem;

        debug!("StylesheetSet::flush_without_invalidation");

        self.invalidations.clear();
        mem::replace(&mut self.origins_dirty, OriginSet::empty())
    }

    /// Returns an iterator over the current list of stylesheets.
    pub fn iter(&self) -> StylesheetIterator<S> {
        StylesheetIterator(self.entries.iter())
    }

    /// Mark the stylesheets for the specified origin as dirty, because
    /// something external may have invalidated it.
    pub fn force_dirty(&mut self, origins: OriginSet) {
        self.invalidations.invalidate_fully();
        self.origins_dirty |= origins;
        for origin in origins.iter() {
            // We don't know what happened, assume the worse.
            self.set_data_validity_at_least(origin, OriginValidity::FullyInvalid);
        }
    }
}
<commit_msg>style: Remove outdated comment.<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/. */

//! A centralized set of stylesheets for a document.

use dom::TElement;
use invalidation::stylesheets::StylesheetInvalidationSet;
use media_queries::Device;
use shared_lock::SharedRwLockReadGuard;
use std::slice;
use stylesheets::{Origin, OriginSet, PerOrigin, StylesheetInDocument};

/// Entry for a StylesheetSet.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
struct StylesheetSetEntry<S>
where
    S: StylesheetInDocument + PartialEq + 'static,
{
    sheet: S,
    dirty: bool,
}

impl<S> StylesheetSetEntry<S>
where
    S: StylesheetInDocument + PartialEq + 'static,
{
    fn new(sheet: S) -> Self {
        Self { sheet, dirty: true }
    }
}

/// A iterator over the stylesheets of a list of entries in the StylesheetSet.
#[derive(Clone)]
pub struct StylesheetIterator<'a, S>(slice::Iter<'a, StylesheetSetEntry<S>>)
where
    S: StylesheetInDocument + PartialEq + 'static;

impl<'a, S> Iterator for StylesheetIterator<'a, S>
where
    S: StylesheetInDocument + PartialEq + 'static,
{
    type Item = &'a S;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|entry| &entry.sheet)
    }
}

/// The validity of the data in a given cascade origin.
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum OriginValidity {
    /// The origin is clean, all the data already there is valid, though we may
    /// have new sheets at the end.
    Valid = 0,

    /// The cascade data is invalid, but not the invalidation data (which is
    /// order-independent), and thus only the cascade data should be inserted.
    CascadeInvalid = 1,

    /// Everything needs to be rebuilt.
    FullyInvalid = 2,
}

impl Default for OriginValidity {
    fn default() -> Self {
        OriginValidity::Valid
    }
}

/// A struct to iterate over the different stylesheets to be flushed.
pub struct StylesheetFlusher<'a, 'b, S>
where
    'b: 'a,
    S: StylesheetInDocument + PartialEq + 'static,
{
    iter: slice::IterMut<'a, StylesheetSetEntry<S>>,
    guard: &'a SharedRwLockReadGuard<'b>,
    origins_dirty: OriginSet,
    origin_data_validity: PerOrigin<OriginValidity>,
    author_style_disabled: bool,
    had_invalidations: bool,
}

/// The type of rebuild that we need to do for a given stylesheet.
pub enum SheetRebuildKind {
    /// A full rebuild, of both cascade data and invalidation data.
    Full,
    /// A partial rebuild, of only the cascade data.
    CascadeOnly,
}

impl SheetRebuildKind {
    /// Whether the stylesheet invalidation data should be rebuilt.
    pub fn should_rebuild_invalidation(&self) -> bool {
        matches!(*self, SheetRebuildKind::Full)
    }
}

impl<'a, 'b, S> StylesheetFlusher<'a, 'b, S>
where
    'b: 'a,
    S: StylesheetInDocument + PartialEq + 'static,
{
    /// The data validity for a given origin.
    pub fn origin_validity(&self, origin: Origin) -> OriginValidity {
        *self.origin_data_validity.borrow_for_origin(&origin)
    }

    /// Returns whether running the whole flushing process would be a no-op.
    pub fn nothing_to_do(&self) -> bool {
        self.origins_dirty.is_empty()
    }

    /// Returns whether any DOM invalidations were processed as a result of the
    /// stylesheet flush.
    pub fn had_invalidations(&self) -> bool {
        self.had_invalidations
    }
}

#[cfg(debug_assertions)]
impl<'a, 'b, S> Drop for StylesheetFlusher<'a, 'b, S>
where
    'b: 'a,
    S: StylesheetInDocument + PartialEq + 'static,
{
    fn drop(&mut self) {
        debug_assert!(
            self.iter.next().is_none(),
            "You're supposed to fully consume the flusher"
        );
    }
}

impl<'a, 'b, S> Iterator for StylesheetFlusher<'a, 'b, S>
where
    'b: 'a,
    S: StylesheetInDocument + PartialEq + 'static,
{
    type Item = (&'a S, SheetRebuildKind);

    fn next(&mut self) -> Option<Self::Item> {
        use std::mem;

        loop {
            let potential_sheet = match self.iter.next() {
                None => return None,
                Some(s) => s,
            };

            let dirty = mem::replace(&mut potential_sheet.dirty, false);

            if dirty {
                // If the sheet was dirty, we need to do a full rebuild anyway.
                return Some((&potential_sheet.sheet, SheetRebuildKind::Full))
            }

            let origin = potential_sheet.sheet.contents(self.guard).origin;
            if !self.origins_dirty.contains(origin.into()) {
                continue;
            }

            if self.author_style_disabled && matches!(origin, Origin::Author) {
                continue;
            }

            let rebuild_kind = match self.origin_validity(origin) {
                OriginValidity::Valid => continue,
                OriginValidity::CascadeInvalid => SheetRebuildKind::CascadeOnly,
                OriginValidity::FullyInvalid => SheetRebuildKind::Full,
            };

            return Some((&potential_sheet.sheet, rebuild_kind));
        }
    }
}

/// The set of stylesheets effective for a given document.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct StylesheetSet<S>
where
    S: StylesheetInDocument + PartialEq + 'static,
{
    /// The actual list of all the stylesheets that apply to the given document,
    /// each stylesheet associated with a unique ID.
    ///
    /// This is only a list of top-level stylesheets, and as such it doesn't
    /// include recursive `@import` rules.
    entries: Vec<StylesheetSetEntry<S>>,

    /// The invalidations for stylesheets added or removed from this document.
    invalidations: StylesheetInvalidationSet,

    /// The origins whose stylesheets have changed so far.
    origins_dirty: OriginSet,

    /// The validity of the data that was already there for a given origin.
    ///
    /// Note that an origin may appear on `origins_dirty`, but still have
    /// `OriginValidity::Valid`, if only sheets have been appended into it (in
    /// which case the existing data is valid, but the origin needs to be
    /// rebuilt).
    origin_data_validity: PerOrigin<OriginValidity>,

    /// Has author style been disabled?
    author_style_disabled: bool,
}

impl<S> StylesheetSet<S>
where
    S: StylesheetInDocument + PartialEq + 'static,
{
    /// Create a new empty StylesheetSet.
    pub fn new() -> Self {
        StylesheetSet {
            entries: vec![],
            invalidations: StylesheetInvalidationSet::new(),
            origins_dirty: OriginSet::empty(),
            origin_data_validity: Default::default(),
            author_style_disabled: false,
        }
    }

    /// Returns the number of stylesheets in the set.
    pub fn len(&self) -> usize {
        self.entries.len()
    }

    /// Returns the number of stylesheets in the set.
    pub fn get(&self, index: usize) -> Option<&S> {
        self.entries.get(index).map(|s| &s.sheet)
    }

    /// Returns whether author styles have been disabled for the current
    /// stylesheet set.
    pub fn author_style_disabled(&self) -> bool {
        self.author_style_disabled
    }

    fn remove_stylesheet_if_present(&mut self, sheet: &S) {
        self.entries.retain(|entry| entry.sheet != *sheet);
    }

    fn collect_invalidations_for(
        &mut self,
        device: Option<&Device>,
        sheet: &S,
        guard: &SharedRwLockReadGuard,
    ) {
        if let Some(device) = device {
            self.invalidations.collect_invalidations_for(device, sheet, guard);
        }
        self.origins_dirty |= sheet.contents(guard).origin;
    }

    fn set_data_validity_at_least(
        &mut self,
        origin: Origin,
        validity: OriginValidity,
    ) {
        use std::cmp;

        debug_assert!(
            self.origins_dirty.contains(origin.into()),
            "data_validity should be a subset of origins_dirty"
        );

        let existing_validity =
            self.origin_data_validity.borrow_mut_for_origin(&origin);

        *existing_validity = cmp::max(*existing_validity, validity);
    }

    /// Appends a new stylesheet to the current set.
    ///
    /// No device implies not computing invalidations.
    pub fn append_stylesheet(
        &mut self,
        device: Option<&Device>,
        sheet: S,
        guard: &SharedRwLockReadGuard
    ) {
        debug!("StylesheetSet::append_stylesheet");
        self.remove_stylesheet_if_present(&sheet);
        self.collect_invalidations_for(device, &sheet, guard);
        // Appending sheets doesn't alter the validity of the existing data, so
        // we don't need to change `origin_data_validity` here.
        self.entries.push(StylesheetSetEntry::new(sheet));
    }

    /// Prepend a new stylesheet to the current set.
    pub fn prepend_stylesheet(
        &mut self,
        device: Option<&Device>,
        sheet: S,
        guard: &SharedRwLockReadGuard
    ) {
        debug!("StylesheetSet::prepend_stylesheet");
        self.remove_stylesheet_if_present(&sheet);
        self.collect_invalidations_for(device, &sheet, guard);

        // Inserting stylesheets somewhere but at the end changes the validity
        // of the cascade data, but not the invalidation data.
        self.set_data_validity_at_least(sheet.contents(guard).origin, OriginValidity::CascadeInvalid);

        self.entries.insert(0, StylesheetSetEntry::new(sheet));
    }

    /// Insert a given stylesheet before another stylesheet in the document.
    pub fn insert_stylesheet_before(
        &mut self,
        device: Option<&Device>,
        sheet: S,
        before_sheet: S,
        guard: &SharedRwLockReadGuard,
    ) {
        debug!("StylesheetSet::insert_stylesheet_before");
        self.remove_stylesheet_if_present(&sheet);
        let index = self.entries.iter().position(|entry| {
            entry.sheet == before_sheet
        }).expect("`before_sheet` stylesheet not found");
        self.collect_invalidations_for(device, &sheet, guard);

        // Inserting stylesheets somewhere but at the end changes the validity
        // of the cascade data, but not the invalidation data.
        self.set_data_validity_at_least(sheet.contents(guard).origin, OriginValidity::CascadeInvalid);
        self.entries.insert(index, StylesheetSetEntry::new(sheet));
    }

    /// Remove a given stylesheet from the set.
    pub fn remove_stylesheet(
        &mut self,
        device: Option<&Device>,
        sheet: S,
        guard: &SharedRwLockReadGuard,
    ) {
        debug!("StylesheetSet::remove_stylesheet");
        self.remove_stylesheet_if_present(&sheet);

        self.collect_invalidations_for(device, &sheet, guard);

        // Removing sheets makes us tear down the whole cascade and invalidation
        // data.
        self.set_data_validity_at_least(sheet.contents(guard).origin, OriginValidity::FullyInvalid);
    }

    /// Notes that the author style has been disabled for this document.
    pub fn set_author_style_disabled(&mut self, disabled: bool) {
        debug!("StylesheetSet::set_author_style_disabled");
        if self.author_style_disabled == disabled {
            return;
        }
        self.author_style_disabled = disabled;
        self.invalidations.invalidate_fully();
        self.origins_dirty |= Origin::Author;
    }

    /// Returns whether the given set has changed from the last flush.
    pub fn has_changed(&self) -> bool {
        !self.origins_dirty.is_empty()
    }

    /// Flush the current set, unmarking it as dirty, and returns a
    /// `StylesheetFlusher` in order to rebuild the stylist.
    pub fn flush<'a, 'b, E>(
        &'a mut self,
        document_element: Option<E>,
        guard: &'a SharedRwLockReadGuard<'b>,
    ) -> StylesheetFlusher<'a, 'b, S>
    where
        E: TElement,
    {
        use std::mem;

        debug!("StylesheetSet::flush");

        let had_invalidations = self.invalidations.flush(document_element);
        let origins_dirty = mem::replace(&mut self.origins_dirty, OriginSet::empty());
        let origin_data_validity =
            mem::replace(&mut self.origin_data_validity, Default::default());

        StylesheetFlusher {
            iter: self.entries.iter_mut(),
            author_style_disabled: self.author_style_disabled,
            had_invalidations,
            origins_dirty,
            origin_data_validity,
            guard,
        }
    }

    /// Flush stylesheets, but without running any of the invalidation passes.
    #[cfg(feature = "servo")]
    pub fn flush_without_invalidation(&mut self) -> OriginSet {
        use std::mem;

        debug!("StylesheetSet::flush_without_invalidation");

        self.invalidations.clear();
        mem::replace(&mut self.origins_dirty, OriginSet::empty())
    }

    /// Returns an iterator over the current list of stylesheets.
    pub fn iter(&self) -> StylesheetIterator<S> {
        StylesheetIterator(self.entries.iter())
    }

    /// Mark the stylesheets for the specified origin as dirty, because
    /// something external may have invalidated it.
    pub fn force_dirty(&mut self, origins: OriginSet) {
        self.invalidations.invalidate_fully();
        self.origins_dirty |= origins;
        for origin in origins.iter() {
            // We don't know what happened, assume the worse.
            self.set_data_validity_at_least(origin, OriginValidity::FullyInvalid);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::mem;
use std::slice;
use libc::c_void;

#[cfg(feature = "use_glib")]
use glib::translate::*;
use ffi;
use ::enums::{
    Content,
    Status,
    SurfaceType,
};

#[derive(Debug)]
pub struct Surface(*mut ffi::cairo_surface_t, bool);

impl Surface {
    pub unsafe fn from_raw_none(ptr: *mut ffi::cairo_surface_t) -> Surface {
        assert!(!ptr.is_null());
        ffi::cairo_surface_reference(ptr);
        Surface(ptr, false)
    }

    pub unsafe fn from_raw_borrow(ptr: *mut ffi::cairo_surface_t) -> Surface {
        assert!(!ptr.is_null());
        Surface(ptr, true)
    }

    pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_surface_t) -> Surface {
        assert!(!ptr.is_null());
        Surface(ptr, false)
    }

    pub fn to_raw_none(&self) -> *mut ffi::cairo_surface_t {
        self.0
    }

    pub fn create_similar(&self, content: Content, width: i32, height: i32) -> Surface {
        unsafe {
            Self::from_raw_full(ffi::cairo_surface_create_similar(self.0,
                                                                  content.into(),
                                                                  width,
                                                                  height))
        }
    }

    pub fn get_mime_data(&self, mime_type: &str) -> Option<&[u8]> {
        let mut data_ptr: *mut u8 = ptr::null_mut();
        let mut length = 0u64;
        unsafe {
            ffi::cairo_surface_get_mime_data(
                self.to_raw_none(),
                mime_type.to_glib_none().0,
                &mut data_ptr,
                &mut length,
            );
            if !data_ptr.is_null() && length != 0 {
                Some(slice::from_raw_parts(
                    data_ptr as *const u8,
                    length as usize,
                ))
            } else {
                None
            }
        }
    }

    pub fn set_mime_data<T: AsRef<[u8]> + Send + 'static>(&self,
                                                          mime_type: &str,
                                                          slice: T) -> Result<(), Status> {
        let b = Box::new(slice);
        let (size, data) = {
            let slice = (*b).as_ref();
            (slice.len(), slice.as_ptr())
        };

        let user_data = Box::into_raw(b);

        let status = unsafe {
            ffi::cairo_surface_set_mime_data(
                self.to_raw_none(),
                mime_type.to_glib_none().0,
                data,
                size as u64,
                Some(unbox::<T>),
                user_data as *mut _,
                )
        };

        match Status::from(status) {
            Status::Success => Ok(()),
            x => Err(x),
        }
    }

    pub fn supports_mime_type(&self, mime_type: &str) -> bool {
        unsafe {
            ffi::cairo_surface_supports_mime_type(self.0, mime_type.to_glib_none().0).as_bool()
        }
    }
}

#[cfg(feature = "use_glib")]
impl<'a> ToGlibPtr<'a, *mut ffi::cairo_surface_t> for Surface {
    type Storage = &'a Surface;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::cairo_surface_t, Self> {
        Stash(self.to_raw_none(), self)
    }

    #[inline]
    fn to_glib_full(&self) -> *mut ffi::cairo_surface_t {
        unsafe {
            ffi::cairo_surface_reference(self.to_raw_none())
        }
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrNone<*mut ffi::cairo_surface_t> for Surface {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut ffi::cairo_surface_t) -> Surface {
        Self::from_raw_none(ptr)
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrBorrow<*mut ffi::cairo_surface_t> for Surface {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_surface_t) -> Surface {
        Self::from_raw_borrow(ptr)
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrFull<*mut ffi::cairo_surface_t> for Surface {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut ffi::cairo_surface_t) -> Surface {
        Self::from_raw_full(ptr)
    }
}

#[cfg(feature = "use_glib")]
gvalue_impl!(Surface, ffi::cairo_surface_t, ffi::gobject::cairo_gobject_surface_get_type);

impl AsRef<Surface> for Surface {
    fn as_ref(&self) -> &Surface {
        self
    }
}

impl Clone for Surface {
    fn clone(&self) -> Surface {
        unsafe { Self::from_raw_none(self.0) }
    }
}

impl Drop for Surface {
    fn drop(&mut self) {
        if !self.1 {
            unsafe { ffi::cairo_surface_destroy(self.0); }
        }
    }
}

pub trait SurfaceExt {
    fn flush(&self);
    fn finish(&self);
    fn get_type(&self) -> SurfaceType;
    fn status(&self) -> Status;
}

impl<O: AsRef<Surface>> SurfaceExt for O {
    fn flush(&self) {
        unsafe { ffi::cairo_surface_flush(self.as_ref().0); }
    }

    fn finish(&self) {
        unsafe { ffi::cairo_surface_finish(self.as_ref().0); }
    }

    fn get_type(&self) -> SurfaceType {
        unsafe { SurfaceType::from(ffi::cairo_surface_get_type(self.as_ref().0)) }
    }

    fn status(&self) -> Status {
        unsafe { Status::from(ffi::cairo_surface_status(self.as_ref().0)) }
    }
}

pub(crate) trait SurfacePriv {
    unsafe fn set_user_data<K, T>(&self, key: &K, data: Box<T>) -> Result<(), Status>;
}

impl<O: AsRef<Surface>> SurfacePriv for O {
    unsafe fn set_user_data<K, T>(&self, key: &K, data: Box<T>) -> Result<(), Status> {
        let ptr: *mut T = Box::into_raw(data);

        assert_eq!(mem::size_of::<*mut c_void>(), mem::size_of_val(&ptr));

        let status = ffi::cairo_surface_set_user_data(self.as_ref().0, key as *const _ as *mut _,
            ptr as *mut c_void, Some(unbox::<T>));
        match Status::from(status) {
            Status::Success => Ok(()),
            x => Err(x),
        }
    }
}

unsafe extern "C" fn unbox<T>(data: *mut c_void) {
    let data: Box<T> = Box::from_raw(data as *mut T);
    drop(data);
}

#[cfg(test)]
mod tests {
    use Format;
    use ImageSurface;
    use constants::MIME_TYPE_PNG;

    #[test]
    fn mime_data() {
        let surface = ImageSurface::create(Format::ARgb32, 500, 500).unwrap();
        let data = surface.get_mime_data(MIME_TYPE_PNG);
        /* Initially the data for any mime type has to be none */
        assert!(data.is_none());

        assert!(surface.set_mime_data(MIME_TYPE_PNG, &[1u8, 10u8]).is_ok());
        let data = surface.get_mime_data(MIME_TYPE_PNG).unwrap();
        assert_eq!(data, &[1u8, 10u8]);
    }
}
<commit_msg>surface: return a vector with get_mime_data()<commit_after>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::mem;
use std::slice;
use libc::c_void;

#[cfg(feature = "use_glib")]
use glib::translate::*;
use ffi;
use ::enums::{
    Content,
    Status,
    SurfaceType,
};

#[derive(Debug)]
pub struct Surface(*mut ffi::cairo_surface_t, bool);

impl Surface {
    pub unsafe fn from_raw_none(ptr: *mut ffi::cairo_surface_t) -> Surface {
        assert!(!ptr.is_null());
        ffi::cairo_surface_reference(ptr);
        Surface(ptr, false)
    }

    pub unsafe fn from_raw_borrow(ptr: *mut ffi::cairo_surface_t) -> Surface {
        assert!(!ptr.is_null());
        Surface(ptr, true)
    }

    pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_surface_t) -> Surface {
        assert!(!ptr.is_null());
        Surface(ptr, false)
    }

    pub fn to_raw_none(&self) -> *mut ffi::cairo_surface_t {
        self.0
    }

    pub fn create_similar(&self, content: Content, width: i32, height: i32) -> Surface {
        unsafe {
            Self::from_raw_full(ffi::cairo_surface_create_similar(self.0,
                                                                  content.into(),
                                                                  width,
                                                                  height))
        }
    }

    pub fn get_mime_data(&self, mime_type: &str) -> Option<Vec<u8>> {
        let mut data_ptr: *mut u8 = ptr::null_mut();
        let mut length = 0u64;
        unsafe {
            ffi::cairo_surface_get_mime_data(
                self.to_raw_none(),
                mime_type.to_glib_none().0,
                &mut data_ptr,
                &mut length,
            );
            if !data_ptr.is_null() && length != 0 {
                Some(slice::from_raw_parts(
                    data_ptr as *const u8,
                    length as usize,
                ).to_vec())
            } else {
                None
            }
        }
    }

    pub fn set_mime_data<T: AsRef<[u8]> + Send + 'static>(&self,
                                                          mime_type: &str,
                                                          slice: T) -> Result<(), Status> {
        let b = Box::new(slice);
        let (size, data) = {
            let slice = (*b).as_ref();
            (slice.len(), slice.as_ptr())
        };

        let user_data = Box::into_raw(b);

        let status = unsafe {
            ffi::cairo_surface_set_mime_data(
                self.to_raw_none(),
                mime_type.to_glib_none().0,
                data,
                size as u64,
                Some(unbox::<T>),
                user_data as *mut _)
        };

        match Status::from(status) {
            Status::Success => Ok(()),
            x => Err(x),
        }
    }

    pub fn supports_mime_type(&self, mime_type: &str) -> bool {
        unsafe {
            ffi::cairo_surface_supports_mime_type(self.0, mime_type.to_glib_none().0).as_bool()
        }
    }
}

#[cfg(feature = "use_glib")]
impl<'a> ToGlibPtr<'a, *mut ffi::cairo_surface_t> for Surface {
    type Storage = &'a Surface;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::cairo_surface_t, Self> {
        Stash(self.to_raw_none(), self)
    }

    #[inline]
    fn to_glib_full(&self) -> *mut ffi::cairo_surface_t {
        unsafe {
            ffi::cairo_surface_reference(self.to_raw_none())
        }
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrNone<*mut ffi::cairo_surface_t> for Surface {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut ffi::cairo_surface_t) -> Surface {
        Self::from_raw_none(ptr)
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrBorrow<*mut ffi::cairo_surface_t> for Surface {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_surface_t) -> Surface {
        Self::from_raw_borrow(ptr)
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrFull<*mut ffi::cairo_surface_t> for Surface {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut ffi::cairo_surface_t) -> Surface {
        Self::from_raw_full(ptr)
    }
}

#[cfg(feature = "use_glib")]
gvalue_impl!(Surface, ffi::cairo_surface_t, ffi::gobject::cairo_gobject_surface_get_type);

impl AsRef<Surface> for Surface {
    fn as_ref(&self) -> &Surface {
        self
    }
}

impl Clone for Surface {
    fn clone(&self) -> Surface {
        unsafe { Self::from_raw_none(self.0) }
    }
}

impl Drop for Surface {
    fn drop(&mut self) {
        if !self.1 {
            unsafe { ffi::cairo_surface_destroy(self.0); }
        }
    }
}

pub trait SurfaceExt {
    fn flush(&self);
    fn finish(&self);
    fn get_type(&self) -> SurfaceType;
    fn status(&self) -> Status;
}

impl<O: AsRef<Surface>> SurfaceExt for O {
    fn flush(&self) {
        unsafe { ffi::cairo_surface_flush(self.as_ref().0); }
    }

    fn finish(&self) {
        unsafe { ffi::cairo_surface_finish(self.as_ref().0); }
    }

    fn get_type(&self) -> SurfaceType {
        unsafe { SurfaceType::from(ffi::cairo_surface_get_type(self.as_ref().0)) }
    }

    fn status(&self) -> Status {
        unsafe { Status::from(ffi::cairo_surface_status(self.as_ref().0)) }
    }
}

pub(crate) trait SurfacePriv {
    unsafe fn set_user_data<K, T>(&self, key: &K, data: Box<T>) -> Result<(), Status>;
}

impl<O: AsRef<Surface>> SurfacePriv for O {
    unsafe fn set_user_data<K, T>(&self, key: &K, data: Box<T>) -> Result<(), Status> {
        let ptr: *mut T = Box::into_raw(data);

        assert_eq!(mem::size_of::<*mut c_void>(), mem::size_of_val(&ptr));

        let status = ffi::cairo_surface_set_user_data(self.as_ref().0, key as *const _ as *mut _,
            ptr as *mut c_void, Some(unbox::<T>));
        match Status::from(status) {
            Status::Success => Ok(()),
            x => Err(x),
        }
    }
}

unsafe extern "C" fn unbox<T>(data: *mut c_void) {
    let data: Box<T> = Box::from_raw(data as *mut T);
    drop(data);
}

#[cfg(test)]
mod tests {
    use Format;
    use ImageSurface;
    use constants::MIME_TYPE_PNG;

    #[test]
    fn mime_data() {
        let surface = ImageSurface::create(Format::ARgb32, 500, 500).unwrap();
        let data = surface.get_mime_data(MIME_TYPE_PNG);
        /* Initially the data for any mime type has to be none */
        assert!(data.is_none());

        assert!(surface.set_mime_data(MIME_TYPE_PNG, &[1u8, 10u8]).is_ok());
        let data = surface.get_mime_data(MIME_TYPE_PNG).unwrap();
        assert_eq!(data, &[1u8, 10u8]);
    }
}
<|endoftext|>