<commit_before>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

extern crate wayland_client;
use wayland_client::client::{FromPrimitive, Display,
                             Registry, RegistryEventHandler,
                             Seat, SeatEventHandler, SeatCapability,
                             Shm, ShmEventHandler, ShmFormat,
                             Output, OutputEventHandler, OutputSubpixel,
                             OutputTransform, OutputMode};

use std::collections::HashMap;

#[derive(Default)]
struct SeatData {
    name: String,
    capabilities: Vec<String>,
}

#[derive(Default)]
struct ShmData {
    formats: Vec<String>,
}

#[derive(Default)]
struct OutputData {
    x: i32,
    y: i32,
    physical_width: i32,
    physical_height: i32,
    subpixel: String,
    make: String,
    model: String,
    transform: String,
    modes: Vec<OutputModeData>,
}

struct OutputModeData {
    width: i32,
    height: i32,
    refresh: i32,
    flags: String,
}

struct Info {
    registry: Registry,
    seat: Option<Seat>,
    shm: Option<Shm>,
    output: Option<Output>,
    pub roundtrip: bool,
    data: HashMap<String, String>,
    seat_data: SeatData,
    shm_data: ShmData,
    output_data: OutputData,
}

impl Info {
    fn new(registry: Registry) -> Info {
        return Info {
            registry: registry,
            seat: None,
            shm: None,
            output: None,
            roundtrip: true,
            data: HashMap::new(),
            seat_data: Default::default(),
            shm_data: Default::default(),
            output_data: Default::default(),
        };
    }

    fn print_it(&self) {
        for (key, val) in self.data.iter() {
            println!("{}", val);
            match key.as_ref() {
                "wl_shm" => {
                    println!("\tformats: {}",
                             self.shm_data.formats.connect(" "));
                },
                "wl_seat" => {
                    println!("\tname: {}", self.seat_data.name);
                    println!("\tcapabilities: {}",
                             self.seat_data.capabilities.connect(" "));
                },
                "wl_output" => {
                    println!("\tx: {}, y: {},", self.output_data.x,
                             self.output_data.y);
                    println!("\tphysical_width: {} mm, physical_height: {} mm,",
                             self.output_data.physical_width,
                             self.output_data.physical_height);
                    println!("\tmake: '{}', model: '{}',",
                             self.output_data.make, self.output_data.model);
                    println!("\tsubpixel_orientation: '{}', transformation: '{}',",
                             self.output_data.subpixel,
                             self.output_data.transform);
                    for mode in self.output_data.modes.iter() {
                        println!("\tmode:");
                        println!("\t\twidth: {} px, height: {} px, refresh: {} Hz,",
                                 mode.width, mode.height, mode.refresh / 1000);
                        println!("\t\tflags: {}", mode.flags);
                    }
                }
                _ => (),
            }
        }
    }
}

impl RegistryEventHandler for Info {
    fn get_registry(&mut self) -> &mut Registry {
        return &mut self.registry;
    }

    fn on_global(&mut self, name: u32, interface: String, version: u32) {
        self.data.insert(interface.clone(),
                         format!("interface: '{}', version: {}, name: {}",
                                 interface, version, name));

        if interface == "wl_seat" {
            self.roundtrip = true;
            self.seat = self.registry.bind(name, version).ok();
            SeatEventHandler::connect_dispatcher(self);
        } else if interface == "wl_shm" {
            self.roundtrip = true;
            self.shm = self.registry.bind(name, version).ok();
            ShmEventHandler::connect_dispatcher(self);
        } else if interface == "wl_output" {
            self.roundtrip = true;
            self.output = self.registry.bind(name, version).ok();
            OutputEventHandler::connect_dispatcher(self);
        }
    }
}

impl SeatEventHandler for Info {
    fn get_seat(&mut self) -> &mut Seat {
        return self.seat.as_mut().unwrap();
    }

    fn on_capabilities(&mut self, capabilities: u32) {
        if capabilities & (SeatCapability::POINTER as u32) != 0 {
            self.seat_data.capabilities.push("pointer".to_string());
        }
        if capabilities & (SeatCapability::KEYBOARD as u32) != 0 {
            self.seat_data.capabilities.push("keyboard".to_string());
        }
        if capabilities & (SeatCapability::TOUCH as u32) != 0 {
            self.seat_data.capabilities.push("touch".to_string());
        }
    }

    fn on_name(&mut self, name: String) {
        self.seat_data.name = name;
    }
}

impl ShmEventHandler for Info {
    fn get_shm(&mut self) -> &mut Shm {
        return self.shm.as_mut().unwrap();
    }

    fn on_format(&mut self, format: u32) {
        self.shm_data.formats.push(format!("{:?}", ShmFormat::from_u32(format).unwrap()));
    }
}

impl OutputEventHandler for Info {
    fn get_output(&mut self) -> &mut Output {
        return self.output.as_mut().unwrap();
    }

    fn on_geometry(&mut self, x: i32, y: i32, physical_width: i32,
                   physical_height: i32, subpixel: i32, make: String, model:
                   String, transform: i32) {
        self.output_data.x = x;
        self.output_data.y = y;
        self.output_data.physical_width = physical_width;
        self.output_data.physical_height = physical_height;
        self.output_data.subpixel = format!("{:?}", OutputSubpixel::from_u32(subpixel as u32).unwrap());
        self.output_data.make = make;
        self.output_data.model = model;
        self.output_data.transform = format!("{:?}", OutputTransform::from_u32(transform as u32).unwrap());
    }

    fn on_mode(&mut self, flags: u32, width: i32, height: i32, refresh: i32) {
        let mut flags_ = Vec::new();
        if flags & (OutputMode::CURRENT as u32) != 0 {
            flags_.push("current".to_string());
        }
        if flags & (OutputMode::PREFERRED as u32) != 0 {
            flags_.push("preferred".to_string());
        }
        self.output_data.modes.push(OutputModeData {
            width: width,
            height: height,
            refresh: refresh,
            flags: flags_.connect(" "),
        })
    }
}

fn main() {
    let mut display = Display::connect(None).unwrap();
    let mut info = Info::new(display.get_registry().unwrap());
    RegistryEventHandler::connect_dispatcher(&mut info);

    while info.roundtrip {
        info.roundtrip = false;
        display.roundtrip();
    }
    info.print_it();
}
<commit_msg>weston-info: use FromPrimitive::from_i32()<commit_after>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

extern crate wayland_client;
use wayland_client::client::{FromPrimitive, Display,
                             Registry, RegistryEventHandler,
                             Seat, SeatEventHandler, SeatCapability,
                             Shm, ShmEventHandler, ShmFormat,
                             Output, OutputEventHandler, OutputSubpixel,
                             OutputTransform, OutputMode};

use std::collections::HashMap;

#[derive(Default)]
struct SeatData {
    name: String,
    capabilities: Vec<String>,
}

#[derive(Default)]
struct ShmData {
    formats: Vec<String>,
}

#[derive(Default)]
struct OutputData {
    x: i32,
    y: i32,
    physical_width: i32,
    physical_height: i32,
    subpixel: String,
    make: String,
    model: String,
    transform: String,
    modes: Vec<OutputModeData>,
}

struct OutputModeData {
    width: i32,
    height: i32,
    refresh: i32,
    flags: String,
}

struct Info {
    registry: Registry,
    seat: Option<Seat>,
    shm: Option<Shm>,
    output: Option<Output>,
    pub roundtrip: bool,
    data: HashMap<String, String>,
    seat_data: SeatData,
    shm_data: ShmData,
    output_data: OutputData,
}

impl Info {
    fn new(registry: Registry) -> Info {
        return Info {
            registry: registry,
            seat: None,
            shm: None,
            output: None,
            roundtrip: true,
            data: HashMap::new(),
            seat_data: Default::default(),
            shm_data: Default::default(),
            output_data: Default::default(),
        };
    }

    fn print_it(&self) {
        for (key, val) in self.data.iter() {
            println!("{}", val);
            match key.as_ref() {
                "wl_shm" => {
                    println!("\tformats: {}",
                             self.shm_data.formats.connect(" "));
                },
                "wl_seat" => {
                    println!("\tname: {}", self.seat_data.name);
                    println!("\tcapabilities: {}",
                             self.seat_data.capabilities.connect(" "));
                },
                "wl_output" => {
                    println!("\tx: {}, y: {},", self.output_data.x,
                             self.output_data.y);
                    println!("\tphysical_width: {} mm, physical_height: {} mm,",
                             self.output_data.physical_width,
                             self.output_data.physical_height);
                    println!("\tmake: '{}', model: '{}',",
                             self.output_data.make, self.output_data.model);
                    println!("\tsubpixel_orientation: '{}', transformation: '{}',",
                             self.output_data.subpixel,
                             self.output_data.transform);
                    for mode in self.output_data.modes.iter() {
                        println!("\tmode:");
                        println!("\t\twidth: {} px, height: {} px, refresh: {} Hz,",
                                 mode.width, mode.height, mode.refresh / 1000);
                        println!("\t\tflags: {}", mode.flags);
                    }
                }
                _ => (),
            }
        }
    }
}

impl RegistryEventHandler for Info {
    fn get_registry(&mut self) -> &mut Registry {
        return &mut self.registry;
    }

    fn on_global(&mut self, name: u32, interface: String, version: u32) {
        self.data.insert(interface.clone(),
                         format!("interface: '{}', version: {}, name: {}",
                                 interface, version, name));

        if interface == "wl_seat" {
            self.roundtrip = true;
            self.seat = self.registry.bind(name, version).ok();
            SeatEventHandler::connect_dispatcher(self);
        } else if interface == "wl_shm" {
            self.roundtrip = true;
            self.shm = self.registry.bind(name, version).ok();
            ShmEventHandler::connect_dispatcher(self);
        } else if interface == "wl_output" {
            self.roundtrip = true;
            self.output = self.registry.bind(name, version).ok();
            OutputEventHandler::connect_dispatcher(self);
        }
    }
}

impl SeatEventHandler for Info {
    fn get_seat(&mut self) -> &mut Seat {
        return self.seat.as_mut().unwrap();
    }

    fn on_capabilities(&mut self, capabilities: u32) {
        if capabilities & (SeatCapability::POINTER as u32) != 0 {
            self.seat_data.capabilities.push("pointer".to_string());
        }
        if capabilities & (SeatCapability::KEYBOARD as u32) != 0 {
            self.seat_data.capabilities.push("keyboard".to_string());
        }
        if capabilities & (SeatCapability::TOUCH as u32) != 0 {
            self.seat_data.capabilities.push("touch".to_string());
        }
    }

    fn on_name(&mut self, name: String) {
        self.seat_data.name = name;
    }
}

impl ShmEventHandler for Info {
    fn get_shm(&mut self) -> &mut Shm {
        return self.shm.as_mut().unwrap();
    }

    fn on_format(&mut self, format: u32) {
        self.shm_data.formats.push(format!("{:?}", ShmFormat::from_u32(format).unwrap()));
    }
}

impl OutputEventHandler for Info {
    fn get_output(&mut self) -> &mut Output {
        return self.output.as_mut().unwrap();
    }

    fn on_geometry(&mut self, x: i32, y: i32, physical_width: i32,
                   physical_height: i32, subpixel: i32, make: String, model:
                   String, transform: i32) {
        self.output_data.x = x;
        self.output_data.y = y;
        self.output_data.physical_width = physical_width;
        self.output_data.physical_height = physical_height;
        self.output_data.subpixel = format!("{:?}", OutputSubpixel::from_i32(subpixel).unwrap());
        self.output_data.make = make;
        self.output_data.model = model;
        self.output_data.transform = format!("{:?}", OutputTransform::from_i32(transform).unwrap());
    }

    fn on_mode(&mut self, flags: u32, width: i32, height: i32, refresh: i32) {
        let mut flags_ = Vec::new();
        if flags & (OutputMode::CURRENT as u32) != 0 {
            flags_.push("current".to_string());
        }
        if flags & (OutputMode::PREFERRED as u32) != 0 {
            flags_.push("preferred".to_string());
        }
        self.output_data.modes.push(OutputModeData {
            width: width,
            height: height,
            refresh: refresh,
            flags: flags_.connect(" "),
        })
    }
}

fn main() {
    let mut display = Display::connect(None).unwrap();
    let mut info = Info::new(display.get_registry().unwrap());
    RegistryEventHandler::connect_dispatcher(&mut info);

    while info.roundtrip {
        info.roundtrip = false;
        display.roundtrip();
    }
    info.print_it();
}
<|endoftext|>


<commit_before>//! The CXX code generator for constructing and compiling C++ code.
//!
//! This is intended to be used from Cargo build scripts to execute CXX's
//! C++ code generator, set up any additional compiler flags depending on
//! the use case, and make the C++ compiler invocation.
//!
//!

//!
//! # Example
//!
//! Example of a canonical Cargo build script that builds a CXX bridge:
//!
//! ```no_run
//! // build.rs
//!
//! fn main() {
//!     cxx_build::bridge("src/main.rs")
//!         .file("src/demo.cc")
//!         .flag_if_supported("-std=c++11")
//!         .compile("cxxbridge-demo");
//!
//!     println!("cargo:rerun-if-changed=src/main.rs");
//!     println!("cargo:rerun-if-changed=src/demo.cc");
//!     println!("cargo:rerun-if-changed=include/demo.h");
//! }
//! ```
//!
//! A runnable working setup with this build script is shown in the *demo*
//! directory of [https://github.com/dtolnay/cxx].
//!
//! [https://github.com/dtolnay/cxx]: https://github.com/dtolnay/cxx
//!
//!

//!
//! # Alternatives
//!
//! For use in non-Cargo builds like Bazel or Buck, CXX provides an
//! alternate way of invoking the C++ code generator as a standalone command
//! line tool. The tool is packaged as the `cxxbridge-cmd` crate.
//!
//! ```bash
//! $ cargo install cxxbridge-cmd  # or build it from the repo
//!
//! $ cxxbridge src/main.rs --header > path/to/mybridge.h
//! $ cxxbridge src/main.rs > path/to/mybridge.cc
//! ```

#![allow(
    clippy::inherent_to_string,
    clippy::needless_doctest_main,
    clippy::new_without_default,
    clippy::or_fun_call,
    clippy::toplevel_ref_arg
)]

mod cargo;
mod error;
mod gen;
mod paths;
mod syntax;

use crate::error::Result;
use crate::gen::error::report;
use crate::gen::{fs, Opt};
use crate::paths::TargetDir;
use cc::Build;
use std::io::{self, Write};
use std::iter;
use std::path::{Path, PathBuf};
use std::process;

/// This returns a [`cc::Build`] on which you should continue to set up any
/// additional source files or compiler flags, and lastly call its [`compile`]
/// method to execute the C++ build.
///
/// [`compile`]: https://docs.rs/cc/1.0.49/cc/struct.Build.html#method.compile
#[must_use]
pub fn bridge(rust_source_file: impl AsRef<Path>) -> Build {
    bridges(iter::once(rust_source_file))
}

/// `cxx_build::bridge` but for when more than one file contains a
/// #\[cxx::bridge\] module.
///
/// ```no_run
/// let source_files = vec!["src/main.rs", "src/path/to/other.rs"];
/// cxx_build::bridges(source_files)
///     .file("src/demo.cc")
///     .flag_if_supported("-std=c++11")
///     .compile("cxxbridge-demo");
/// ```
#[must_use]
pub fn bridges(rust_source_files: impl IntoIterator<Item = impl AsRef<Path>>) -> Build {
    let ref mut rust_source_files = rust_source_files.into_iter();
    build(rust_source_files).unwrap_or_else(|err| {
        let _ = writeln!(io::stderr(), "\n\ncxxbridge error: {}\n\n", report(err));
        process::exit(1);
    })
}

struct Project {
    out_dir: PathBuf,
    target_dir: TargetDir,
}

impl Project {
    fn init() -> Result<Self> {
        let out_dir = paths::out_dir()?;

        let target_dir = match cargo::target_dir() {
            target_dir @ TargetDir::Path(_) => target_dir,
            // Fallback if Cargo did not work.
            TargetDir::Unknown => paths::search_parents_for_target_dir(&out_dir),
        };

        Ok(Project {
            out_dir,
            target_dir,
        })
    }
}

fn build(rust_source_files: &mut dyn Iterator<Item = impl AsRef<Path>>) -> Result<Build> {
    let ref prj = Project::init()?;
    let mut build = paths::cc_build(prj);
    build.cpp(true);
    build.cpp_link_stdlib(None); // linked via link-cplusplus crate
    write_header(prj);

    for path in rust_source_files {
        generate_bridge(prj, &mut build, path.as_ref())?;
    }

    Ok(build)
}

fn write_header(prj: &Project) {
    let ref cxx_h = paths::include_dir(prj).join("rust").join("cxx.h");
    let _ = write(cxx_h, gen::include::HEADER.as_bytes());
}

fn generate_bridge(prj: &Project, build: &mut Build, rust_source_file: &Path) -> Result<()> {
    let opt = Opt::default();
    let generated = gen::generate_from_path(rust_source_file, &opt);

    let header_path = paths::out_with_extension(prj, rust_source_file, ".h")?;
    write(&header_path, &generated.header)?;
    paths::symlink_header(prj, &header_path, rust_source_file);

    let implementation_path = paths::out_with_extension(prj, rust_source_file, ".cc")?;
    write(&implementation_path, &generated.implementation)?;
    build.file(&implementation_path);
    Ok(())
}

fn write(path: &Path, content: &[u8]) -> Result<()> {
    if path.exists() {
        if let Ok(existing) = fs::read(path) {
            if existing == content {
                // Avoid bumping modified time with unchanged contents.
                return Ok(());
            }
        }
        let _ = fs::remove_file(path);
    } else {
        let _ = fs::create_dir_all(path.parent().unwrap());
    }
    fs::write(path, content)?;
    Ok(())
}
<commit_msg>Propagate create dir error if subsequent write fails<commit_after>//! The CXX code generator for constructing and compiling C++ code.
//!
//! This is intended to be used from Cargo build scripts to execute CXX's
//! C++ code generator, set up any additional compiler flags depending on
//! the use case, and make the C++ compiler invocation.
//!
//!

//!
//! # Example
//!
//! Example of a canonical Cargo build script that builds a CXX bridge:
//!
//! ```no_run
//! // build.rs
//!
//! fn main() {
//!     cxx_build::bridge("src/main.rs")
//!         .file("src/demo.cc")
//!         .flag_if_supported("-std=c++11")
//!         .compile("cxxbridge-demo");
//!
//!     println!("cargo:rerun-if-changed=src/main.rs");
//!     println!("cargo:rerun-if-changed=src/demo.cc");
//!     println!("cargo:rerun-if-changed=include/demo.h");
//! }
//! ```
//!
//! A runnable working setup with this build script is shown in the *demo*
//! directory of [https://github.com/dtolnay/cxx].
//!
//! [https://github.com/dtolnay/cxx]: https://github.com/dtolnay/cxx
//!
//!

//!
//! # Alternatives
//!
//! For use in non-Cargo builds like Bazel or Buck, CXX provides an
//! alternate way of invoking the C++ code generator as a standalone command
//! line tool. The tool is packaged as the `cxxbridge-cmd` crate.
//!
//! ```bash
//! $ cargo install cxxbridge-cmd  # or build it from the repo
//!
//! $ cxxbridge src/main.rs --header > path/to/mybridge.h
//! $ cxxbridge src/main.rs > path/to/mybridge.cc
//! ```

#![allow(
    clippy::inherent_to_string,
    clippy::needless_doctest_main,
    clippy::new_without_default,
    clippy::or_fun_call,
    clippy::toplevel_ref_arg
)]

mod cargo;
mod error;
mod gen;
mod paths;
mod syntax;

use crate::error::{Error, Result};
use crate::gen::error::report;
use crate::gen::{fs, Opt};
use crate::paths::TargetDir;
use cc::Build;
use std::io::{self, Write};
use std::iter;
use std::path::{Path, PathBuf};
use std::process;

/// This returns a [`cc::Build`] on which you should continue to set up any
/// additional source files or compiler flags, and lastly call its [`compile`]
/// method to execute the C++ build.
///
/// [`compile`]: https://docs.rs/cc/1.0.49/cc/struct.Build.html#method.compile
#[must_use]
pub fn bridge(rust_source_file: impl AsRef<Path>) -> Build {
    bridges(iter::once(rust_source_file))
}

/// `cxx_build::bridge` but for when more than one file contains a
/// #\[cxx::bridge\] module.
///
/// ```no_run
/// let source_files = vec!["src/main.rs", "src/path/to/other.rs"];
/// cxx_build::bridges(source_files)
///     .file("src/demo.cc")
///     .flag_if_supported("-std=c++11")
///     .compile("cxxbridge-demo");
/// ```
#[must_use]
pub fn bridges(rust_source_files: impl IntoIterator<Item = impl AsRef<Path>>) -> Build {
    let ref mut rust_source_files = rust_source_files.into_iter();
    build(rust_source_files).unwrap_or_else(|err| {
        let _ = writeln!(io::stderr(), "\n\ncxxbridge error: {}\n\n", report(err));
        process::exit(1);
    })
}

struct Project {
    out_dir: PathBuf,
    target_dir: TargetDir,
}

impl Project {
    fn init() -> Result<Self> {
        let out_dir = paths::out_dir()?;

        let target_dir = match cargo::target_dir() {
            target_dir @ TargetDir::Path(_) => target_dir,
            // Fallback if Cargo did not work.
            TargetDir::Unknown => paths::search_parents_for_target_dir(&out_dir),
        };

        Ok(Project {
            out_dir,
            target_dir,
        })
    }
}

fn build(rust_source_files: &mut dyn Iterator<Item = impl AsRef<Path>>) -> Result<Build> {
    let ref prj = Project::init()?;
    let mut build = paths::cc_build(prj);
    build.cpp(true);
    build.cpp_link_stdlib(None); // linked via link-cplusplus crate
    write_header(prj);

    for path in rust_source_files {
        generate_bridge(prj, &mut build, path.as_ref())?;
    }

    Ok(build)
}

fn write_header(prj: &Project) {
    let ref cxx_h = paths::include_dir(prj).join("rust").join("cxx.h");
    let _ = write(cxx_h, gen::include::HEADER.as_bytes());
}

fn generate_bridge(prj: &Project, build: &mut Build, rust_source_file: &Path) -> Result<()> {
    let opt = Opt::default();
    let generated = gen::generate_from_path(rust_source_file, &opt);

    let header_path = paths::out_with_extension(prj, rust_source_file, ".h")?;
    write(&header_path, &generated.header)?;
    paths::symlink_header(prj, &header_path, rust_source_file);

    let implementation_path = paths::out_with_extension(prj, rust_source_file, ".cc")?;
    write(&implementation_path, &generated.implementation)?;
    build.file(&implementation_path);
    Ok(())
}

fn write(path: &Path, content: &[u8]) -> Result<()> {
    let mut create_dir_error = None;
    if path.exists() {
        if let Ok(existing) = fs::read(path) {
            if existing == content {
                // Avoid bumping modified time with unchanged contents.
                return Ok(());
            }
        }
        let _ = fs::remove_file(path);
    } else {
        let parent = path.parent().unwrap();
        create_dir_error = fs::create_dir_all(parent).err();
    }

    match fs::write(path, content) {
        // As long as write succeeded, ignore any create_dir_all error.
        Ok(()) => Ok(()),
        // If create_dir_all and write both failed, prefer the first error.
        Err(err) => Err(Error::Fs(create_dir_error.unwrap_or(err))),
    }
}
<|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/. */

/// Gecko's pseudo-element definition.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum PseudoElement {
    % for pseudo in PSEUDOS:
        /// ${pseudo.value}
        % if pseudo.is_tree_pseudo_element():
        ${pseudo.capitalized()}(Box<[Atom]>),
        % else:
        ${pseudo.capitalized()},
        % endif
    % endfor
}

/// Important: If you change this, you should also update Gecko's
/// nsCSSPseudoElements::IsEagerlyCascadedInServo.
<% EAGER_PSEUDOS = ["Before", "After", "FirstLine", "FirstLetter"] %>
<% TREE_PSEUDOS = [pseudo for pseudo in PSEUDOS if pseudo.is_tree_pseudo_element()] %>
<% SIMPLE_PSEUDOS = [pseudo for pseudo in PSEUDOS if not pseudo.is_tree_pseudo_element()] %>

/// The number of eager pseudo-elements.
pub const EAGER_PSEUDO_COUNT: usize = ${len(EAGER_PSEUDOS)};

/// The number of non-functional pseudo-elements.
pub const SIMPLE_PSEUDO_COUNT: usize = ${len(SIMPLE_PSEUDOS)};

/// The number of tree pseudo-elements.
pub const TREE_PSEUDO_COUNT: usize = ${len(TREE_PSEUDOS)};

/// The number of all pseudo-elements.
pub const PSEUDO_COUNT: usize = ${len(PSEUDOS)};

/// The list of eager pseudos.
pub const EAGER_PSEUDOS: [PseudoElement; EAGER_PSEUDO_COUNT] = [
    % for eager_pseudo_name in EAGER_PSEUDOS:
    PseudoElement::${eager_pseudo_name},
    % endfor
];

<%def name="pseudo_element_variant(pseudo, tree_arg='..')">\
PseudoElement::${pseudo.capitalized()}${"({})".format(tree_arg) if pseudo.is_tree_pseudo_element() else ""}\
</%def>

impl PseudoElement {
    /// Get the pseudo-element as an atom.
    #[inline]
    pub fn atom(&self) -> Atom {
        match *self {
            % for pseudo in PSEUDOS:
                ${pseudo_element_variant(pseudo)} => atom!("${pseudo.value}"),
            % endfor
        }
    }

    /// Returns an index of the pseudo-element.
    #[inline]
    pub fn index(&self) -> usize {
        match *self {
            % for i, pseudo in enumerate(PSEUDOS):
            ${pseudo_element_variant(pseudo)} => ${i},
            % endfor
        }
    }

    /// Returns an array of `None` values.
    ///
    /// FIXME(emilio): Integer generics can't come soon enough.
    pub fn pseudo_none_array<T>() -> [Option<T>; PSEUDO_COUNT] {
        [
            ${",\n            ".join(["None" for pseudo in PSEUDOS])}
        ]
    }

    /// Whether this pseudo-element is an anonymous box.
    #[inline]
    pub fn is_anon_box(&self) -> bool {
        match *self {
            % for pseudo in PSEUDOS:
                % if pseudo.is_anon_box():
                    ${pseudo_element_variant(pseudo)} => true,
                % endif
            % endfor
            _ => false,
        }
    }

    /// Whether this pseudo-element is eagerly-cascaded.
    #[inline]
    pub fn is_eager(&self) -> bool {
        matches!(*self,
                 ${" | ".join(map(lambda name: "PseudoElement::{}".format(name), EAGER_PSEUDOS))})
    }

    /// Whether this pseudo-element is tree pseudo-element.
    #[inline]
    pub fn is_tree_pseudo_element(&self) -> bool {
        match *self {
            % for pseudo in TREE_PSEUDOS:
            ${pseudo_element_variant(pseudo)} => true,
            % endfor
            _ => false,
        }
    }

    /// Gets the flags associated to this pseudo-element, or 0 if it's an
    /// anonymous box.
    pub fn flags(&self) -> u32 {
        match *self {
            % for pseudo in PSEUDOS:
                ${pseudo_element_variant(pseudo)} =>
                % if pseudo.is_tree_pseudo_element():
                    0,
                % elif pseudo.is_anon_box():
                    structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS,
                % else:
                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_${pseudo.original_ident},
                % endif
            % endfor
        }
    }

    /// Construct a pseudo-element from a `CSSPseudoElementType`.
    #[inline]
    pub fn from_pseudo_type(type_: CSSPseudoElementType) -> Option<Self> {
        match type_ {
            % for pseudo in PSEUDOS:
                % if not pseudo.is_anon_box():
                    CSSPseudoElementType::${pseudo.original_ident} => {
                        Some(${pseudo_element_variant(pseudo)})
                    },
                % endif
            % endfor
            _ => None,
        }
    }

    /// Construct a `CSSPseudoElementType` from a pseudo-element
    #[inline]
    pub fn pseudo_type(&self) -> CSSPseudoElementType {
        use gecko_bindings::structs::CSSPseudoElementType_InheritingAnonBox;

        match *self {
            % for pseudo in PSEUDOS:
                % if not pseudo.is_anon_box():
                    PseudoElement::${pseudo.capitalized()} => CSSPseudoElementType::${pseudo.original_ident},
                % elif pseudo.is_tree_pseudo_element():
                    PseudoElement::${pseudo.capitalized()}(..) => CSSPseudoElementType::XULTree,
                % elif pseudo.is_inheriting_anon_box():
                    PseudoElement::${pseudo.capitalized()} => CSSPseudoElementType_InheritingAnonBox,
                % else:
                    PseudoElement::${pseudo.capitalized()} => CSSPseudoElementType::NonInheritingAnonBox,
                % endif
            % endfor
        }
    }

    /// Get a PseudoInfo for a pseudo
    pub fn pseudo_info(&self) -> (*mut structs::nsAtom, CSSPseudoElementType) {
        (self.atom().as_ptr(), self.pseudo_type())
    }

    /// Get the argument list of a tree pseudo-element.
    #[inline]
    pub fn tree_pseudo_args(&self) -> Option<<&[Atom]> {
        match *self {
            % for pseudo in TREE_PSEUDOS:
            PseudoElement::${pseudo.capitalized()}(ref args) => Some(args),
            % endfor
            _ => None,
        }
    }

    /// Construct a pseudo-element from an `Atom`.
    #[inline]
    pub fn from_atom(atom: &Atom) -> Option<Self> {
        % for pseudo in PSEUDOS:
            % if pseudo.is_tree_pseudo_element():
                // We cannot generate ${pseudo_element_variant(pseudo)} from just an atom.
            % else:
                if atom == &atom!("${pseudo.value}") {
                    return Some(${pseudo_element_variant(pseudo)});
                }
            % endif
        % endfor
        None
    }

    /// Construct a pseudo-element from an anonymous box `Atom`.
    #[inline]
    pub fn from_anon_box_atom(atom: &Atom) -> Option<Self> {
        % for pseudo in PSEUDOS:
            % if pseudo.is_tree_pseudo_element():
                // We cannot generate ${pseudo_element_variant(pseudo)} from just an atom.
            % elif pseudo.is_anon_box():
                if atom == &atom!("${pseudo.value}") {
                    return Some(${pseudo_element_variant(pseudo)});
                }
            % endif
        % endfor
        None
    }

    /// Construct a tree pseudo-element from atom and args.
    #[inline]
    pub fn from_tree_pseudo_atom(atom: &Atom, args: Box<[Atom]>) -> Option<Self> {
        % for pseudo in PSEUDOS:
            % if pseudo.is_tree_pseudo_element():
                if atom == &atom!("${pseudo.value}") {
                    return Some(PseudoElement::${pseudo.capitalized()}(args));
                }
            % endif
        % endfor
        None
    }

    /// Constructs an atom from a string of text, and whether we're in a
    /// user-agent stylesheet.
    ///
    /// If we're not in a user-agent stylesheet, we will never parse anonymous
    /// box pseudo-elements.
    ///
    /// Returns `None` if the pseudo-element is not recognised.
    #[inline]
    pub fn from_slice(name: &str) -> Option<Self> {
        // We don't need to support tree pseudos because functional
        // pseudo-elements needs arguments, and thus should be created
        // via other methods.
        match_ignore_ascii_case! { name,
            % for pseudo in SIMPLE_PSEUDOS:
            "${pseudo.value[1:]}" => {
                return Some(${pseudo_element_variant(pseudo)})
            }
            % endfor
            _ => {
                // FIXME: -moz-tree check should probably be
                // ascii-case-insensitive.
                if name.starts_with("-moz-tree-") {
                    return PseudoElement::tree_pseudo_element(name, Box::new([]))
                }
            }
        }

        None
    }

    /// Constructs a tree pseudo-element from the given name and arguments.
    /// "name" must start with "-moz-tree-".
    ///
    /// Returns `None` if the pseudo-element is not recognized.
    #[inline]
    pub fn tree_pseudo_element(name: &str, args: Box<[Atom]>) -> Option<Self> {
        debug_assert!(name.starts_with("-moz-tree-"));
        let tree_part = &name[10..];
        % for pseudo in TREE_PSEUDOS:
            if tree_part.eq_ignore_ascii_case("${pseudo.value[11:]}") {
                return Some(${pseudo_element_variant(pseudo, "args")});
            }
        % endfor
        None
    }
}

impl ToCss for PseudoElement {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        dest.write_char(':')?;
        match *self {
            % for pseudo in PSEUDOS:
                ${pseudo_element_variant(pseudo)} => dest.write_str("${pseudo.value}")?,
            % endfor
        }
        if let Some(args) = self.tree_pseudo_args() {
            if !args.is_empty() {
                dest.write_char('(')?;
                let mut iter = args.iter();
                if let Some(first) = iter.next() {
                    serialize_atom_identifier(&first, dest)?;
                    for item in iter {
                        dest.write_str(", ")?;
                        serialize_atom_identifier(item, dest)?;
                    }
                }
                dest.write_char(')')?;
            }
        }
        Ok(())
    }
}
<commit_msg>style: Unprefix :-moz-selection.<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/. */

/// Gecko's pseudo-element definition.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum PseudoElement {
    % for pseudo in PSEUDOS:
        /// ${pseudo.value}
        % if pseudo.is_tree_pseudo_element():
        ${pseudo.capitalized()}(Box<[Atom]>),
        % else:
        ${pseudo.capitalized()},
        % endif
    % endfor
}

/// Important: If you change this, you should also update Gecko's
/// nsCSSPseudoElements::IsEagerlyCascadedInServo.
<% EAGER_PSEUDOS = ["Before", "After", "FirstLine", "FirstLetter"] %>
<% TREE_PSEUDOS = [pseudo for pseudo in PSEUDOS if pseudo.is_tree_pseudo_element()] %>
<% SIMPLE_PSEUDOS = [pseudo for pseudo in PSEUDOS if not pseudo.is_tree_pseudo_element()] %>

/// The number of eager pseudo-elements.
pub const EAGER_PSEUDO_COUNT: usize = ${len(EAGER_PSEUDOS)};

/// The number of non-functional pseudo-elements.
pub const SIMPLE_PSEUDO_COUNT: usize = ${len(SIMPLE_PSEUDOS)};

/// The number of tree pseudo-elements.
pub const TREE_PSEUDO_COUNT: usize = ${len(TREE_PSEUDOS)};

/// The number of all pseudo-elements.
pub const PSEUDO_COUNT: usize = ${len(PSEUDOS)};

/// The list of eager pseudos.
pub const EAGER_PSEUDOS: [PseudoElement; EAGER_PSEUDO_COUNT] = [
    % for eager_pseudo_name in EAGER_PSEUDOS:
    PseudoElement::${eager_pseudo_name},
    % endfor
];

<%def name="pseudo_element_variant(pseudo, tree_arg='..')">\
PseudoElement::${pseudo.capitalized()}${"({})".format(tree_arg) if pseudo.is_tree_pseudo_element() else ""}\
</%def>

impl PseudoElement {
    /// Get the pseudo-element as an atom.
    #[inline]
    pub fn atom(&self) -> Atom {
        match *self {
            % for pseudo in PSEUDOS:
                ${pseudo_element_variant(pseudo)} => atom!("${pseudo.value}"),
            % endfor
        }
    }

    /// Returns an index of the pseudo-element.
    #[inline]
    pub fn index(&self) -> usize {
        match *self {
            % for i, pseudo in enumerate(PSEUDOS):
            ${pseudo_element_variant(pseudo)} => ${i},
            % endfor
        }
    }

    /// Returns an array of `None` values.
    ///
    /// FIXME(emilio): Integer generics can't come soon enough.
    pub fn pseudo_none_array<T>() -> [Option<T>; PSEUDO_COUNT] {
        [
            ${",\n            ".join(["None" for pseudo in PSEUDOS])}
        ]
    }

    /// Whether this pseudo-element is an anonymous box.
    #[inline]
    pub fn is_anon_box(&self) -> bool {
        match *self {
            % for pseudo in PSEUDOS:
                % if pseudo.is_anon_box():
                    ${pseudo_element_variant(pseudo)} => true,
                % endif
            % endfor
            _ => false,
        }
    }

    /// Whether this pseudo-element is eagerly-cascaded.
    #[inline]
    pub fn is_eager(&self) -> bool {
        matches!(*self,
                 ${" | ".join(map(lambda name: "PseudoElement::{}".format(name), EAGER_PSEUDOS))})
    }

    /// Whether this pseudo-element is tree pseudo-element.
    #[inline]
    pub fn is_tree_pseudo_element(&self) -> bool {
        match *self {
            % for pseudo in TREE_PSEUDOS:
            ${pseudo_element_variant(pseudo)} => true,
            % endfor
            _ => false,
        }
    }

    /// Gets the flags associated to this pseudo-element, or 0 if it's an
    /// anonymous box.
    pub fn flags(&self) -> u32 {
        match *self {
            % for pseudo in PSEUDOS:
                ${pseudo_element_variant(pseudo)} =>
                % if pseudo.is_tree_pseudo_element():
                    0,
                % elif pseudo.is_anon_box():
                    structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS,
                % else:
                    structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_${pseudo.original_ident},
                % endif
            % endfor
        }
    }

    /// Construct a pseudo-element from a `CSSPseudoElementType`.
    #[inline]
    pub fn from_pseudo_type(type_: CSSPseudoElementType) -> Option<Self> {
        match type_ {
            % for pseudo in PSEUDOS:
                % if not pseudo.is_anon_box():
                    CSSPseudoElementType::${pseudo.original_ident} => {
                        Some(${pseudo_element_variant(pseudo)})
                    },
                % endif
            % endfor
            _ => None,
        }
    }

    /// Construct a `CSSPseudoElementType` from a pseudo-element
    #[inline]
    pub fn pseudo_type(&self) -> CSSPseudoElementType {
        use gecko_bindings::structs::CSSPseudoElementType_InheritingAnonBox;

        match *self {
            % for pseudo in PSEUDOS:
                % if not pseudo.is_anon_box():
                    PseudoElement::${pseudo.capitalized()} => CSSPseudoElementType::${pseudo.original_ident},
                % elif pseudo.is_tree_pseudo_element():
                    PseudoElement::${pseudo.capitalized()}(..) => CSSPseudoElementType::XULTree,
                % elif pseudo.is_inheriting_anon_box():
                    PseudoElement::${pseudo.capitalized()} => CSSPseudoElementType_InheritingAnonBox,
                % else:
                    PseudoElement::${pseudo.capitalized()} => CSSPseudoElementType::NonInheritingAnonBox,
                % endif
            % endfor
        }
    }

    /// Get a PseudoInfo for a pseudo
    pub fn pseudo_info(&self) -> (*mut structs::nsAtom, CSSPseudoElementType) {
        (self.atom().as_ptr(), self.pseudo_type())
    }

    /// Get the argument list of a tree pseudo-element.
    #[inline]
    pub fn tree_pseudo_args(&self) -> Option<<&[Atom]> {
        match *self {
            % for pseudo in TREE_PSEUDOS:
            PseudoElement::${pseudo.capitalized()}(ref args) => Some(args),
            % endfor
            _ => None,
        }
    }

    /// Construct a pseudo-element from an `Atom`.
    #[inline]
    pub fn from_atom(atom: &Atom) -> Option<Self> {
        % for pseudo in PSEUDOS:
            % if pseudo.is_tree_pseudo_element():
                // We cannot generate ${pseudo_element_variant(pseudo)} from just an atom.
            % else:
                if atom == &atom!("${pseudo.value}") {
                    return Some(${pseudo_element_variant(pseudo)});
                }
            % endif
        % endfor
        None
    }

    /// Construct a pseudo-element from an anonymous box `Atom`.
    #[inline]
    pub fn from_anon_box_atom(atom: &Atom) -> Option<Self> {
        % for pseudo in PSEUDOS:
            % if pseudo.is_tree_pseudo_element():
                // We cannot generate ${pseudo_element_variant(pseudo)} from just an atom.
            % elif pseudo.is_anon_box():
                if atom == &atom!("${pseudo.value}") {
                    return Some(${pseudo_element_variant(pseudo)});
                }
            % endif
        % endfor
        None
    }

    /// Construct a tree pseudo-element from atom and args.
    #[inline]
    pub fn from_tree_pseudo_atom(atom: &Atom, args: Box<[Atom]>) -> Option<Self> {
        % for pseudo in PSEUDOS:
            % if pseudo.is_tree_pseudo_element():
                if atom == &atom!("${pseudo.value}") {
                    return Some(PseudoElement::${pseudo.capitalized()}(args));
                }
            % endif
        % endfor
        None
    }

    /// Constructs a pseudo-element from a string of text.
    ///
    /// Returns `None` if the pseudo-element is not recognised.
    #[inline]
    pub fn from_slice(name: &str) -> Option<Self> {
        // We don't need to support tree pseudos because functional
        // pseudo-elements needs arguments, and thus should be created
        // via other methods.
        match_ignore_ascii_case! { name,
            % for pseudo in SIMPLE_PSEUDOS:
            "${pseudo.value[1:]}" => {
                return Some(${pseudo_element_variant(pseudo)})
            }
            % endfor
            // Alias "-moz-selection" to "selection" at parse time.
            "-moz-selection" => {
                return Some(PseudoElement::Selection);
            }
            _ => {
                // FIXME: -moz-tree check should probably be
                // ascii-case-insensitive.
                if name.starts_with("-moz-tree-") {
                    return PseudoElement::tree_pseudo_element(name, Box::new([]))
                }
            }
        }

        None
    }

    /// Constructs a tree pseudo-element from the given name and arguments.
    /// "name" must start with "-moz-tree-".
    ///
    /// Returns `None` if the pseudo-element is not recognized.
    #[inline]
    pub fn tree_pseudo_element(name: &str, args: Box<[Atom]>) -> Option<Self> {
        debug_assert!(name.starts_with("-moz-tree-"));
        let tree_part = &name[10..];
        % for pseudo in TREE_PSEUDOS:
            if tree_part.eq_ignore_ascii_case("${pseudo.value[11:]}") {
                return Some(${pseudo_element_variant(pseudo, "args")});
            }
        % endfor
        None
    }
}

impl ToCss for PseudoElement {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        dest.write_char(':')?;
        match *self {
            % for pseudo in PSEUDOS:
                ${pseudo_element_variant(pseudo)} => dest.write_str("${pseudo.value}")?,
            % endfor
        }
        if let Some(args) = self.tree_pseudo_args() {
            if !args.is_empty() {
                dest.write_char('(')?;
                let mut iter = args.iter();
                if let Some(first) = iter.next() {
                    serialize_atom_identifier(&first, dest)?;
                    for item in iter {
                        dest.write_str(", ")?;
                        serialize_atom_identifier(item, dest)?;
                    }
                }
                dest.write_char(')')?;
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use nom::{ConsumerState, FileProducer, Producer};
use std::io::{Error, ErrorKind, Result};
use std::u32;
use std::fs::File;

use utility::{ErrorKind, ReadStream};

use metadata::{
  Metadata, Data,
  StreamInfo, CueSheet, VorbisComment, Picture,
  PictureType,
};
use metadata::types::Consumer;

// Will return true when the unwrapped value of `option` and `other` match
// or `option` is `Option::None`, otherwise false.
#[inline]
pub fn optional_eq<T: Eq>(option: Option<T>, other: T) -> bool {
  option.map_or(true, |value| value == other)
}

// With the given filename, return all metadata blocks available.
//
// This function expects a flac file, but will return a proper `Result::Err`
// when things go wrong.
//
// # Failures
//
// * `ErrorKind::NotFound` is returned when the given filename isn't found.
// * `ErrorKind::InvalidData` is returned when the data within the file
//   isn't valid FLAC data.
pub fn get_metadata(filename: &str) -> Result<Vec<Metadata>> {
  File::open(filename).and_then(|file| {
    let mut stream   = ReadStream::new(file);
    let mut consumer = Consumer::new();
    let mut is_error = false;

    loop {
      match consumer.handle(&mut stream) {
        Ok(_)                         => break,
        Err(ErrorKind::Consumed(_))   => continue,
        Err(ErrorKind::Incomplete(_)) => continue,
        Err(_)                        => {
          is_error = true;

          break;
        }
      }
    }

    if is_error {
      let error_str = "parser: couldn't find any metadata";

      Err(Error::new(ErrorKind::InvalidData, error_str))
    } else {
      Ok(consumer.data)
    }
  })
}

/// Reads and returns the `StreamInfo` metadata block of the given FLAC
/// file.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found
///   or there is no `StreamInfo` within the file.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
///
/// match metadata::get_stream_info("path/to/file.flac") {
///   Ok(stream_info) => {
///     // Use the stream_info variable...
///   }
///   Err(error)      => println!("{}", error),
/// }
/// ```
///
/// Or just ignore the errors:
///
/// ```no_run
/// use flac::metadata;
///
/// let stream_info = metadata::get_stream_info("path/to/file.flac").unwrap();
/// ```
pub fn get_stream_info(filename: &str) -> Result<StreamInfo> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find StreamInfo";
    let mut result = Err(Error::new(ErrorKind::NotFound, error_str));

    for block in blocks {
      if let Data::StreamInfo(stream_info) = block.data {
        result = Ok(stream_info);
        break;
      }
    }

    result
  })
}

/// Reads and returns the `VorbisComment` metadata block of the given FLAC
/// file.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found
///   or there is no `VorbisComment` within the file.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
///
/// match metadata::get_vorbis_comment("path/to/file.flac") {
///   Ok(vorbis_comment) => {
///     // Use the vorbis_comment variable...
///   }
///   Err(error)         => println!("{}", error),
/// }
/// ```
///
/// Or just ignore the errors:
///
/// ```no_run
/// use flac::metadata;
///
/// let vorbis_comment =
///   metadata::get_vorbis_comment("path/to/file.flac").unwrap();
/// ```
pub fn get_vorbis_comment(filename: &str) -> Result<VorbisComment> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find VorbisComment";
    let mut result = Err(Error::new(ErrorKind::NotFound, error_str));

    for block in blocks {
      if let Data::VorbisComment(vorbis_comment) = block.data {
        result = Ok(vorbis_comment);
        break;
      }
    }

    result
  })
}

/// Reads and returns the `CueSheet` metadata block of the given FLAC file.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found
///   or there is no `CueSheet` within the file.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
///
/// match metadata::get_cue_sheet("path/to/file.flac") {
///   Ok(cue_sheet) => {
///     // Use the cue_sheet variable...
///   }
///   Err(error)    => println!("{}", error),
/// }
/// ```
///
/// Or just ignore the errors
///
/// ```no_run
/// use flac::metadata;
///
/// let cue_sheet = metadata::get_cue_sheet("path/to/file.flac").unwrap();
/// ```
pub fn get_cue_sheet(filename: &str) -> Result<CueSheet> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find CueSheet";
    let mut result = Err(Error::new(ErrorKind::NotFound, error_str));

    for block in blocks {
      if let Data::CueSheet(cue_sheet) = block.data {
        result = Ok(cue_sheet);
        break;
      }
    }

    result
  })
}

/// Reads and returns a `Picture` metadata block of the given FLAC file.
///
/// There can be more than one `Picture` block in a file and this function
/// takes optional, that being `Option<T>`, parameters that act as
/// constraints to search within. The `Picture` with the largest area
/// matching all constraints will be returned.
///
/// Putting `None` into any of the optional constraints conveys that you
/// want any of that parameter. Otherwise it will try to look for the image
/// that matches within the given constraints.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found,
///   there is no `Picture` within the file, or no `Picture` that fits the
///   given constraints.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
/// use flac::metadata::PictureType;
///
/// let result = metadata::get_picture("path/to/file.flac",
///                                    Some(PictureType::FileIcon),
///                                    Some("image/gif"),
///                                    None, None, None,
///                                    None, None);
///
/// match result {
///   Ok(picture) => {
///     // Use the picture variable...
///   }
///   Err(error)  => println!("{}", error),
/// }
/// ```
///
/// Or just ignore the errors:
///
/// ```no_run
/// use flac::metadata;
/// use flac::metadata::PictureType;
///
/// let picture = metadata::get_picture("path/to/file.flac",
///                                     Some(PictureType::FileIcon),
///                                     Some("image/gif"),
///                                     None, None, None,
///                                     None, None).unwrap();
/// ```
pub fn get_picture(filename: &str,
                   picture_type: Option<PictureType>,
                   mime_type: Option<&str>,
                   description: Option<&str>,
                   max_width: Option<u32>,
                   max_height: Option<u32>,
                   max_depth: Option<u32>,
                   max_colors: Option<u32>)
                   -> Result<Picture> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find any Picture";
    let mut result = Err(Error::new(ErrorKind::NotFound, error_str));

    let mut max_area_seen  = 0;
    let mut max_depth_seen = 0;

    let max_value      = u32::max_value();
    let max_width_num  = max_width.unwrap_or(max_value);
    let max_height_num = max_height.unwrap_or(max_value);
    let max_depth_num  = max_depth.unwrap_or(max_value);
    let max_colors_num = max_colors.unwrap_or(max_value);

    for block in blocks {
      if let Data::Picture(picture) = block.data {
        let area = (picture.width as u64) * (picture.height as u64);

        if optional_eq(picture_type, picture.picture_type) &&
           optional_eq(mime_type, &picture.mime_type) &&
           optional_eq(description, &picture.description) &&
           picture.width <= max_width_num &&
           picture.height <= max_height_num &&
           picture.depth <= max_depth_num &&
           picture.colors <= max_colors_num &&
           (area > max_area_seen || (area == max_area_seen &&
                                     picture.depth > max_depth_seen)) {
          max_area_seen  = area;
          max_depth_seen = picture.depth;
          result         = Ok(picture);
        }
      }
    }

    result
  })
}

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

  #[test]
  #[should_panic]
  fn test_panic_optional_eq() {
    assert!(optional_eq(Some(1), 0));
  }

  #[test]
  fn test_optional_eq() {
    assert!(optional_eq(None, 0), "Should always return true when None");
    assert!(optional_eq(Some(0), 0), "Should return true (Some(0) == 0)");
  }

  #[test]
  fn test_get_metadata() {
    let not_found    = get_metadata("non-existent/file.txt");
    let invalid_data = get_metadata("README.md");
    let result       = get_metadata("tests/assets/input-SVAUP.flac");

    assert_eq!(not_found.unwrap_err().kind(), ErrorKind::NotFound);
    assert_eq!(invalid_data.unwrap_err().kind(), ErrorKind::InvalidData);
    assert!(result.is_ok());
  }
}
<commit_msg>Step `ErrorKind` to `io::ErrorKind`<commit_after>use nom::{ConsumerState, FileProducer, Producer};
use std::io;
use std::io::{Error, Result};
use std::u32;
use std::fs::File;

use utility::{ErrorKind, ReadStream};

use metadata::{
  Metadata, Data,
  StreamInfo, CueSheet, VorbisComment, Picture,
  PictureType,
};
use metadata::types::Consumer;

// Will return true when the unwrapped value of `option` and `other` match
// or `option` is `Option::None`, otherwise false.
#[inline]
pub fn optional_eq<T: Eq>(option: Option<T>, other: T) -> bool {
  option.map_or(true, |value| value == other)
}

// With the given filename, return all metadata blocks available.
//
// This function expects a flac file, but will return a proper `Result::Err`
// when things go wrong.
//
// # Failures
//
// * `ErrorKind::NotFound` is returned when the given filename isn't found.
// * `ErrorKind::InvalidData` is returned when the data within the file
//   isn't valid FLAC data.
pub fn get_metadata(filename: &str) -> Result<Vec<Metadata>> {
  File::open(filename).and_then(|file| {
    let mut stream   = ReadStream::new(file);
    let mut consumer = Consumer::new();
    let mut is_error = false;

    loop {
      match consumer.handle(&mut stream) {
        Ok(_)                         => break,
        Err(ErrorKind::Consumed(_))   => continue,
        Err(ErrorKind::Incomplete(_)) => continue,
        Err(_)                        => {
          is_error = true;

          break;
        }
      }
    }

    if is_error {
      let error_str = "parser: couldn't find any metadata";

      Err(Error::new(io::ErrorKind::InvalidData, error_str))
    } else {
      Ok(consumer.data)
    }
  })
}

/// Reads and returns the `StreamInfo` metadata block of the given FLAC
/// file.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found
///   or there is no `StreamInfo` within the file.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
///
/// match metadata::get_stream_info("path/to/file.flac") {
///   Ok(stream_info) => {
///     // Use the stream_info variable...
///   }
///   Err(error)      => println!("{}", error),
/// }
/// ```
///
/// Or just ignore the errors:
///
/// ```no_run
/// use flac::metadata;
///
/// let stream_info = metadata::get_stream_info("path/to/file.flac").unwrap();
/// ```
pub fn get_stream_info(filename: &str) -> Result<StreamInfo> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find StreamInfo";
    let mut result = Err(Error::new(io::ErrorKind::NotFound, error_str));

    for block in blocks {
      if let Data::StreamInfo(stream_info) = block.data {
        result = Ok(stream_info);
        break;
      }
    }

    result
  })
}

/// Reads and returns the `VorbisComment` metadata block of the given FLAC
/// file.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found
///   or there is no `VorbisComment` within the file.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
///
/// match metadata::get_vorbis_comment("path/to/file.flac") {
///   Ok(vorbis_comment) => {
///     // Use the vorbis_comment variable...
///   }
///   Err(error)         => println!("{}", error),
/// }
/// ```
///
/// Or just ignore the errors:
///
/// ```no_run
/// use flac::metadata;
///
/// let vorbis_comment =
///   metadata::get_vorbis_comment("path/to/file.flac").unwrap();
/// ```
pub fn get_vorbis_comment(filename: &str) -> Result<VorbisComment> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find VorbisComment";
    let mut result = Err(Error::new(io::ErrorKind::NotFound, error_str));

    for block in blocks {
      if let Data::VorbisComment(vorbis_comment) = block.data {
        result = Ok(vorbis_comment);
        break;
      }
    }

    result
  })
}

/// Reads and returns the `CueSheet` metadata block of the given FLAC file.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found
///   or there is no `CueSheet` within the file.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
///
/// match metadata::get_cue_sheet("path/to/file.flac") {
///   Ok(cue_sheet) => {
///     // Use the cue_sheet variable...
///   }
///   Err(error)    => println!("{}", error),
/// }
/// ```
///
/// Or just ignore the errors
///
/// ```no_run
/// use flac::metadata;
///
/// let cue_sheet = metadata::get_cue_sheet("path/to/file.flac").unwrap();
/// ```
pub fn get_cue_sheet(filename: &str) -> Result<CueSheet> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find CueSheet";
    let mut result = Err(Error::new(io::ErrorKind::NotFound, error_str));

    for block in blocks {
      if let Data::CueSheet(cue_sheet) = block.data {
        result = Ok(cue_sheet);
        break;
      }
    }

    result
  })
}

/// Reads and returns a `Picture` metadata block of the given FLAC file.
///
/// There can be more than one `Picture` block in a file and this function
/// takes optional, that being `Option<T>`, parameters that act as
/// constraints to search within. The `Picture` with the largest area
/// matching all constraints will be returned.
///
/// Putting `None` into any of the optional constraints conveys that you
/// want any of that parameter. Otherwise it will try to look for the image
/// that matches within the given constraints.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found,
///   there is no `Picture` within the file, or no `Picture` that fits the
///   given constraints.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
/// use flac::metadata::PictureType;
///
/// let result = metadata::get_picture("path/to/file.flac",
///                                    Some(PictureType::FileIcon),
///                                    Some("image/gif"),
///                                    None, None, None,
///                                    None, None);
///
/// match result {
///   Ok(picture) => {
///     // Use the picture variable...
///   }
///   Err(error)  => println!("{}", error),
/// }
/// ```
///
/// Or just ignore the errors:
///
/// ```no_run
/// use flac::metadata;
/// use flac::metadata::PictureType;
///
/// let picture = metadata::get_picture("path/to/file.flac",
///                                     Some(PictureType::FileIcon),
///                                     Some("image/gif"),
///                                     None, None, None,
///                                     None, None).unwrap();
/// ```
pub fn get_picture(filename: &str,
                   picture_type: Option<PictureType>,
                   mime_type: Option<&str>,
                   description: Option<&str>,
                   max_width: Option<u32>,
                   max_height: Option<u32>,
                   max_depth: Option<u32>,
                   max_colors: Option<u32>)
                   -> Result<Picture> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find any Picture";
    let mut result = Err(Error::new(io::ErrorKind::NotFound, error_str));

    let mut max_area_seen  = 0;
    let mut max_depth_seen = 0;

    let max_value      = u32::max_value();
    let max_width_num  = max_width.unwrap_or(max_value);
    let max_height_num = max_height.unwrap_or(max_value);
    let max_depth_num  = max_depth.unwrap_or(max_value);
    let max_colors_num = max_colors.unwrap_or(max_value);

    for block in blocks {
      if let Data::Picture(picture) = block.data {
        let area = (picture.width as u64) * (picture.height as u64);

        if optional_eq(picture_type, picture.picture_type) &&
           optional_eq(mime_type, &picture.mime_type) &&
           optional_eq(description, &picture.description) &&
           picture.width <= max_width_num &&
           picture.height <= max_height_num &&
           picture.depth <= max_depth_num &&
           picture.colors <= max_colors_num &&
           (area > max_area_seen || (area == max_area_seen &&
                                     picture.depth > max_depth_seen)) {
          max_area_seen  = area;
          max_depth_seen = picture.depth;
          result         = Ok(picture);
        }
      }
    }

    result
  })
}

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

  #[test]
  #[should_panic]
  fn test_panic_optional_eq() {
    assert!(optional_eq(Some(1), 0));
  }

  #[test]
  fn test_optional_eq() {
    assert!(optional_eq(None, 0), "Should always return true when None");
    assert!(optional_eq(Some(0), 0), "Should return true (Some(0) == 0)");
  }

  #[test]
  fn test_get_metadata() {
    let not_found    = get_metadata("non-existent/file.txt");
    let invalid_data = get_metadata("README.md");
    let result       = get_metadata("tests/assets/input-SVAUP.flac");

    assert_eq!(not_found.unwrap_err().kind(), ErrorKind::NotFound);
    assert_eq!(invalid_data.unwrap_err().kind(), ErrorKind::InvalidData);
    assert!(result.is_ok());
  }
}
<|endoftext|>


<commit_before>use std::io::Command;
use std::io::process::StdioContainer;
#[cfg(target_os = "linux")]
use std::io::fs;

#[cfg(target_os = "linux")]
fn main() {
    Command::new("make")
            .arg("-C").arg("modules/oculus_sdk_linux/")
            .stdout(StdioContainer::InheritFd(1))
            .stderr(StdioContainer::InheritFd(2))
            .status()
            .ok().expect("Failed to build");
    fs::copy(&Path::new("modules/oculus_sdk_linux/LibOVR/Lib/Linux/Release/x86_64/libovr.a"),
             &Path::new(env!("OUT_DIR")).join(Path::new("libovr.a")))
            .ok().expect("Failed to move file");

    println!("cargo:rustc-flags=-L {} -l ovr:static", env!("OUT_DIR"));
}

#[cfg(target_os = "macos")]
fn main() {
    Command::new("xcodebuild")
            .arg("-project")
            .arg("modules/oculus_sdk_mac/LibOVR/Projects/Mac/Xcode/LibOVR.xcodeproj")
            .arg("build")
            .stdout(StdioContainer::InheritFd(1))
            .stderr(StdioContainer::InheritFd(2))
            .status()
            .ok().expect("Failed to build");
    Command::new("lipo")
            .arg("modules/oculus_sdk_mac/LibOVR/Lib/MacOS/Release/libovr.a")
            .arg("-thin")
            .arg("x86_64")
            .arg("-output")
            .arg(Path::new(env!("OUT_DIR")).join(Path::new("libovr.a")).as_str().unwrap())
            .stdout(StdioContainer::InheritFd(1))
            .stderr(StdioContainer::InheritFd(2))
            .status()
            .ok().expect("Failed to lipo library");
    println!("cargo:rustc-flags=-L {} -l ovr:static", env!("OUT_DIR"));
}<commit_msg>fix build script; io -> old_io<commit_after>use std::old_io::Command;
use std::old_io::process::StdioContainer;
#[cfg(target_os = "linux")]
use std::old_io::fs;

#[cfg(target_os = "linux")]
fn main() {
    Command::new("make")
            .arg("-C").arg("modules/oculus_sdk_linux/")
            .stdout(StdioContainer::InheritFd(1))
            .stderr(StdioContainer::InheritFd(2))
            .status()
            .ok().expect("Failed to build");
    fs::copy(&Path::new("modules/oculus_sdk_linux/LibOVR/Lib/Linux/Release/x86_64/libovr.a"),
             &Path::new(env!("OUT_DIR")).join(Path::new("libovr.a")))
            .ok().expect("Failed to move file");

    println!("cargo:rustc-flags=-L {} -l ovr:static", env!("OUT_DIR"));
}

#[cfg(target_os = "macos")]
fn main() {
    Command::new("xcodebuild")
            .arg("-project")
            .arg("modules/oculus_sdk_mac/LibOVR/Projects/Mac/Xcode/LibOVR.xcodeproj")
            .arg("build")
            .stdout(StdioContainer::InheritFd(1))
            .stderr(StdioContainer::InheritFd(2))
            .status()
            .ok().expect("Failed to build");
    Command::new("lipo")
            .arg("modules/oculus_sdk_mac/LibOVR/Lib/MacOS/Release/libovr.a")
            .arg("-thin")
            .arg("x86_64")
            .arg("-output")
            .arg(Path::new(env!("OUT_DIR")).join(Path::new("libovr.a")).as_str().unwrap())
            .stdout(StdioContainer::InheritFd(1))
            .stderr(StdioContainer::InheritFd(2))
            .status()
            .ok().expect("Failed to lipo library");
    println!("cargo:rustc-flags=-L {} -l ovr:static", env!("OUT_DIR"));
}<|endoftext|>


<commit_before>//! Cubemapping module

use std::num::cast;
use nalgebra::{BaseFloat, Vec3, Vec2, zero};
#[cfg(any(test, feature = "arbitrary"))]
use quickcheck::{Arbitrary, Gen};
use partition::{Partition, Subdivide};
use partition::UnitQuad;

/// An axis direction
///
/// This effectively distinguishes whether we are moving in positive or negative
/// direction along some axis, i.e. +X vs -X, +Y vs. -Y etc.
#[derive(Copy, Clone, Show, PartialEq, Hash, Eq)]
pub enum Direction {
    /// Positive direction
    Positive,

    /// Negative direction
    Negative,
}

#[cfg(any(test, feature = "arbitrary"))]
impl Arbitrary for Direction {
    fn arbitrary<G: Gen>(g: &mut G) -> Direction {
        match g.gen_range(0, 2) {
            0 => Direction::Positive,
            1 => Direction::Negative,
            _ => unreachable!(),
        }
    }
}

/// A coordinate axis
#[derive(Copy, Clone, Show, PartialEq, Hash, Eq)]
pub enum Axis {
    /// X-axis
    X,

    /// Y-axis
    Y,

    /// Z-axis
    Z,
}

#[cfg(any(test, feature = "arbitrary"))]
impl Arbitrary for Axis {
    fn arbitrary<G: Gen>(g: &mut G) -> Axis {
        match g.gen_range(0, 3) {
            0 => Axis::X,
            1 => Axis::Y,
            2 => Axis::Z,
            _ => unreachable!(),
        }
    }
}

/// A quad-shaped partition of a side of a cubemap
#[derive(Copy, Clone, Show, PartialEq, Hash, Eq)]
pub struct Quad {
    /// Normal axis of the quad normal
    pub axis: Axis,

    /// Direction of the quad normal along the axis
    pub direction: Direction,

    /// Embedded flat unit quad
    pub flat_quad: UnitQuad,
}

impl Subdivide for Quad {
    fn subdivide(&self) -> Vec<Quad> {
        self.flat_quad.subdivide()
            .into_iter()
            .map(|q| Quad {
                axis: self.axis,
                direction: self.direction,
                flat_quad: q,
            })
            .collect()
    }
}

impl<T: BaseFloat + PartialOrd> Partition<Vec3<T>> for Quad {
    fn contains(&self, elem: &Vec3<T>) -> bool {
        let _1: T = cast(1.0).unwrap();
        let _2: T = cast(2.0).unwrap();
        let (i, j, k) = match self.axis {
            Axis::X => (0, 1, 2),
            Axis::Y => (1, 2, 0),
            Axis::Z => (2, 0, 1),
        };
        match (elem[i] > zero(), self.direction) {
            (true, Direction::Positive) | (false, Direction::Negative) =>
                self.flat_quad.contains(&Vec2::new(
                    (elem[j] / elem[i] + _1) / _2,
                    (elem[k] / elem[i] + _1) / _2,
                )),
            _ => false,
        }
    }
}

#[cfg(any(test, feature = "arbitrary"))]
impl Arbitrary for Quad {
    fn arbitrary<G: Gen>(g: &mut G) -> Quad {
        Quad {
            axis: Arbitrary::arbitrary(g),
            direction: Arbitrary::arbitrary(g),
            flat_quad: Arbitrary::arbitrary(g),
        }
    }
}

/// A cubemap partition of a 3-vector space
///
/// This has no radial partitioning, as it is intended mainly for the surface of
/// a 2-sphere (which is a subset of the full ℝ³). It is either the full
/// spherical dome or some subdivision stage on one of the six quad-shape sides
/// obtained by projecting the sphere onto a cube.
#[derive(Copy, Clone, Show, PartialEq, Hash, Eq)]
pub enum CubeMap {
    /// The full sphere
    Sphere,

    /// A quad-based subdivision
    Quad(Quad),
}

impl Subdivide for CubeMap {
    fn subdivide(&self) -> Vec<CubeMap> {
        match *self {
            CubeMap::Sphere =>
                vec![
                    (Direction::Positive, Axis::X),
                    (Direction::Positive, Axis::Y),
                    (Direction::Positive, Axis::Z),
                    (Direction::Negative, Axis::X),
                    (Direction::Negative, Axis::Y),
                    (Direction::Negative, Axis::Z),
                ]
                .into_iter()
                .map(|(dir, ax)| CubeMap::Quad(Quad {
                    axis: ax,
                    direction: dir,
                    flat_quad: UnitQuad::new(0, [0, 0]),
                }))
                .collect(),
            CubeMap::Quad(ref quad) =>
                quad.subdivide().into_iter().map(|q| CubeMap::Quad(q)).collect(),
        }
    }
}

impl<T: BaseFloat + PartialOrd> Partition<Vec3<T>> for CubeMap {
    fn contains(&self, elem: &Vec3<T>) -> bool {
        match *self {
            CubeMap::Sphere => true,
            CubeMap::Quad(q) => q.contains(elem),
        }
    }
}

#[cfg(any(test, feature = "arbitrary"))]
impl Arbitrary for CubeMap {
    fn arbitrary<G: Gen>(g: &mut G) -> CubeMap {
        match { let s = g.size(); g.gen_range(0, s) } {
            0 => CubeMap::Sphere,
            _ => CubeMap::Quad(Arbitrary::arbitrary(g)),
        }
    }
}

#[cfg(test)]
mod test {
    pub use nalgebra::Vec3;
    pub use super::*;
    use quickcheck::quickcheck;
    use partition::Partition;

    partition_quickcheck!(quad_vec3_f32, Quad, Vec3<f32>);
    partition_quickcheck!(quad_vec3_f64, Quad, Vec3<f64>);
    partition_quickcheck!(cubemap_vec3_f32, CubeMap, Vec3<f32>);
    partition_quickcheck!(cubemap_vec3_f64, CubeMap, Vec3<f64>);

    #[test]
    fn cubemap_covers_vec3() {
        fn check(v: Vec3<f64>) -> bool {
            CubeMap::Sphere.contains(&v)
        }
        quickcheck(check as fn(Vec3<f64>) -> bool);
    }
}
<commit_msg>Add some functions for cubemap geometry<commit_after>//! Cubemapping module

use nalgebra::{BaseFloat, Vec3, Vec2, Norm, zero, one};
#[cfg(any(test, feature = "arbitrary"))]
use quickcheck::{Arbitrary, Gen};
use partition::{Partition, Subdivide};
use partition::UnitQuad;

/// An axis direction
///
/// This effectively distinguishes whether we are moving in positive or negative
/// direction along some axis, i.e. +X vs -X, +Y vs. -Y etc.
#[derive(Copy, Clone, Show, PartialEq, Hash, Eq)]
pub enum Direction {
    /// Positive direction
    Positive,

    /// Negative direction
    Negative,
}

#[cfg(any(test, feature = "arbitrary"))]
impl Arbitrary for Direction {
    fn arbitrary<G: Gen>(g: &mut G) -> Direction {
        match g.gen_range(0, 2) {
            0 => Direction::Positive,
            1 => Direction::Negative,
            _ => unreachable!(),
        }
    }
}

/// A coordinate axis
#[derive(Copy, Clone, Show, PartialEq, Hash, Eq)]
pub enum Axis {
    /// X-axis
    X,

    /// Y-axis
    Y,

    /// Z-axis
    Z,
}

#[cfg(any(test, feature = "arbitrary"))]
impl Arbitrary for Axis {
    fn arbitrary<G: Gen>(g: &mut G) -> Axis {
        match g.gen_range(0, 3) {
            0 => Axis::X,
            1 => Axis::Y,
            2 => Axis::Z,
            _ => unreachable!(),
        }
    }
}

/// Get the triple of axis vectors
///
/// The first vector is the normal vector n, the remaining are tangents t_1 and
/// t_2. They form a basis that is right-handed, i.e. n × t_1 = t_2.
pub fn axis_vector_triple<T: BaseFloat>(axis: Axis, direction: Direction) -> [Vec3<T>; 3] {
    let _p: T = one();
    let _n: T = -_p;
    let _0: T = zero();
    let sgn = match direction {
        Direction::Positive => _p,
        Direction::Negative => -_n,
    };
    match axis {
        Axis::X => [
            Vec3::new(sgn, _0, _0),
            Vec3::new(_0, sgn, _0),
            Vec3::new(_0, _0, _p),
        ],
        Axis::Y => [
            Vec3::new(_0, sgn, _0),
            Vec3::new(_0, _0, sgn),
            Vec3::new(_p, _0, _0),
        ],
        Axis::Z => [
            Vec3::new(_0, _0, sgn),
            Vec3::new(sgn, _0, _0),
            Vec3::new(_0, _p, _0),
        ],
    }
}

/// A quad-shaped partition of the side of a cubemap
#[derive(Copy, Clone, Show, PartialEq, Hash, Eq)]
pub struct Quad {
    /// Normal axis of the quad normal
    pub axis: Axis,

    /// Direction of the quad normal along the axis
    pub direction: Direction,

    /// Embedded flat unit quad
    pub flat_quad: UnitQuad,
}

impl Quad {
    /// The center of this quad on the cube
    pub fn center_on_cube<T: BaseFloat>(&self) -> Vec3<T> {
        let _1: T = one();
        let _2: T = _1 + _1;
        let c: Vec2<T> = self.flat_quad.center();
        let [n, t1, t2]: [Vec3<T>; 3] =
            axis_vector_triple(self.axis, self.direction);
        n + t1 * (c.x * _2 - _1) + t2 * (c.y * _2 - _1)
    }

    /// The center of this quad on the unit sphere
    pub fn center_on_sphere<T: BaseFloat>(&self) -> Vec3<T> {
        let mut c = self.center_on_cube();
        c.normalize();
        c
    }
}

impl Subdivide for Quad {
    fn subdivide(&self) -> Vec<Quad> {
        self.flat_quad.subdivide()
            .into_iter()
            .map(|q| Quad {
                axis: self.axis,
                direction: self.direction,
                flat_quad: q,
            })
            .collect()
    }
}

impl<T: BaseFloat + PartialOrd> Partition<Vec3<T>> for Quad {
    fn contains(&self, elem: &Vec3<T>) -> bool {
        let _1: T = one();
        let _2: T = _1 + _1;
        let (i, j, k) = match self.axis {
            Axis::X => (0, 1, 2),
            Axis::Y => (1, 2, 0),
            Axis::Z => (2, 0, 1),
        };
        match (elem[i] > zero(), self.direction) {
            (true, Direction::Positive) | (false, Direction::Negative) =>
                self.flat_quad.contains(&Vec2::new(
                    (elem[j] / elem[i] + _1) / _2,
                    (elem[k] / elem[i] + _1) / _2,
                )),
            _ => false,
        }
    }
}

#[cfg(any(test, feature = "arbitrary"))]
impl Arbitrary for Quad {
    fn arbitrary<G: Gen>(g: &mut G) -> Quad {
        Quad {
            axis: Arbitrary::arbitrary(g),
            direction: Arbitrary::arbitrary(g),
            flat_quad: Arbitrary::arbitrary(g),
        }
    }
}

/// A cubemap partition of a 3-vector space
///
/// This has no radial partitioning, as it is intended mainly for the surface of
/// a 2-sphere (which is a subset of the full ℝ³). It is either the full
/// spherical dome or some subdivision stage on one of the six quad-shape sides
/// obtained by projecting the sphere onto a cube.
#[derive(Copy, Clone, Show, PartialEq, Hash, Eq)]
pub enum CubeMap {
    /// The full sphere
    Sphere,

    /// A quad-based subdivision
    Quad(Quad),
}

impl Subdivide for CubeMap {
    fn subdivide(&self) -> Vec<CubeMap> {
        match *self {
            CubeMap::Sphere =>
                vec![
                    (Direction::Positive, Axis::X),
                    (Direction::Positive, Axis::Y),
                    (Direction::Positive, Axis::Z),
                    (Direction::Negative, Axis::X),
                    (Direction::Negative, Axis::Y),
                    (Direction::Negative, Axis::Z),
                ]
                .into_iter()
                .map(|(dir, ax)| CubeMap::Quad(Quad {
                    axis: ax,
                    direction: dir,
                    flat_quad: UnitQuad::new(0, [0, 0]),
                }))
                .collect(),
            CubeMap::Quad(ref quad) =>
                quad.subdivide().into_iter().map(|q| CubeMap::Quad(q)).collect(),
        }
    }
}

impl<T: BaseFloat + PartialOrd> Partition<Vec3<T>> for CubeMap {
    fn contains(&self, elem: &Vec3<T>) -> bool {
        match *self {
            CubeMap::Sphere => true,
            CubeMap::Quad(q) => q.contains(elem),
        }
    }
}

#[cfg(any(test, feature = "arbitrary"))]
impl Arbitrary for CubeMap {
    fn arbitrary<G: Gen>(g: &mut G) -> CubeMap {
        match { let s = g.size(); g.gen_range(0, s) } {
            0 => CubeMap::Sphere,
            _ => CubeMap::Quad(Arbitrary::arbitrary(g)),
        }
    }
}

#[cfg(test)]
mod test {
    pub use nalgebra::{Vec3, Cross};
    pub use super::*;
    use quickcheck::quickcheck;
    use partition::Partition;

    partition_quickcheck!(quad_vec3_f32, Quad, Vec3<f32>);
    partition_quickcheck!(quad_vec3_f64, Quad, Vec3<f64>);
    partition_quickcheck!(cubemap_vec3_f32, CubeMap, Vec3<f32>);
    partition_quickcheck!(cubemap_vec3_f64, CubeMap, Vec3<f64>);

    #[test]
    fn cubemap_covers_vec3() {
        fn check(v: Vec3<f64>) -> bool {
            CubeMap::Sphere.contains(&v)
        }
        quickcheck(check as fn(Vec3<f64>) -> bool);
    }

    #[test]
    fn axis_vector_triples_are_right_handed() {
        fn check(axis: Axis, direction: Direction) -> bool {
            let [n, t1, t2]: [Vec3<f64>; 3] = axis_vector_triple(axis, direction);
            n.cross(&t1) == t2
        }
        quickcheck(check as fn(Axis, Direction) -> bool);
    }
}
<|endoftext|>


<commit_before>//
// zhtta.rs
//
// Running on Rust 0.8
//
// Starting code for PS3
//
// Note: it would be very unwise to run this server on a machine that is
// on the Internet and contains any sensitive files!
//
// University of Virginia - cs4414 Fall 2013
// Weilin Xu and David Evans
// Version 0.3

extern mod extra;

use std::rt::io::*;
use std::rt::io::net::ip::SocketAddr;
use std::io::println;
use std::cell::Cell;
use std::{os, str, io, run, uint};
use extra::arc;
use std::comm::*;
use extra::priority_queue::PriorityQueue;
use std::rt::io::net::ip::*;
use std::hashmap::HashMap;

mod gashing;

static PORT:    int = 4414;
static IP: &'static str = "127.0.0.1";

struct sched_msg {
    stream: Option<std::rt::io::net::tcp::TcpStream>,
    filepath: ~std::path::PosixPath,
    ip: IpAddr,
    filesize: Option<uint>, //filesize added to store file size
}

fn main() {
    let mut cache: HashMap<~str, ~[u8]> = HashMap::new();
    let shared_cache = arc::RWArc::new(cache);
    let add_cache = shared_cache.clone();

    let mut req_vec : PriorityQueue<sched_msg> = PriorityQueue::new();
    let shared_req_vec = arc::RWArc::new(req_vec);
    let add_vec = shared_req_vec.clone();
    let take_vec = shared_req_vec.clone();

    let (port, chan) = stream();
    let chan = SharedChan::new(chan);

    // dequeue file requests, and send responses.
    // FIFO
    do spawn {
        let (sm_port, sm_chan) = stream();

        // a task for sending responses.
        do spawn {
            loop {
                let mut tf: sched_msg = sm_port.recv(); // wait for the dequeued request to handle

                let ref file = tf.filepath.components[tf.filepath.components.len()-1];

                let mut cache_data: Option<~[u8]> = None;

                do add_cache.write | map | {
                    let foundfile: Option<&~[u8]> = (*map).find(file);
                    match foundfile {
                        Some(stuff) => {
                            cache_data = Some( stuff.to_owned() );
                        },
                        None => ()
                    }

                }

                let mut file_data: ~[u8] = ~[];
                match cache_data {
                    Some(ref data) => {
                        println("\n[Cache] hit! found "+file.to_owned()+"\n");
                        file_data = (*data).to_owned();
                    },
                    None => {
                        match io::read_whole_file(tf.filepath) {
                            Ok(data) => {
                                println("\n[Cache] miss, could not file "+file.to_owned()+"\n");
                                file_data = data;

                                do add_cache.write | map | {
                                    (*map).swap(file.to_owned(), file_data.clone());
                                }

                            }
                            Err(err) => println(err)
                        }
                    }
                }

                println(fmt!("begin serving file [%?]", tf.filepath));
                // A web server should always reply a HTTP header for any legal HTTP request.

                if file.ends_with(".html") {
                    tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n".as_bytes());
                    let strval = str::from_utf8(file_data);
                    let gashresult = gashing::gashify(strval);
                    file_data = gashresult.as_bytes().to_owned();
                } else if file.ends_with(".txt") || file.ends_with(".md") {
                    tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: text/plain; charset=UTF-8\r\n\r\n".as_bytes());
                } else {
                    tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream; charset=UTF-8\r\n\r\n".as_bytes());
                }

                tf.stream.write(file_data);

            }
        }

        loop {
            port.recv(); // wait for arrving notification
            do take_vec.write |vec| {
                if ((*vec).len() > 0) {
                    // LIFO didn't make sense in service scheduling, so we modify it as FIFO by using shift_opt() rather than pop().
                    let tf : sched_msg = (*vec).pop();
                    println(fmt!("shift from queue, size: %ud", (*vec).len()));
                    sm_chan.send(tf); // send the request to send-response-task to serve.
                }
            }
        }
    }

    let ip = match FromStr::from_str(IP) { Some(ip) => ip,
                                           None => { println(fmt!("Error: Invalid IP address <%s>", IP));
                                                     return;},
                                         };

    let socket = net::tcp::TcpListener::bind(SocketAddr {ip: ip, port: PORT as u16});

    println(fmt!("Listening on %s:%d ...", ip.to_str(), PORT));
    let mut acceptor = socket.listen().unwrap();

    let mycount: uint = 0;
    let shared_mycount = arc::RWArc::new(mycount);

    for stream in acceptor.incoming() {
        let stream = Cell::new(stream);

        // Start a new task to handle the each connection
        let child_chan = chan.clone();
        let child_add_vec = add_vec.clone();
        let update_count = shared_mycount.clone();
        do spawn {
            let mut visitor_count = 0;
            do update_count.write |c| {
                *c += 1;
                visitor_count = *c;
             }

            let mut stream = stream.take();

            let mut visitor_ip: IpAddr = std::rt::io::net::ip::Ipv4Addr(-1, -1, -1, -1);

            stream.and_then_mut_ref(|x| {
                    match x.peer_name() {
                        Some(sock_addr) => {visitor_ip = sock_addr.ip;},
                        None => ()
                    }
                    Some(x)
                });

            println(fmt!("Visitor IP is %s", visitor_ip.to_str()));

            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);

            let req_group : ~[&str]= request_str.splitn_iter(' ', 3).collect();
            if req_group.len() > 2 {
                let path = req_group[1];
                println(fmt!("Request for path: \n%?", path));

                let file_path = ~os::getcwd().push(path.replace("/../", ""));
                if !os::path_exists(file_path) || os::path_is_dir(file_path) {
                    println(fmt!("Request received:\n%s", request_str));
                    let response: ~str = fmt!(
                        "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                         <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

Visitor count: %u

                         \r\n", visitor_count);

                    stream.write(response.as_bytes());
                }
                else {
                    // Requests scheduling

		    // Started Problem 3 code here
		    // Creates process that runs and parses file size command for problem 3
		    let mut args : ~[~str] = ~[~"-c", ~"<", file_path.to_str()];
		    let mut pr = run::Process::new("wc", args, run::ProcessOptions::new());
		    let poutput = pr.finish_with_output();
		    let mut poutputc = poutput.output;
		    let mut realstr = str::from_utf8(poutputc);
		    let mut strarray: ~[&str] = realstr.split_iter(' ').collect();
		    let mut formatfsize : Option<uint> = from_str(strarray[0]);

                    let msg: sched_msg = sched_msg{stream: stream, filepath: file_path.clone(), ip: visitor_ip, filesize : formatfsize };

		    println(fmt!("%?", realstr));//print file size served
		    println(fmt!("%?", strarray[0]));//print file size served
		    println(fmt!("%?", formatfsize));//print file size served

		    //Problem 3 Code finishes here

                    let (sm_port, sm_chan) = std::comm::stream();
                    sm_chan.send(msg);

                    do child_add_vec.write |vec| {
                        let msg = sm_port.recv();
                        (*vec).push(msg); // enqueue new request.
                        println("add to queue");
                    }
                    child_chan.send(""); //notify the new arriving request.
                    println(fmt!("get file request: %?", file_path));
                }
            }
            println!("connection terminates")
        }
    }
}

impl Ord for sched_msg {

	fn lt(&self, other: &sched_msg) -> bool {

		let selfIP: IpAddr = self.ip;
		let otherIP: IpAddr = other.ip;

		let selfSize : Option<uint> = self.filesize;
		let otherSize : Option<uint> = other.filesize;

		match selfIP {
			Ipv4Addr(a , b, c, d) => {
				if ((a == 128 && b == 143) || (a == 137 && b == 54)){
					return false;
				}else{
					if (selfSize < otherSize){
						return false;
					}else{
						return true;
					}
				}
			},
			Ipv6Addr(a, b, c, d, e, f, g, h) => {
				if ((a == 128 && b == 143) || (a == 137 && b == 54)){
					return false;
				}else{
					if (selfSize < otherSize){
						return false;
					}else{
						return true;
					}
				}

			}
		}

	}
}

<commit_msg>fixed typo<commit_after>//
// zhtta.rs
//
// Running on Rust 0.8
//
// Starting code for PS3
//
// Note: it would be very unwise to run this server on a machine that is
// on the Internet and contains any sensitive files!
//
// University of Virginia - cs4414 Fall 2013
// Weilin Xu and David Evans
// Version 0.3

extern mod extra;

use std::rt::io::*;
use std::rt::io::net::ip::SocketAddr;
use std::io::println;
use std::cell::Cell;
use std::{os, str, io, run, uint};
use extra::arc;
use std::comm::*;
use extra::priority_queue::PriorityQueue;
use std::rt::io::net::ip::*;
use std::hashmap::HashMap;

mod gashing;

static PORT:    int = 4414;
static IP: &'static str = "127.0.0.1";

struct sched_msg {
    stream: Option<std::rt::io::net::tcp::TcpStream>,
    filepath: ~std::path::PosixPath,
    ip: IpAddr,
    filesize: Option<uint>, //filesize added to store file size
}

fn main() {
    let mut cache: HashMap<~str, ~[u8]> = HashMap::new();
    let shared_cache = arc::RWArc::new(cache);
    let add_cache = shared_cache.clone();

    let mut req_vec : PriorityQueue<sched_msg> = PriorityQueue::new();
    let shared_req_vec = arc::RWArc::new(req_vec);
    let add_vec = shared_req_vec.clone();
    let take_vec = shared_req_vec.clone();

    let (port, chan) = stream();
    let chan = SharedChan::new(chan);

    // dequeue file requests, and send responses.
    // FIFO
    do spawn {
        let (sm_port, sm_chan) = stream();

        // a task for sending responses.
        do spawn {
            loop {
                let mut tf: sched_msg = sm_port.recv(); // wait for the dequeued request to handle

                let ref file = tf.filepath.components[tf.filepath.components.len()-1];

                let mut cache_data: Option<~[u8]> = None;

                do add_cache.write | map | {
                    let foundfile: Option<&~[u8]> = (*map).find(file);
                    match foundfile {
                        Some(stuff) => {
                            cache_data = Some( stuff.to_owned() );
                        },
                        None => ()
                    }

                }

                let mut file_data: ~[u8] = ~[];
                match cache_data {
                    Some(ref data) => {
                        println("\n[Cache] hit! found "+file.to_owned()+"\n");
                        file_data = (*data).to_owned();
                    },
                    None => {
                        match io::read_whole_file(tf.filepath) {
                            Ok(data) => {
                                println("\n[Cache] miss, could not find "+file.to_owned()+"\n");
                                file_data = data;

                                do add_cache.write | map | {
                                    (*map).swap(file.to_owned(), file_data.clone());
                                }

                            }
                            Err(err) => println(err)
                        }
                    }
                }

                println(fmt!("begin serving file [%?]", tf.filepath));
                // A web server should always reply a HTTP header for any legal HTTP request.

                if file.ends_with(".html") {
                    tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n".as_bytes());
                    let strval = str::from_utf8(file_data);
                    let gashresult = gashing::gashify(strval);
                    file_data = gashresult.as_bytes().to_owned();
                } else if file.ends_with(".txt") || file.ends_with(".md") {
                    tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: text/plain; charset=UTF-8\r\n\r\n".as_bytes());
                } else {
                    tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream; charset=UTF-8\r\n\r\n".as_bytes());
                }

                tf.stream.write(file_data);

            }
        }

        loop {
            port.recv(); // wait for arrving notification
            do take_vec.write |vec| {
                if ((*vec).len() > 0) {
                    // LIFO didn't make sense in service scheduling, so we modify it as FIFO by using shift_opt() rather than pop().
                    let tf : sched_msg = (*vec).pop();
                    println(fmt!("shift from queue, size: %ud", (*vec).len()));
                    sm_chan.send(tf); // send the request to send-response-task to serve.
                }
            }
        }
    }

    let ip = match FromStr::from_str(IP) { Some(ip) => ip,
                                           None => { println(fmt!("Error: Invalid IP address <%s>", IP));
                                                     return;},
                                         };

    let socket = net::tcp::TcpListener::bind(SocketAddr {ip: ip, port: PORT as u16});

    println(fmt!("Listening on %s:%d ...", ip.to_str(), PORT));
    let mut acceptor = socket.listen().unwrap();

    let mycount: uint = 0;
    let shared_mycount = arc::RWArc::new(mycount);

    for stream in acceptor.incoming() {
        let stream = Cell::new(stream);

        // Start a new task to handle the each connection
        let child_chan = chan.clone();
        let child_add_vec = add_vec.clone();
        let update_count = shared_mycount.clone();
        do spawn {
            let mut visitor_count = 0;
            do update_count.write |c| {
                *c += 1;
                visitor_count = *c;
             }

            let mut stream = stream.take();

            let mut visitor_ip: IpAddr = std::rt::io::net::ip::Ipv4Addr(-1, -1, -1, -1);

            stream.and_then_mut_ref(|x| {
                    match x.peer_name() {
                        Some(sock_addr) => {visitor_ip = sock_addr.ip;},
                        None => ()
                    }
                    Some(x)
                });

            println(fmt!("Visitor IP is %s", visitor_ip.to_str()));

            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);

            let req_group : ~[&str]= request_str.splitn_iter(' ', 3).collect();
            if req_group.len() > 2 {
                let path = req_group[1];
                println(fmt!("Request for path: \n%?", path));

                let file_path = ~os::getcwd().push(path.replace("/../", ""));
                if !os::path_exists(file_path) || os::path_is_dir(file_path) {
                    println(fmt!("Request received:\n%s", request_str));
                    let response: ~str = fmt!(
                        "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                         <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

Visitor count: %u

                         \r\n", visitor_count);

                    stream.write(response.as_bytes());
                }
                else {
                    // Requests scheduling

		    // Started Problem 3 code here
		    // Creates process that runs and parses file size command for problem 3
		    let mut args : ~[~str] = ~[~"-c", ~"<", file_path.to_str()];
		    let mut pr = run::Process::new("wc", args, run::ProcessOptions::new());
		    let poutput = pr.finish_with_output();
		    let mut poutputc = poutput.output;
		    let mut realstr = str::from_utf8(poutputc);
		    let mut strarray: ~[&str] = realstr.split_iter(' ').collect();
		    let mut formatfsize : Option<uint> = from_str(strarray[0]);

                    let msg: sched_msg = sched_msg{stream: stream, filepath: file_path.clone(), ip: visitor_ip, filesize : formatfsize };

		    println(fmt!("%?", realstr));//print file size served
		    println(fmt!("%?", strarray[0]));//print file size served
		    println(fmt!("%?", formatfsize));//print file size served

		    //Problem 3 Code finishes here

                    let (sm_port, sm_chan) = std::comm::stream();
                    sm_chan.send(msg);

                    do child_add_vec.write |vec| {
                        let msg = sm_port.recv();
                        (*vec).push(msg); // enqueue new request.
                        println("add to queue");
                    }
                    child_chan.send(""); //notify the new arriving request.
                    println(fmt!("get file request: %?", file_path));
                }
            }
            println!("connection terminates")
        }
    }
}

impl Ord for sched_msg {

	fn lt(&self, other: &sched_msg) -> bool {

		let selfIP: IpAddr = self.ip;
		let otherIP: IpAddr = other.ip;

		let selfSize : Option<uint> = self.filesize;
		let otherSize : Option<uint> = other.filesize;

		match selfIP {
			Ipv4Addr(a , b, c, d) => {
				if ((a == 128 && b == 143) || (a == 137 && b == 54)){
					return false;
				}else{
					if (selfSize < otherSize){
						return false;
					}else{
						return true;
					}
				}
			},
			Ipv6Addr(a, b, c, d, e, f, g, h) => {
				if ((a == 128 && b == 143) || (a == 137 && b == 54)){
					return false;
				}else{
					if (selfSize < otherSize){
						return false;
					}else{
						return true;
					}
				}

			}
		}

	}
}

<|endoftext|>