<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/. */

//! The `servo` test application.
//!
//! Creates a `Servo` instance with a simple implementation of
//! the compositor's `WindowMethods` to create a working web browser.
//!
//! This browser's implementation of `WindowMethods` is built on top
//! of [glutin], the cross-platform OpenGL utility and windowing
//! library.
//!
//! For the engine itself look next door in `components/servo/lib.rs`.
//!
//! [glutin]: https://github.com/tomaka/glutin

#![cfg_attr(feature = "unstable", feature(core_intrinsics))]

#[cfg(target_os = "android")]
extern crate android_injected_glue;
extern crate backtrace;
#[macro_use] extern crate bitflags;
extern crate compositing;
extern crate euclid;
#[cfg(target_os = "windows")] extern crate gdi32;
extern crate gleam;
extern crate glutin;
// The window backed by glutin
#[macro_use] extern crate log;
extern crate msg;
#[cfg(any(target_os = "linux", target_os = "macos"))] extern crate osmesa_sys;
extern crate script_traits;
extern crate servo;
extern crate servo_config;
extern crate servo_geometry;
#[cfg(all(feature = "unstable", not(target_os = "android")))]
#[macro_use]
extern crate sig;
extern crate style_traits;
extern crate tinyfiledialogs;
extern crate webrender_api;
extern crate winit;
#[cfg(target_os = "windows")] extern crate winapi;
#[cfg(target_os = "windows")] extern crate user32;

mod glutin_app;

use backtrace::Backtrace;
use servo::Servo;
use servo::compositing::windowing::WindowEvent;
#[cfg(target_os = "android")]
use servo::config;
use servo::config::opts::{self, ArgumentParsingResult, parse_url_or_filename};
use servo::config::servo_version;
use servo::ipc_channel::ipc;
use servo::servo_config::prefs::PREFS;
use servo::servo_url::ServoUrl;
use std::env;
use std::panic;
use std::process;
use std::thread;

mod browser;

pub mod platform {
    #[cfg(target_os = "macos")]
    pub use platform::macos::deinit;

    #[cfg(target_os = "macos")]
    pub mod macos;

    #[cfg(not(target_os = "macos"))]
    pub fn deinit() {}
}

#[cfg(all(feature = "unstable", not(target_os = "android")))]
fn install_crash_handler() {
    use backtrace::Backtrace;
    use sig::ffi::Sig;
    use std::intrinsics::abort;
    use std::thread;

    fn handler(_sig: i32) {
        let name = thread::current()
            .name()
            .map(|n| format!(" for thread \"{}\"", n))
            .unwrap_or("".to_owned());
        println!("Stack trace{}\n{:?}", name, Backtrace::new());
        unsafe {
            // N.B. Using process::abort() here causes the crash handler to be
            //      triggered recursively.
            abort();
        }
    }

    signal!(Sig::SEGV, handler); // handle segfaults
    signal!(Sig::ILL, handler); // handle stack overflow and unsupported CPUs
    signal!(Sig::IOT, handler); // handle double panics
    signal!(Sig::BUS, handler); // handle invalid memory access
}

#[cfg(any(not(feature = "unstable"), target_os = "android"))]
fn install_crash_handler() {}

fn main() {
    install_crash_handler();

    // Parse the command line options and store them globally
    let opts_result = opts::from_cmdline_args(&*args());

    let content_process_token = if let ArgumentParsingResult::ContentProcess(token) = opts_result {
        Some(token)
    } else {
        if opts::get().is_running_problem_test && ::std::env::var("RUST_LOG").is_err() {
            ::std::env::set_var("RUST_LOG", "compositing::constellation");
        }

        None
    };

    // TODO: once log-panics is released, can this be replaced by
    // log_panics::init()?
    panic::set_hook(Box::new(|info| {
        warn!("Panic hook called.");
        let msg = match info.payload().downcast_ref::<&'static str>() {
            Some(s) => *s,
            None => {
                match info.payload().downcast_ref::<String>() {
                    Some(s) => &**s,
                    None => "Box<Any>",
                }
            },
        };
        let current_thread = thread::current();
        let name = current_thread.name().unwrap_or("<unnamed>");
        if let Some(location) = info.location() {
            println!("{} (thread {}, at {}:{})",
                     msg,
                     name,
                     location.file(),
                     location.line());
        } else {
            println!("{} (thread {})", msg, name);
        }
        if env::var("RUST_BACKTRACE").is_ok() {
            println!("{:?}", Backtrace::new());
        }

        error!("{}", msg);
    }));

    setup_logging();

    if let Some(token) = content_process_token {
        return servo::run_content_process(token);
    }

    if opts::get().is_printing_version {
        println!("{}", servo_version());
        process::exit(0);
    }

    let window = glutin_app::create_window();

    let mut browser = browser::Browser::new(window.clone());

    // If the url is not provided, we fallback to the homepage in PREFS,
    // or a blank page in case the homepage is not set either.
    let cwd = env::current_dir().unwrap();
    let cmdline_url = opts::get().url.clone();
    let pref_url = PREFS.get("shell.homepage").as_string()
        .and_then(|str| parse_url_or_filename(&cwd, str).ok());
    let blank_url = ServoUrl::parse("about:blank").ok();

    let target_url = cmdline_url.or(pref_url).or(blank_url).unwrap();

    let mut servo = Servo::new(window.clone());

    let (sender, receiver) = ipc::channel().unwrap();
    servo.handle_events(vec![WindowEvent::NewBrowser(target_url, sender)]);
    let browser_id = receiver.recv().unwrap();
    browser.set_browser_id(browser_id);
    servo.handle_events(vec![WindowEvent::SelectBrowser(browser_id)]);

    servo.setup_logging();

    window.run(|| {
        let win_events = window.get_events();
        let servo_events = servo.get_events();

        // FIXME: this could be handled by Servo. We don't need
        // a repaint_synchronously function exposed.
        let need_resize = win_events.iter().any(|e| match *e {
            WindowEvent::Resize => true,
            _ => false,
        });

        browser.handle_servo_events(servo_events);
        browser.handle_window_events(win_events);

        if browser.shutdown_requested() {
            return true;
        }

        servo.handle_events(browser.get_events());
        if need_resize {
            servo.repaint_synchronously();
        }
        false
    });

    servo.deinit();

    platform::deinit()
}

#[cfg(target_os = "android")]
fn setup_logging() {
    // Piping logs from stdout/stderr to logcat happens in android_injected_glue.
    ::std::env::set_var("RUST_LOG", "error");

    unsafe { android_injected_glue::ffi::app_dummy() };
}

#[cfg(not(target_os = "android"))]
fn setup_logging() {}

#[cfg(target_os = "android")]
/// Attempt to read parameters from a file since they are not passed to us in Android environments.
/// The first line should be the "servo" argument and the last should be the URL to load.
/// Blank lines and those beginning with a '#' are ignored.
/// Each line should be a separate parameter as would be parsed by the shell.
/// For example, "servo -p 10 http://en.wikipedia.org/wiki/Rust" would take 4 lines.
fn args() -> Vec<String> {
    use std::error::Error;
    use std::fs::File;
    use std::io::{BufRead, BufReader};

    let mut params_file = config::basedir::default_config_dir();
    params_file.push("android_params");
    match File::open(params_file.to_str().unwrap()) {
        Ok(f) => {
            let mut vec = Vec::new();
            let file = BufReader::new(&f);
            for line in file.lines() {
                let l = line.unwrap().trim().to_owned();
                // ignore blank lines and those that start with a '#'
                match l.is_empty() || l.as_bytes()[0] == b'#' {
                    true => (),
                    false => vec.push(l),
                }
            }
            vec
        },
        Err(e) => {
            debug!("Failed to open params file '{}': {}",
                   params_file.to_str().unwrap(),
                   Error::description(&e));
            vec!["servo".to_owned(), "http://en.wikipedia.org/wiki/Rust".to_owned()]
        },
    }
}

#[cfg(not(target_os = "android"))]
fn args() -> Vec<String> {
    use std::env;
    env::args().collect()
}

#[cfg(target_os = "android")]
#[no_mangle]
#[inline(never)]
#[allow(non_snake_case)]
pub extern "C" fn android_main(app: *mut ()) {
    android_injected_glue::android_main2(app as *mut _, move |_, _| main());
}

// These functions aren't actually called. They are here as a link
// hack because Skia references them.

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn glBindVertexArrayOES(_array: usize)
{
    unimplemented!()
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn glDeleteVertexArraysOES(_n: isize, _arrays: *const ())
{
    unimplemented!()
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn glGenVertexArraysOES(_n: isize, _arrays: *const ())
{
    unimplemented!()
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn glRenderbufferStorageMultisampleIMG(_: isize, _: isize, _: isize, _: isize, _: isize)
{
    unimplemented!()
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn glFramebufferTexture2DMultisampleIMG(_: isize, _: isize, _: isize, _: isize, _: isize, _: isize)
{
    unimplemented!()
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn glDiscardFramebufferEXT(_: isize, _: isize, _: *const ())
{
    unimplemented!()
}
<commit_msg>loop until we exhausted all the servo events<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/. */

//! The `servo` test application.
//!
//! Creates a `Servo` instance with a simple implementation of
//! the compositor's `WindowMethods` to create a working web browser.
//!
//! This browser's implementation of `WindowMethods` is built on top
//! of [glutin], the cross-platform OpenGL utility and windowing
//! library.
//!
//! For the engine itself look next door in `components/servo/lib.rs`.
//!
//! [glutin]: https://github.com/tomaka/glutin

#![cfg_attr(feature = "unstable", feature(core_intrinsics))]

#[cfg(target_os = "android")]
extern crate android_injected_glue;
extern crate backtrace;
#[macro_use] extern crate bitflags;
extern crate compositing;
extern crate euclid;
#[cfg(target_os = "windows")] extern crate gdi32;
extern crate gleam;
extern crate glutin;
// The window backed by glutin
#[macro_use] extern crate log;
extern crate msg;
#[cfg(any(target_os = "linux", target_os = "macos"))] extern crate osmesa_sys;
extern crate script_traits;
extern crate servo;
extern crate servo_config;
extern crate servo_geometry;
#[cfg(all(feature = "unstable", not(target_os = "android")))]
#[macro_use]
extern crate sig;
extern crate style_traits;
extern crate tinyfiledialogs;
extern crate webrender_api;
extern crate winit;
#[cfg(target_os = "windows")] extern crate winapi;
#[cfg(target_os = "windows")] extern crate user32;

mod glutin_app;

use backtrace::Backtrace;
use servo::Servo;
use servo::compositing::windowing::WindowEvent;
#[cfg(target_os = "android")]
use servo::config;
use servo::config::opts::{self, ArgumentParsingResult, parse_url_or_filename};
use servo::config::servo_version;
use servo::ipc_channel::ipc;
use servo::servo_config::prefs::PREFS;
use servo::servo_url::ServoUrl;
use std::env;
use std::panic;
use std::process;
use std::thread;

mod browser;

pub mod platform {
    #[cfg(target_os = "macos")]
    pub use platform::macos::deinit;

    #[cfg(target_os = "macos")]
    pub mod macos;

    #[cfg(not(target_os = "macos"))]
    pub fn deinit() {}
}

#[cfg(all(feature = "unstable", not(target_os = "android")))]
fn install_crash_handler() {
    use backtrace::Backtrace;
    use sig::ffi::Sig;
    use std::intrinsics::abort;
    use std::thread;

    fn handler(_sig: i32) {
        let name = thread::current()
            .name()
            .map(|n| format!(" for thread \"{}\"", n))
            .unwrap_or("".to_owned());
        println!("Stack trace{}\n{:?}", name, Backtrace::new());
        unsafe {
            // N.B. Using process::abort() here causes the crash handler to be
            //      triggered recursively.
            abort();
        }
    }

    signal!(Sig::SEGV, handler); // handle segfaults
    signal!(Sig::ILL, handler); // handle stack overflow and unsupported CPUs
    signal!(Sig::IOT, handler); // handle double panics
    signal!(Sig::BUS, handler); // handle invalid memory access
}

#[cfg(any(not(feature = "unstable"), target_os = "android"))]
fn install_crash_handler() {}

fn main() {
    install_crash_handler();

    // Parse the command line options and store them globally
    let opts_result = opts::from_cmdline_args(&*args());

    let content_process_token = if let ArgumentParsingResult::ContentProcess(token) = opts_result {
        Some(token)
    } else {
        if opts::get().is_running_problem_test && ::std::env::var("RUST_LOG").is_err() {
            ::std::env::set_var("RUST_LOG", "compositing::constellation");
        }

        None
    };

    // TODO: once log-panics is released, can this be replaced by
    // log_panics::init()?
    panic::set_hook(Box::new(|info| {
        warn!("Panic hook called.");
        let msg = match info.payload().downcast_ref::<&'static str>() {
            Some(s) => *s,
            None => {
                match info.payload().downcast_ref::<String>() {
                    Some(s) => &**s,
                    None => "Box<Any>",
                }
            },
        };
        let current_thread = thread::current();
        let name = current_thread.name().unwrap_or("<unnamed>");
        if let Some(location) = info.location() {
            println!("{} (thread {}, at {}:{})",
                     msg,
                     name,
                     location.file(),
                     location.line());
        } else {
            println!("{} (thread {})", msg, name);
        }
        if env::var("RUST_BACKTRACE").is_ok() {
            println!("{:?}", Backtrace::new());
        }

        error!("{}", msg);
    }));

    setup_logging();

    if let Some(token) = content_process_token {
        return servo::run_content_process(token);
    }

    if opts::get().is_printing_version {
        println!("{}", servo_version());
        process::exit(0);
    }

    let window = glutin_app::create_window();

    let mut browser = browser::Browser::new(window.clone());

    // If the url is not provided, we fallback to the homepage in PREFS,
    // or a blank page in case the homepage is not set either.
    let cwd = env::current_dir().unwrap();
    let cmdline_url = opts::get().url.clone();
    let pref_url = PREFS.get("shell.homepage").as_string()
        .and_then(|str| parse_url_or_filename(&cwd, str).ok());
    let blank_url = ServoUrl::parse("about:blank").ok();

    let target_url = cmdline_url.or(pref_url).or(blank_url).unwrap();

    let mut servo = Servo::new(window.clone());

    let (sender, receiver) = ipc::channel().unwrap();
    servo.handle_events(vec![WindowEvent::NewBrowser(target_url, sender)]);
    let browser_id = receiver.recv().unwrap();
    browser.set_browser_id(browser_id);
    servo.handle_events(vec![WindowEvent::SelectBrowser(browser_id)]);

    servo.setup_logging();

    window.run(|| {
        let win_events = window.get_events();

        // FIXME: this could be handled by Servo. We don't need
        // a repaint_synchronously function exposed.
        let need_resize = win_events.iter().any(|e| match *e {
            WindowEvent::Resize => true,
            _ => false,
        });

        browser.handle_window_events(win_events);

        let mut servo_events = servo.get_events();
        loop {
            browser.handle_servo_events(servo_events);
            servo.handle_events(browser.get_events());
            if browser.shutdown_requested() {
                return true;
            }
            servo_events = servo.get_events();
            if servo_events.is_empty() {
                break;
            }
        }

        if need_resize {
            servo.repaint_synchronously();
        }
        false
    });

    servo.deinit();

    platform::deinit()
}

#[cfg(target_os = "android")]
fn setup_logging() {
    // Piping logs from stdout/stderr to logcat happens in android_injected_glue.
    ::std::env::set_var("RUST_LOG", "error");

    unsafe { android_injected_glue::ffi::app_dummy() };
}

#[cfg(not(target_os = "android"))]
fn setup_logging() {}

#[cfg(target_os = "android")]
/// Attempt to read parameters from a file since they are not passed to us in Android environments.
/// The first line should be the "servo" argument and the last should be the URL to load.
/// Blank lines and those beginning with a '#' are ignored.
/// Each line should be a separate parameter as would be parsed by the shell.
/// For example, "servo -p 10 http://en.wikipedia.org/wiki/Rust" would take 4 lines.
fn args() -> Vec<String> {
    use std::error::Error;
    use std::fs::File;
    use std::io::{BufRead, BufReader};

    let mut params_file = config::basedir::default_config_dir();
    params_file.push("android_params");
    match File::open(params_file.to_str().unwrap()) {
        Ok(f) => {
            let mut vec = Vec::new();
            let file = BufReader::new(&f);
            for line in file.lines() {
                let l = line.unwrap().trim().to_owned();
                // ignore blank lines and those that start with a '#'
                match l.is_empty() || l.as_bytes()[0] == b'#' {
                    true => (),
                    false => vec.push(l),
                }
            }
            vec
        },
        Err(e) => {
            debug!("Failed to open params file '{}': {}",
                   params_file.to_str().unwrap(),
                   Error::description(&e));
            vec!["servo".to_owned(), "http://en.wikipedia.org/wiki/Rust".to_owned()]
        },
    }
}

#[cfg(not(target_os = "android"))]
fn args() -> Vec<String> {
    use std::env;
    env::args().collect()
}

#[cfg(target_os = "android")]
#[no_mangle]
#[inline(never)]
#[allow(non_snake_case)]
pub extern "C" fn android_main(app: *mut ()) {
    android_injected_glue::android_main2(app as *mut _, move |_, _| main());
}

// These functions aren't actually called. They are here as a link
// hack because Skia references them.

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn glBindVertexArrayOES(_array: usize)
{
    unimplemented!()
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn glDeleteVertexArraysOES(_n: isize, _arrays: *const ())
{
    unimplemented!()
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn glGenVertexArraysOES(_n: isize, _arrays: *const ())
{
    unimplemented!()
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn glRenderbufferStorageMultisampleIMG(_: isize, _: isize, _: isize, _: isize, _: isize)
{
    unimplemented!()
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn glFramebufferTexture2DMultisampleIMG(_: isize, _: isize, _: isize, _: isize, _: isize, _: isize)
{
    unimplemented!()
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn glDiscardFramebufferEXT(_: isize, _: isize, _: *const ())
{
    unimplemented!()
}
<|endoftext|>


<commit_before>//! Key algorithms used in Matrix spec.

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use strum::{AsRefStr, Display, EnumString};

/// The basic key algorithms in the specification.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, AsRefStr, Display, EnumString)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[non_exhaustive]
pub enum DeviceKeyAlgorithm {
    /// The Ed25519 signature algorithm.
    #[strum(to_string = "ed25519")]
    Ed25519,

    /// The Curve25519 ECDH algorithm.
    #[strum(to_string = "curve25519")]
    Curve25519,

    /// The Curve25519 ECDH algorithm, but the key also contains signatures
    #[strum(to_string = "signed_curve25519")]
    SignedCurve25519,
}

/// The server key algorithms defined in the Matrix spec.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, AsRefStr, Display, EnumString)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[non_exhaustive]
pub enum ServerKeyAlgorithm {
    /// The Ed25519 signature algorithm.
    #[strum(to_string = "ed25519")]
    Ed25519,
}
<commit_msg>Use strum(serialize_all) instead of strum(to_string)<commit_after>//! Key algorithms used in Matrix spec.

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use strum::{AsRefStr, Display, EnumString};

/// The basic key algorithms in the specification.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, AsRefStr, Display, EnumString)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[non_exhaustive]
#[strum(serialize_all = "snake_case")]
pub enum DeviceKeyAlgorithm {
    /// The Ed25519 signature algorithm.
    Ed25519,

    /// The Curve25519 ECDH algorithm.
    Curve25519,

    /// The Curve25519 ECDH algorithm, but the key also contains signatures
    SignedCurve25519,
}

/// The server key algorithms defined in the Matrix spec.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, AsRefStr, Display, EnumString)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[non_exhaustive]
#[strum(serialize_all = "snake_case")]
pub enum ServerKeyAlgorithm {
    /// The Ed25519 signature algorithm.
    Ed25519,
}
<|endoftext|>


<commit_before>use std::env;
use std::str;
use std::process;

use serde_json;
use console::strip_ansi_codes;
use glob::{glob_with, MatchOptions};

use prelude::*;
use utils::xcode::{InfoPlist, XcodeProjectInfo};
use utils::releases::{get_xcode_release_name, infer_gradle_release_name};

#[derive(Debug, Deserialize)]
pub struct CodePushPackage {
    pub label: String,
}

#[derive(Debug, Deserialize)]
pub struct CodePushDeployment {
    pub name: String,
    pub package: Option<CodePushPackage>,
}

pub fn get_codepush_deployments(app: &str)
    -> Result<Vec<CodePushDeployment>>
{
    let p = process::Command::new("code-push")
        .arg("deployment")
        .arg("ls")
        .arg(app)
        .arg("--format")
        .arg("json")
        .output()?;
    if !p.status.success() {
        let msgstr;
        let detail = if let Ok(msg) = str::from_utf8(&p.stderr) {
            msgstr = strip_ansi_codes(msg);
            if &msgstr[..9] == "[Error]  " {
                &msgstr[9..]
            } else if &msgstr[..8] == "[Error] " {
                &msgstr[8..]
            } else {
                &msgstr
            }
        } else {
            "Unknown Error"
        };
        return Err(format!("Failed to get codepush deployments ({})", detail).into());
    }
    Ok(serde_json::from_slice(&p.stdout)?)
}

pub fn get_codepush_package(app: &str, deployment: &str)
    -> Result<CodePushPackage>
{
    let deployments = get_codepush_deployments(app)?;
    for dep in deployments {
        if_chain! {
            if &dep.name == deployment;
            if let Some(pkg) = dep.package;
            then {
                return Ok(pkg);
            }
        }
    }

    Err(format!("could not find deployment {} for {}", deployment, app).into())
}

pub fn get_react_native_codepush_release(package: &CodePushPackage, platform: &str,
                                         bundle_id_override: Option<&str>)
    -> Result<String>
{
    if let Some(bundle_id) = bundle_id_override {
        return Ok(format!("{}-codepush:{}", bundle_id, package.label));
    }

    if platform == "ios" {
        if !cfg!(target_os="macos") {
            return Err("Codepush releases for iOS require OS X if no \
                        bundle ID is specified".into());
        }
        let mut opts = MatchOptions::new();
        opts.case_sensitive = false;
        for entry_rv in glob_with("ios/*.xcodeproj", &opts)? {
            if let Ok(entry) = entry_rv {
                let pi = XcodeProjectInfo::from_path(&entry)?;
                if let Some(ipl) = InfoPlist::from_project_info(&pi)? {
                    if let Some(release_name) = get_xcode_release_name(Some(ipl))? {
                        return Ok(format!("{}-codepush:{}", release_name, package.label));
                    }
                }
            }
        }
        return Err("Could not find plist".into());
    } else if platform == "android" {
        if_chain! {
            if let Ok(here) = env::current_dir();
            if let Ok(android_folder) = here.join("android").metadata();
            if android_folder.is_dir();
            then {
                return if let Some(release_name) = infer_gradle_release_name(Some(here.join("android")))? {
                    Ok(format!("{}-codepush:{}", release_name, package.label))
                } else {
                    Err("Could not parse app id from build.gradle".into())
                }
            }
        }
        return Err("Could not find AndroidManifest.xml".into());
    }
    return Err(format!("Unsupported platform '{}'", platform).into());
}
<commit_msg>ref(codepush): Improve codepush error messages (#220)<commit_after>use std::env;
use std::io;
use std::path::Path;
use std::process;
use std::str;

use serde_json;
use console::strip_ansi_codes;
use glob::{glob_with, MatchOptions};

use prelude::*;
use utils::xcode::{InfoPlist, XcodeProjectInfo};
use utils::releases::{get_xcode_release_name, infer_gradle_release_name};

static CODEPUSH_BIN_PATH: &'static str = "code-push";
static CODEPUSH_NPM_PATH: &'static str = "node_modules/.bin/code-push";

#[derive(Debug, Deserialize)]
pub struct CodePushPackage {
    pub label: String,
}

#[derive(Debug, Deserialize)]
pub struct CodePushDeployment {
    pub name: String,
    pub package: Option<CodePushPackage>,
}

fn get_codepush_error(output: process::Output) -> Error {
    if let Ok(message) = str::from_utf8(&output.stderr) {
        let stripped = strip_ansi_codes(message);
        Error::from(if stripped.starts_with("[Error]  ") {
            &stripped[9..]
        } else if stripped.starts_with("[Error] ") {
            &stripped[8..]
        } else {
            &stripped
        })
    } else {
        Error::from("Unknown Error")
    }
}

pub fn get_codepush_deployments(app: &str) -> Result<Vec<CodePushDeployment>> {
    let codepush_bin = if Path::new(CODEPUSH_NPM_PATH).exists() {
        CODEPUSH_NPM_PATH
    } else {
        CODEPUSH_BIN_PATH
    };

    let output = process::Command::new(codepush_bin)
        .arg("deployment")
        .arg("ls")
        .arg(app)
        .arg("--format")
        .arg("json")
        .output()
        .map_err(|e| {
            if e.kind() == io::ErrorKind::NotFound {
                "Codepush not found. Is it installed and configured on the PATH?".into()
            } else {
                Error::from(e).chain_err(|| "Failed to run codepush")
            }
        })?;

    if output.status.success() {
        Ok(serde_json::from_slice(&output.stdout)?)
    } else {
        Err(get_codepush_error(output)).chain_err(|| "Failed to get codepush deployments")
    }
}

pub fn get_codepush_package(app: &str, deployment: &str)
    -> Result<CodePushPackage>
{
    let deployments = get_codepush_deployments(app)?;
    for dep in deployments {
        if_chain! {
            if &dep.name == deployment;
            if let Some(pkg) = dep.package;
            then {
                return Ok(pkg);
            }
        }
    }

    Err(format!("Could not find deployment {} for {}", deployment, app).into())
}

pub fn get_react_native_codepush_release(package: &CodePushPackage, platform: &str,
                                         bundle_id_override: Option<&str>)
    -> Result<String>
{
    if let Some(bundle_id) = bundle_id_override {
        return Ok(format!("{}-codepush:{}", bundle_id, package.label));
    }

    if platform == "ios" {
        if !cfg!(target_os="macos") {
            return Err("Codepush releases for iOS require OS X if no \
                        bundle ID is specified".into());
        }
        let mut opts = MatchOptions::new();
        opts.case_sensitive = false;
        for entry_rv in glob_with("ios/*.xcodeproj", &opts)? {
            if let Ok(entry) = entry_rv {
                let pi = XcodeProjectInfo::from_path(&entry)?;
                if let Some(ipl) = InfoPlist::from_project_info(&pi)? {
                    if let Some(release_name) = get_xcode_release_name(Some(ipl))? {
                        return Ok(format!("{}-codepush:{}", release_name, package.label));
                    }
                }
            }
        }
        return Err("Could not find plist".into());
    } else if platform == "android" {
        if_chain! {
            if let Ok(here) = env::current_dir();
            if let Ok(android_folder) = here.join("android").metadata();
            if android_folder.is_dir();
            then {
                return if let Some(release_name) = infer_gradle_release_name(Some(here.join("android")))? {
                    Ok(format!("{}-codepush:{}", release_name, package.label))
                } else {
                    Err("Could not parse app id from build.gradle".into())
                }
            }
        }
        return Err("Could not find AndroidManifest.xml".into());
    }
    return Err(format!("Unsupported platform '{}'", platform).into());
}
<|endoftext|>


<commit_before>//! Interfaces and implementations for directed graphs.
//!
//! This module provides a set of interfaces and implementations of software
//! components for graph representations.  Ergonomics and composability are the
//! main goals here.
//!
//! We would like a graph representation that gives us both fast traversal and
//! fast analysis, and whose API allows for efficient *and* ergonomic use.
//! Naturally there is no best fit, but we can achieve a good fit using
//! a variant of the adjacency-list pattern.
//!
//! Our implementation is based on that of the `petgraph` crate.  Here,
//! however, each node contains space-optimized vectors of outgoing and
//! incoming edges.
//!
//!

mod common;
pub mod iter;
pub mod interface;
pub mod visit;

pub use self::common::{EdgeIndex,NodeIndex,AdjacencyList};
pub use self::weighted::{Edge as WeightedEdge, Node as WeightedNode};
pub use self::interface::{Id,Edge,Node,Graph};

/// Simple data-bearing directed graph.  `N` determines the type of data
/// attached to nodes, `E` the type attached to edges, and `Ix` the integer
/// type used to identify nodes and edges.
pub type WeightedGraph<N, E, Ix = common::DefaultIndexType> = AdjacencyList<WeightedNode<N, EdgeIndex<Ix>>, WeightedEdge<E, NodeIndex<Ix>>>;

/// Unweighted directed graph.  `Ix` determines the integer type used to
/// identify nodes and edges.
pub type BasicGraph<Ix = common::DefaultIndexType> = AdjacencyList<basic::Node<EdgeIndex<Ix>>, basic::Edge<NodeIndex<Ix>>>;

/// Implement `interface::Edge` for a type with members
/// `source: $I` and `target: $I`.
macro_rules! impl_basic_edge {
    ($I: ident) => {
        type NodeId = $I;
        #[inline(always)]
        fn source(&self) -> I { self.source }
        #[inline(always)]
        fn target(&self) -> I { self.target }
    }
}

/// Implement `interface::Node` for a type with members `incoming_edges` and
/// `outgoing_edges` of types compatible with `Vec<$I>`.
macro_rules! impl_basic_node {
    ($I: ident) => {
        type EdgeId = $I;
        #[inline(always)]
        fn incoming_edges(&self) -> std::slice::Iter<$I> {
            self.incoming_edges.iter()
        }

        fn incoming_edge_count(&self) -> usize {
            self.incoming_edges.len()
        }

        #[inline(always)]
        fn outgoing_edges(&self) -> std::slice::Iter<$I> {
            self.outgoing_edges.iter()
        }

        fn outgoing_edge_count(&self) -> usize {
            self.outgoing_edges.len()
        }

        #[inline(always)]
        fn add_incoming_edge(&mut self, e: $I) {
            self.incoming_edges.push(e);
        }

        #[inline(always)]
        fn add_outgoing_edge(&mut self, e: $I) {
            self.outgoing_edges.push(e);
        }
    }
}

pub mod weighted;
pub mod basic;
<commit_msg>util/graph/mod.rs: update module docs<commit_after>//! Interfaces and implementations for directed graphs.
//!
//! This module provides a set of interfaces and implementations of software
//! components for graph representations.
//!
//! These types are designed to maximize composability and ergonomics;
//! currently we have a single graph implementation
//! ([AdjacencyList](struct.AdjacencyList.html), which uses the adjacency-list
//! pattern and integer-based IDs) and two sets of edge/node implementations
//! ([basic](basic/) and [weighted](weighted/)).
//!
//! We would like a graph representation that gives us both fast traversal and
//! fast analysis, and whose API allows for efficient *and* ergonomic use.
//! Naturally there is no best fit, but we can achieve a good fit using
//! a variant of the adjacency-list pattern.
//!
//! Our implementation is based on that of the `petgraph` crate.  Here,
//! however, each node contains space-optimized vectors of outgoing and
//! incoming edges.
//!
//!

mod common;
pub mod iter;
pub mod interface;
pub mod visit;

pub use self::common::{EdgeIndex,NodeIndex,AdjacencyList};
pub use self::weighted::{Edge as WeightedEdge, Node as WeightedNode};
pub use self::interface::{Id,Edge,Node,Graph};

/// Simple data-bearing directed graph.  `N` determines the type of data
/// attached to nodes, `E` the type attached to edges, and `Ix` the integer
/// type used to identify nodes and edges.
pub type WeightedGraph<N, E, Ix = common::DefaultIndexType> = AdjacencyList<WeightedNode<N, EdgeIndex<Ix>>, WeightedEdge<E, NodeIndex<Ix>>>;

/// Unweighted directed graph.  `Ix` determines the integer type used to
/// identify nodes and edges.
pub type BasicGraph<Ix = common::DefaultIndexType> = AdjacencyList<basic::Node<EdgeIndex<Ix>>, basic::Edge<NodeIndex<Ix>>>;

/// Implement `interface::Edge` for a type with members
/// `source: $I` and `target: $I`.
macro_rules! impl_basic_edge {
    ($I: ident) => {
        type NodeId = $I;
        #[inline(always)]
        fn source(&self) -> I { self.source }
        #[inline(always)]
        fn target(&self) -> I { self.target }
    }
}

/// Implement `interface::Node` for a type with members `incoming_edges` and
/// `outgoing_edges` of types compatible with `Vec<$I>`.
macro_rules! impl_basic_node {
    ($I: ident) => {
        type EdgeId = $I;
        #[inline(always)]
        fn incoming_edges(&self) -> std::slice::Iter<$I> {
            self.incoming_edges.iter()
        }

        fn incoming_edge_count(&self) -> usize {
            self.incoming_edges.len()
        }

        #[inline(always)]
        fn outgoing_edges(&self) -> std::slice::Iter<$I> {
            self.outgoing_edges.iter()
        }

        fn outgoing_edge_count(&self) -> usize {
            self.outgoing_edges.len()
        }

        #[inline(always)]
        fn add_incoming_edge(&mut self, e: $I) {
            self.incoming_edges.push(e);
        }

        #[inline(always)]
        fn add_outgoing_edge(&mut self, e: $I) {
            self.outgoing_edges.push(e);
        }
    }
}

pub mod weighted;
pub mod basic;
<|endoftext|>


<commit_before>// Copyright 2015 The tiny-http Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::sync::{Arc, Mutex, Condvar};
use std::sync::atomic::{Ordering, AtomicUsize};
use std::collections::VecDeque;
use std::thread;

/// Manages a collection of threads.
///
/// A new thread is created every time all the existing threads are full.
/// Any idle thread will automatically die after a few seconds.
pub struct TaskPool {
    sharing: Arc<Sharing>,
}

struct Sharing {
    // list of the tasks to be done by worker threads
    todo: Mutex<VecDeque<Box<FnMut() + Send>>>,

    // condvar that will be notified whenever a task is added to `todo`
    condvar: Condvar,

    // number of total worker threads running
    active_tasks: AtomicUsize,

    // number of idle worker threads
    waiting_tasks: AtomicUsize,
}

/// Minimum number of active threads.
static MIN_THREADS: usize = 4;

struct Registration<'a> {
    nb: &'a AtomicUsize
}

impl<'a> Registration<'a> {
    fn new(nb: &'a AtomicUsize) -> Registration<'a> {
        nb.fetch_add(1, Ordering::Relaxed);
        Registration { nb: nb }
    }
}

impl<'a> Drop for Registration<'a> {
    fn drop(&mut self) {
        self.nb.fetch_sub(1, Ordering::Relaxed);
    }
}

impl TaskPool {
    pub fn new() -> TaskPool {
        let pool = TaskPool {
            sharing: Arc::new(Sharing {
                todo: Mutex::new(VecDeque::new()),
                condvar: Condvar::new(),
                active_tasks: AtomicUsize::new(0),
                waiting_tasks: AtomicUsize::new(0),
            }),
        };

        for _ in 0..MIN_THREADS {
            pool.add_thread(None)
        }

        pool
    }

    /// Executes a function in a thread.
    /// If no thread is available, spawns a new one.
    pub fn spawn(&self, code: Box<FnMut() + Send>) {
        let mut queue = self.sharing.todo.lock().unwrap();

        if self.sharing.waiting_tasks.load(Ordering::Relaxed) == 0 {
            self.add_thread(Some(code));

        } else {
            queue.push_back(code);
            self.sharing.condvar.notify_one();
        }
    }

    fn add_thread(&self, initial_fn: Option<Box<FnMut() + Send>>) {
        let sharing = self.sharing.clone();

        thread::spawn(move || {
            let sharing = sharing;
            let _ = Registration::new(&sharing.active_tasks);

            if initial_fn.is_some() {
                let mut f = initial_fn.unwrap();
                f();
            }

            loop {
                let mut task: Box<FnMut() + Send> = {
                    let mut todo = sharing.todo.lock().unwrap();

                    let task;
                    loop {
                        if let Some(poped_task) = todo.pop_front() {
                            task = poped_task;
                            break;

                        } else {
                            let _ = Registration::new(&sharing.waiting_tasks);

                            let received = if sharing.active_tasks.load(Ordering::Relaxed)
                                                    <= MIN_THREADS
                            {
                                todo = sharing.condvar.wait(todo).unwrap();
                                true

                            } else {
                                let (new_lock, receved) = sharing.condvar
                                                                 .wait_timeout_ms(todo, 5000)
                                                                 .unwrap();
                                todo = new_lock;
                                receved
                            };

                            if !received && todo.is_empty() {
                                return;
                            }
                        }
                    }

                    task
                };

                task();
            }
        });
    }
}

impl Drop for TaskPool {
    fn drop(&mut self) {
        self.sharing.active_tasks.store(999999999, Ordering::Relaxed);
        self.sharing.condvar.notify_all();
    }
}
<commit_msg>Fix the thread_pool<commit_after>// Copyright 2015 The tiny-http Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::sync::{Arc, Mutex, Condvar};
use std::sync::atomic::{Ordering, AtomicUsize};
use std::collections::VecDeque;
use std::thread;

/// Manages a collection of threads.
///
/// A new thread is created every time all the existing threads are full.
/// Any idle thread will automatically die after a few seconds.
pub struct TaskPool {
    sharing: Arc<Sharing>,
}

struct Sharing {
    // list of the tasks to be done by worker threads
    todo: Mutex<VecDeque<Box<FnMut() + Send>>>,

    // condvar that will be notified whenever a task is added to `todo`
    condvar: Condvar,

    // number of total worker threads running
    active_tasks: AtomicUsize,

    // number of idle worker threads
    waiting_tasks: AtomicUsize,
}

/// Minimum number of active threads.
static MIN_THREADS: usize = 4;

struct Registration<'a> {
    nb: &'a AtomicUsize
}

impl<'a> Registration<'a> {
    fn new(nb: &'a AtomicUsize) -> Registration<'a> {
        nb.fetch_add(1, Ordering::Release);
        Registration { nb: nb }
    }
}

impl<'a> Drop for Registration<'a> {
    fn drop(&mut self) {
        self.nb.fetch_sub(1, Ordering::Release);
    }
}

impl TaskPool {
    pub fn new() -> TaskPool {
        let pool = TaskPool {
            sharing: Arc::new(Sharing {
                todo: Mutex::new(VecDeque::new()),
                condvar: Condvar::new(),
                active_tasks: AtomicUsize::new(0),
                waiting_tasks: AtomicUsize::new(0),
            }),
        };

        for _ in 0..MIN_THREADS {
            pool.add_thread(None)
        }

        pool
    }

    /// Executes a function in a thread.
    /// If no thread is available, spawns a new one.
    pub fn spawn(&self, code: Box<FnMut() + Send>) {
        let mut queue = self.sharing.todo.lock().unwrap();

        if self.sharing.waiting_tasks.load(Ordering::Acquire) == 0 {
            self.add_thread(Some(code));

        } else {
            queue.push_back(code);
            self.sharing.condvar.notify_one();
        }
    }

    fn add_thread(&self, initial_fn: Option<Box<FnMut() + Send>>) {
        let sharing = self.sharing.clone();

        thread::spawn(move || {
            let sharing = sharing;
            let _active_guard = Registration::new(&sharing.active_tasks);

            if initial_fn.is_some() {
                let mut f = initial_fn.unwrap();
                f();
            }

            loop {
                let mut task: Box<FnMut() + Send> = {
                    let mut todo = sharing.todo.lock().unwrap();

                    let task;
                    loop {
                        if let Some(poped_task) = todo.pop_front() {
                            task = poped_task;
                            break;

                        } else {
                            let _waiting_guard = Registration::new(&sharing.waiting_tasks);

                            let received = if sharing.active_tasks.load(Ordering::Acquire)
                                                    <= MIN_THREADS
                            {
                                todo = sharing.condvar.wait(todo).unwrap();
                                true

                            } else {
                                let (new_lock, receved) = sharing.condvar
                                                                 .wait_timeout_ms(todo, 5000)
                                                                 .unwrap();
                                todo = new_lock;
                                receved
                            };

                            if !received && todo.is_empty() {
                                return;
                            }
                        }
                    }

                    task
                };

                task();
            }
        });
    }
}

impl Drop for TaskPool {
    fn drop(&mut self) {
        self.sharing.active_tasks.store(999999999, Ordering::Release);
        self.sharing.condvar.notify_all();
    }
}
<|endoftext|>


<commit_before>#![allow(unused, missing_docs)]

use std::fmt;
use std::iter::repeat;
use elements::{BlockType, External, FunctionType, GlobalEntry, GlobalType, Internal, MemoryType,
               Module, Opcode, ResizableLimits, TableType, Type, ValueType};
use common::stack;
use self::context::ModuleContext;
use self::func::{FunctionValidationContext, Validator};

pub use self::module::ValidatedModule;

mod context;
mod module;
mod func;

#[cfg(test)]
mod tests;

pub struct Error(String);

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

impl From<stack::Error> for Error {
	fn from(e: stack::Error) -> Error {
		Error(format!("Stack: {}", e))
	}
}

pub fn validate_module(module: &Module) -> Result<ValidatedModule, Error> {
	let context = prepare_context(module)?;

	let function_section_len = module
		.function_section()
		.map(|s| s.entries().len())
		.unwrap_or(0);
	let code_section_len = module.code_section().map(|s| s.bodies().len()).unwrap_or(0);
	if function_section_len != code_section_len {
		return Err(Error(format!(
			"length of function section is {}, while len of code section is {}",
			function_section_len,
			code_section_len
		)));
	}

	// validate every function body in user modules
	if function_section_len != 0 {
		// tests use invalid code
		let function_section = module
			.function_section()
			.expect("function_section_len != 0; qed");
		let code_section = module
			.code_section()
			.expect("function_section_len != 0; function_section_len == code_section_len; qed");
		// check every function body
		for (index, function) in function_section.entries().iter().enumerate() {
			let function_body = code_section
				.bodies()
				.get(index as usize)
				.ok_or(Error(format!("Missing body for function {}", index)))?;
			Validator::validate_function(&context, function, function_body).map_err(|e| {
				let Error(ref msg) = e;
				Error(format!("Function #{} validation error: {}", index, msg))
			})?;
		}
	}

	// validate start section
	if let Some(start_function) = module.start_section() {
		let (params, return_ty) = context.require_function(start_function)?;
		if return_ty != BlockType::NoResult || params.len() != 0 {
			return Err(Error(
				"start function expected to have type [] -> []".into(),
			));
		}
	}

	// validate export section
	if let Some(export_section) = module.export_section() {
		for export in export_section.entries() {
			match export.internal() {
				&Internal::Function(function_index) => {
					context.require_function(function_index)?;
				}
				&Internal::Global(global_index) => {
					context.require_global(global_index, Some(false))?;
				}
				&Internal::Memory(memory_index) => {
					context.require_memory(memory_index)?;
				}
				&Internal::Table(table_index) => {
					context.require_table(table_index)?;
				}
			}
		}
	}

	let ModuleContext {
		types,
		tables,
		memories,
		globals,
		func_type_indexes,
	} = context;

	Ok(ValidatedModule {
		types,
		tables,
		memories,
		globals,
		func_type_indexes,
	})
}

fn prepare_context(module: &Module) -> Result<ModuleContext, Error> {
	// TODO: Validate imports

	// Copy types from module as is.
	let types = module
		.type_section()
		.map(|ts| ts.types().into_iter().cloned().collect())
		.unwrap_or_default();

	// Fill elements with imported values.

	// TODO: Use Func::type_ref?
	let mut func_type_indexes = Vec::new();
	let mut tables = Vec::new();
	let mut memories = Vec::new();
	let mut globals = Vec::new();

	for import_entry in module
		.import_section()
		.map(|i| i.entries())
		.unwrap_or_default()
	{
		match import_entry.external() {
			&External::Function(idx) => func_type_indexes.push(idx),
			&External::Table(ref table) => tables.push(table.clone()),
			&External::Memory(ref memory) => memories.push(memory.clone()),
			&External::Global(ref global) => globals.push(global.clone()),
		}
	}

	// Concatenate elements with defined in the module.
	if let Some(function_section) = module.function_section() {
		for func_entry in function_section.entries() {
			func_type_indexes.push(func_entry.type_ref());
		}
	}
	if let Some(table_section) = module.table_section() {
		for table_entry in table_section.entries() {
			table_entry.validate()?;
			tables.push(table_entry.clone());
		}
	}
	if let Some(mem_section) = module.memory_section() {
		for mem_entry in mem_section.entries() {
			mem_entry.validate()?;
			memories.push(mem_entry.clone());
		}
	}
	if let Some(global_section) = module.global_section() {
		// Validation of globals is defined over modified context C', which
		// contains only imported globals. So we do globals validation
		// in two passes, in first we validate globals and after all globals are validated
		// add them in globals list.
		for global_entry in global_section.entries() {
			global_entry.validate(&globals)?;
		}

		for global_entry in global_section.entries() {
			globals.push(global_entry.global_type().clone());
		}
	}

	Ok(ModuleContext {
		types,
		tables,
		memories,
		globals,
		func_type_indexes,
	})
}

impl ResizableLimits {
	fn validate(&self) -> Result<(), Error> {
		if let Some(maximum) = self.maximum() {
			if self.initial() > maximum {
				return Err(Error(format!(
					"maximum limit {} is lesser than minimum {}",
					maximum,
					self.initial()
				)));
			}
		}
		Ok(())
	}
}

impl MemoryType {
	fn validate(&self) -> Result<(), Error> {
		self.limits().validate()
	}
}

impl TableType {
	fn validate(&self) -> Result<(), Error> {
		self.limits().validate()
	}
}

impl GlobalEntry {
	fn validate(&self, globals_sofar: &[GlobalType]) -> Result<(), Error> {
		let init = self.init_expr().code();
		if init.len() != 2 {
			return Err(Error(
				format!("Init expression should always be with length 2"),
			));
		}
		let init_expr_ty: ValueType = match init[0] {
			Opcode::I32Const(_) => ValueType::I32,
			Opcode::I64Const(_) => ValueType::I64,
			Opcode::F32Const(_) => ValueType::F32,
			Opcode::F64Const(_) => ValueType::F64,
			Opcode::GetGlobal(idx) => match globals_sofar.get(idx as usize) {
				Some(target_global) => {
					if target_global.is_mutable() {
						return Err(Error(format!("Global {} is mutable", idx)));
					}
					target_global.content_type()
				}
				None => {
					return Err(Error(
						format!("Global {} doesn't exists or not yet defined", idx),
					))
				}
			},
			_ => return Err(Error(format!("Non constant opcode in init expr"))),
		};
		if init_expr_ty != self.global_type().content_type() {
			return Err(Error(format!(
				"Trying to initialize variable of type {:?} with value of type {:?}",
				self.global_type().content_type(),
				init_expr_ty
			)));
		}
		if init[1] != Opcode::End {
			return Err(Error(format!("Expression doesn't ends with `end` opcode")));
		}
		Ok(())
	}
}
<commit_msg>Add checks for tables and memories count.<commit_after>#![allow(unused, missing_docs)]

use std::fmt;
use std::iter::repeat;
use elements::{BlockType, External, FunctionType, GlobalEntry, GlobalType, Internal, MemoryType,
               Module, Opcode, ResizableLimits, TableType, Type, ValueType};
use common::stack;
use self::context::ModuleContext;
use self::func::{FunctionValidationContext, Validator};

pub use self::module::ValidatedModule;

mod context;
mod module;
mod func;

#[cfg(test)]
mod tests;

pub struct Error(String);

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

impl From<stack::Error> for Error {
	fn from(e: stack::Error) -> Error {
		Error(format!("Stack: {}", e))
	}
}

pub fn validate_module(module: &Module) -> Result<ValidatedModule, Error> {
	let context = prepare_context(module)?;

	let function_section_len = module
		.function_section()
		.map(|s| s.entries().len())
		.unwrap_or(0);
	let code_section_len = module.code_section().map(|s| s.bodies().len()).unwrap_or(0);
	if function_section_len != code_section_len {
		return Err(Error(format!(
			"length of function section is {}, while len of code section is {}",
			function_section_len,
			code_section_len
		)));
	}

	// validate every function body in user modules
	if function_section_len != 0 {
		// tests use invalid code
		let function_section = module
			.function_section()
			.expect("function_section_len != 0; qed");
		let code_section = module
			.code_section()
			.expect("function_section_len != 0; function_section_len == code_section_len; qed");
		// check every function body
		for (index, function) in function_section.entries().iter().enumerate() {
			let function_body = code_section
				.bodies()
				.get(index as usize)
				.ok_or(Error(format!("Missing body for function {}", index)))?;
			Validator::validate_function(&context, function, function_body).map_err(|e| {
				let Error(ref msg) = e;
				Error(format!("Function #{} validation error: {}", index, msg))
			})?;
		}
	}

	// validate start section
	if let Some(start_function) = module.start_section() {
		let (params, return_ty) = context.require_function(start_function)?;
		if return_ty != BlockType::NoResult || params.len() != 0 {
			return Err(Error(
				"start function expected to have type [] -> []".into(),
			));
		}
	}

	// validate export section
	if let Some(export_section) = module.export_section() {
		for export in export_section.entries() {
			match export.internal() {
				&Internal::Function(function_index) => {
					context.require_function(function_index)?;
				}
				&Internal::Global(global_index) => {
					context.require_global(global_index, Some(false))?;
				}
				&Internal::Memory(memory_index) => {
					context.require_memory(memory_index)?;
				}
				&Internal::Table(table_index) => {
					context.require_table(table_index)?;
				}
			}
		}
	}

	// there must be no greater than 1 table in tables index space
	if context.tables().len() > 1 {
		return Err(Error(format!("too many tables in index space: {}", context.tables().len())));
	}

	// there must be no greater than 1 linear memory in memory index space
	if context.memories().len() > 1 {
		return Err(Error(format!("too many memory regions in index space: {}", context.memories().len())));
	}

	let ModuleContext {
		types,
		tables,
		memories,
		globals,
		func_type_indexes,
	} = context;

	Ok(ValidatedModule {
		types,
		tables,
		memories,
		globals,
		func_type_indexes,
	})
}

fn prepare_context(module: &Module) -> Result<ModuleContext, Error> {
	// TODO: Validate imports

	// Copy types from module as is.
	let types = module
		.type_section()
		.map(|ts| ts.types().into_iter().cloned().collect())
		.unwrap_or_default();

	// Fill elements with imported values.

	// TODO: Use Func::type_ref?
	let mut func_type_indexes = Vec::new();
	let mut tables = Vec::new();
	let mut memories = Vec::new();
	let mut globals = Vec::new();

	for import_entry in module
		.import_section()
		.map(|i| i.entries())
		.unwrap_or_default()
	{
		match import_entry.external() {
			&External::Function(idx) => func_type_indexes.push(idx),
			&External::Table(ref table) => tables.push(table.clone()),
			&External::Memory(ref memory) => memories.push(memory.clone()),
			&External::Global(ref global) => globals.push(global.clone()),
		}
	}

	// Concatenate elements with defined in the module.
	if let Some(function_section) = module.function_section() {
		for func_entry in function_section.entries() {
			func_type_indexes.push(func_entry.type_ref());
		}
	}
	if let Some(table_section) = module.table_section() {
		for table_entry in table_section.entries() {
			table_entry.validate()?;
			tables.push(table_entry.clone());
		}
	}
	if let Some(mem_section) = module.memory_section() {
		for mem_entry in mem_section.entries() {
			mem_entry.validate()?;
			memories.push(mem_entry.clone());
		}
	}
	if let Some(global_section) = module.global_section() {
		// Validation of globals is defined over modified context C', which
		// contains only imported globals. So we do globals validation
		// in two passes, in first we validate globals and after all globals are validated
		// add them in globals list.
		for global_entry in global_section.entries() {
			global_entry.validate(&globals)?;
		}

		for global_entry in global_section.entries() {
			globals.push(global_entry.global_type().clone());
		}
	}

	Ok(ModuleContext {
		types,
		tables,
		memories,
		globals,
		func_type_indexes,
	})
}

impl ResizableLimits {
	fn validate(&self) -> Result<(), Error> {
		if let Some(maximum) = self.maximum() {
			if self.initial() > maximum {
				return Err(Error(format!(
					"maximum limit {} is lesser than minimum {}",
					maximum,
					self.initial()
				)));
			}
		}
		Ok(())
	}
}

impl MemoryType {
	fn validate(&self) -> Result<(), Error> {
		self.limits().validate()
	}
}

impl TableType {
	fn validate(&self) -> Result<(), Error> {
		self.limits().validate()
	}
}

impl GlobalEntry {
	fn validate(&self, globals_sofar: &[GlobalType]) -> Result<(), Error> {
		let init = self.init_expr().code();
		if init.len() != 2 {
			return Err(Error(
				format!("Init expression should always be with length 2"),
			));
		}
		let init_expr_ty: ValueType = match init[0] {
			Opcode::I32Const(_) => ValueType::I32,
			Opcode::I64Const(_) => ValueType::I64,
			Opcode::F32Const(_) => ValueType::F32,
			Opcode::F64Const(_) => ValueType::F64,
			Opcode::GetGlobal(idx) => match globals_sofar.get(idx as usize) {
				Some(target_global) => {
					if target_global.is_mutable() {
						return Err(Error(format!("Global {} is mutable", idx)));
					}
					target_global.content_type()
				}
				None => {
					return Err(Error(
						format!("Global {} doesn't exists or not yet defined", idx),
					))
				}
			},
			_ => return Err(Error(format!("Non constant opcode in init expr"))),
		};
		if init_expr_ty != self.global_type().content_type() {
			return Err(Error(format!(
				"Trying to initialize variable of type {:?} with value of type {:?}",
				self.global_type().content_type(),
				init_expr_ty
			)));
		}
		if init[1] != Opcode::End {
			return Err(Error(format!("Expression doesn't ends with `end` opcode")));
		}
		Ok(())
	}
}
<|endoftext|>


<commit_before>use plexus::integration::nalgebra;

use bytemuck::{self, Pod, Zeroable};
use decorum::cmp::FloatEq;
use decorum::hash::FloatHash;
use fool::and;
use futures::task::LocalSpawn;
use nalgebra::{Point3, Scalar, Vector4};
use num::{self, One};
use plexus::buffer::{IntoFlatIndex, MeshBuffer};
use plexus::geometry::{FromGeometry, IntoGeometry, UnitGeometry};
use plexus::index::Flat;
use plexus::U3;
use rand::distributions::{Distribution, Standard};
use rand::{self, Rng};
use std::f32::consts::FRAC_PI_4;
use std::hash::{Hash, Hasher};
use std::mem;
use wgpu::util::{BufferInitDescriptor, DeviceExt};
use wgpu::{
    include_spirv, BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor,
    BindGroupLayoutEntry, BindingType, BlendDescriptor, Buffer, BufferAddress, BufferSize,
    BufferUsage, Color, ColorStateDescriptor, ColorWrite, CommandEncoderDescriptor,
    CompareFunction, CullMode, DepthStencilStateDescriptor, Extent3d, FrontFace, IndexFormat,
    InputStepMode, LoadOp, Operations, PipelineLayoutDescriptor, PrimitiveTopology,
    ProgrammableStageDescriptor, RasterizationStateDescriptor, RenderPassColorAttachmentDescriptor,
    RenderPassDepthStencilAttachmentDescriptor, RenderPassDescriptor, RenderPipeline,
    RenderPipelineDescriptor, ShaderStage, SwapChainTexture, TextureDescriptor, TextureDimension,
    TextureFormat, TextureUsage, TextureView, VertexAttributeDescriptor, VertexBufferDescriptor,
    VertexFormat, VertexStateDescriptor,
};
use winit::event::{ElementState, KeyboardInput, VirtualKeyCode, WindowEvent};
use winit::window::WindowBuilder;

use crate::camera::{Camera, Projection};
use crate::harness::{self, Application, ConfigureStage, Reaction, RenderStage};

use Reaction::Abort;
use Reaction::Continue;

#[derive(Clone, Copy, Debug)]
pub struct Color4<T>(pub Vector4<T>)
where
    T: Scalar;

impl<T> Color4<T>
where
    T: Scalar,
{
    pub fn white() -> Self
    where
        T: One,
    {
        Color4(Vector4::repeat(One::one()))
    }

    pub fn random() -> Self
    where
        Standard: Distribution<T>,
    {
        let mut rng = rand::thread_rng();
        Color4(Vector4::from_fn(|_, _| rng.gen()))
    }
}

impl<T> AsRef<Vector4<T>> for Color4<T>
where
    T: Scalar,
{
    fn as_ref(&self) -> &Vector4<T> {
        &self.0
    }
}

impl<T> Default for Color4<T>
where
    T: One + Scalar,
{
    fn default() -> Self {
        Color4::white()
    }
}

impl<T> From<Vector4<T>> for Color4<T>
where
    T: Scalar,
{
    fn from(vector: Vector4<T>) -> Self {
        Color4(vector)
    }
}

impl<T> Into<Vector4<T>> for Color4<T>
where
    T: Scalar,
{
    fn into(self) -> Vector4<T> {
        self.0
    }
}

impl<T> UnitGeometry for Color4<T> where T: One + Scalar {}

#[derive(Clone, Copy)]
#[repr(C)]
pub struct Vertex {
    pub position: [f32; 4],
    pub normal: [f32; 4],
    pub color: [f32; 4],
}

impl Eq for Vertex {}

impl Hash for Vertex {
    fn hash<H>(&self, state: &mut H)
    where
        H: Hasher,
    {
        self.position.float_hash(state);
        self.normal.float_hash(state);
        self.color.float_hash(state);
    }
}

impl PartialEq for Vertex {
    fn eq(&self, other: &Self) -> bool {
        and!(
            self.position.float_eq(&other.position),
            self.normal.float_eq(&other.normal),
            self.color.float_eq(&other.color),
        )
    }
}

unsafe impl Pod for Vertex {}

unsafe impl Zeroable for Vertex {}

struct RenderState {
    camera: Camera,
    from: Point3<f32>,
    buffer: MeshBuffer<Flat<U3, u32>, Vertex>,
}

struct RenderApplication {
    camera: Camera,
    _viewpoint: Buffer,
    transform: Buffer,
    vertices: Buffer,
    indices: Buffer,
    depth: TextureView,
    n: u32,
    bind_group: BindGroup,
    pipeline: RenderPipeline,
}

impl RenderApplication {
    fn configure_depth_buffer(stage: &impl ConfigureStage) -> TextureView {
        stage
            .device()
            .create_texture(&TextureDescriptor {
                label: None,
                size: Extent3d {
                    width: stage.swap_chain_descriptor().width,
                    height: stage.swap_chain_descriptor().height,
                    depth: 1,
                },
                mip_level_count: 1,
                sample_count: 1,
                dimension: TextureDimension::D2,
                format: TextureFormat::Depth32Float,
                usage: TextureUsage::COPY_DST | TextureUsage::OUTPUT_ATTACHMENT,
            })
            .create_view(&Default::default())
    }
}

impl Application for RenderApplication {
    type State = RenderState;
    type Error = ();

    fn configure(state: Self::State, stage: &impl ConfigureStage) -> Result<Self, Self::Error> {
        let RenderState {
            mut camera,
            from,
            buffer,
        } = state;
        camera.reproject(stage.swap_chain_descriptor());
        let vertices = stage.device().create_buffer_init(&BufferInitDescriptor {
            label: None,
            contents: bytemuck::cast_slice(buffer.as_vertex_slice()),
            usage: BufferUsage::VERTEX,
        });
        let indices = stage.device().create_buffer_init(&BufferInitDescriptor {
            label: None,
            contents: bytemuck::cast_slice(buffer.as_index_slice()),
            usage: BufferUsage::INDEX,
        });
        let transform = stage.device().create_buffer_init(&BufferInitDescriptor {
            label: None,
            contents: bytemuck::cast_slice(camera.transform().as_slice()),
            usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
        });
        let viewpoint = stage.device().create_buffer_init(&BufferInitDescriptor {
            label: None,
            contents: bytemuck::cast_slice(from.coords.as_slice()),
            usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
        });
        let depth = Self::configure_depth_buffer(stage);
        let bind_group_layout =
            stage
                .device()
                .create_bind_group_layout(&BindGroupLayoutDescriptor {
                    label: None,
                    entries: &[
                        BindGroupLayoutEntry {
                            binding: 0,
                            visibility: ShaderStage::VERTEX,
                            ty: BindingType::UniformBuffer {
                                dynamic: false,
                                min_binding_size: BufferSize::new(64),
                            },
                            count: None,
                        },
                        BindGroupLayoutEntry {
                            binding: 1,
                            visibility: ShaderStage::VERTEX,
                            ty: BindingType::UniformBuffer {
                                dynamic: false,
                                min_binding_size: BufferSize::new(12),
                            },
                            count: None,
                        },
                    ],
                });
        let bind_group = stage.device().create_bind_group(&BindGroupDescriptor {
            label: None,
            layout: &bind_group_layout,
            entries: &[
                BindGroupEntry {
                    binding: 0,
                    resource: transform.as_entire_binding(),
                },
                BindGroupEntry {
                    binding: 1,
                    resource: viewpoint.as_entire_binding(),
                },
            ],
        });
        let pipeline =
            stage
                .device()
                .create_render_pipeline(&RenderPipelineDescriptor {
                    label: None,
                    layout: Some(&stage.device().create_pipeline_layout(
                        &PipelineLayoutDescriptor {
                            label: None,
                            bind_group_layouts: &[&bind_group_layout],
                            push_constant_ranges: &[],
                        },
                    )),
                    vertex_stage: ProgrammableStageDescriptor {
                        module: &stage
                            .device()
                            .create_shader_module(include_spirv!("shader.spv.vert")),
                        entry_point: "main",
                    },
                    fragment_stage: Some(ProgrammableStageDescriptor {
                        module: &stage
                            .device()
                            .create_shader_module(include_spirv!("shader.spv.frag")),
                        entry_point: "main",
                    }),
                    vertex_state: VertexStateDescriptor {
                        index_format: IndexFormat::Uint32,
                        vertex_buffers: &[VertexBufferDescriptor {
                            stride: mem::size_of::<Vertex>() as BufferAddress,
                            step_mode: InputStepMode::Vertex,
                            attributes: &[
                                #[allow(clippy::erasing_op)]
                                VertexAttributeDescriptor {
                                    format: VertexFormat::Float4,
                                    offset: 0 * 4 * 4,
                                    shader_location: 0,
                                },
                                #[allow(clippy::identity_op)]
                                VertexAttributeDescriptor {
                                    format: VertexFormat::Float4,
                                    offset: 1 * 4 * 4,
                                    shader_location: 1,
                                },
                                VertexAttributeDescriptor {
                                    format: VertexFormat::Float4,
                                    offset: 2 * 4 * 4,
                                    shader_location: 2,
                                },
                            ],
                        }],
                    },
                    primitive_topology: PrimitiveTopology::TriangleList,
                    rasterization_state: Some(RasterizationStateDescriptor {
                        front_face: FrontFace::Ccw,
                        cull_mode: CullMode::Back,
                        ..Default::default()
                    }),
                    color_states: &[ColorStateDescriptor {
                        format: stage.swap_chain_descriptor().format,
                        color_blend: BlendDescriptor::REPLACE,
                        alpha_blend: BlendDescriptor::REPLACE,
                        write_mask: ColorWrite::ALL,
                    }],
                    depth_stencil_state: Some(DepthStencilStateDescriptor {
                        format: TextureFormat::Depth32Float,
                        depth_write_enabled: true,
                        depth_compare: CompareFunction::Less,
                        stencil: Default::default(),
                    }),
                    alpha_to_coverage_enabled: false,
                    sample_count: 1,
                    sample_mask: !0,
                });
        Ok(RenderApplication {
            camera,
            _viewpoint: viewpoint,
            transform,
            vertices,
            indices,
            depth,
            n: buffer.as_index_slice().len() as u32,
            bind_group,
            pipeline,
        })
    }

    fn react(&mut self, event: WindowEvent) -> Reaction {
        match event {
            WindowEvent::KeyboardInput { input, .. } => match input {
                KeyboardInput {
                    virtual_keycode: Some(VirtualKeyCode::Escape),
                    state: ElementState::Pressed,
                    ..
                } => Abort,
                _ => Continue,
            },
            _ => Continue,
        }
    }

    fn resize(&mut self, stage: &impl ConfigureStage) {
        self.camera.reproject(stage.swap_chain_descriptor());
        stage.queue().write_buffer(
            &self.transform,
            0,
            bytemuck::cast_slice(self.camera.transform().as_slice()),
        );
        self.depth = Self::configure_depth_buffer(stage);
    }

    fn render(&mut self, stage: &impl RenderStage, frame: &SwapChainTexture, _: &impl LocalSpawn) {
        let mut encoder = stage
            .device()
            .create_command_encoder(&CommandEncoderDescriptor { label: None });
        let mut pass = encoder.begin_render_pass(&RenderPassDescriptor {
            color_attachments: &[RenderPassColorAttachmentDescriptor {
                attachment: &frame.view,
                resolve_target: None,
                ops: Operations {
                    load: LoadOp::Clear(Color {
                        r: 0.1,
                        g: 0.2,
                        b: 0.3,
                        a: 1.0,
                    }),
                    store: true,
                },
            }],
            depth_stencil_attachment: Some(RenderPassDepthStencilAttachmentDescriptor {
                attachment: &self.depth,
                depth_ops: Some(Operations {
                    load: LoadOp::Clear(1.0),
                    store: true,
                }),
                stencil_ops: None,
            }),
        });
        pass.set_pipeline(&self.pipeline);
        pass.set_bind_group(0, &self.bind_group, &[]);
        pass.set_index_buffer(self.indices.slice(..));
        pass.set_vertex_buffer(0, self.vertices.slice(..));
        pass.draw_indexed(0..self.n, 0, 0..1);
        drop(pass); // Release `encoder`.
        stage.queue().submit(Some(encoder.finish()));
    }
}

pub fn render_mesh_buffer_with<M, G, F>(from: Point3<f32>, to: Point3<f32>, f: F)
where
    M: IntoFlatIndex<U3, G, Item = u32>,
    Vertex: FromGeometry<G>,
    F: FnOnce() -> M,
{
    let camera = {
        let mut camera = Camera::from(Projection::perspective(1.0, FRAC_PI_4, 1.0, 10.0));
        camera.look_at(&from, &to);
        camera
    };
    let buffer = f()
        .into_flat_index()
        .map_vertices(|vertex| vertex.into_geometry());
    harness::run::<RenderApplication, _>(
        RenderState {
            camera,
            from,
            buffer,
        },
        |reactor| {
            WindowBuilder::default()
                .with_title("Plexus")
                .build(reactor)
                .unwrap()
        },
    );
}
<commit_msg>Always saturate the alpha channel when creating random colors.<commit_after>use plexus::integration::nalgebra;
use plexus::integration::theon;

use bytemuck::{self, Pod, Zeroable};
use decorum::cmp::FloatEq;
use decorum::hash::FloatHash;
use fool::and;
use futures::task::LocalSpawn;
use nalgebra::{Point3, Scalar, Vector3, Vector4};
use num::{self, One};
use plexus::buffer::{IntoFlatIndex, MeshBuffer};
use plexus::geometry::{FromGeometry, IntoGeometry, UnitGeometry};
use plexus::index::Flat;
use plexus::U3;
use rand::distributions::{Distribution, Standard};
use rand::{self, Rng};
use std::f32::consts::FRAC_PI_4;
use std::hash::{Hash, Hasher};
use std::mem;
use theon::adjunct::Extend;
use wgpu::util::{BufferInitDescriptor, DeviceExt};
use wgpu::{
    include_spirv, BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor,
    BindGroupLayoutEntry, BindingType, BlendDescriptor, Buffer, BufferAddress, BufferSize,
    BufferUsage, Color, ColorStateDescriptor, ColorWrite, CommandEncoderDescriptor,
    CompareFunction, CullMode, DepthStencilStateDescriptor, Extent3d, FrontFace, IndexFormat,
    InputStepMode, LoadOp, Operations, PipelineLayoutDescriptor, PrimitiveTopology,
    ProgrammableStageDescriptor, RasterizationStateDescriptor, RenderPassColorAttachmentDescriptor,
    RenderPassDepthStencilAttachmentDescriptor, RenderPassDescriptor, RenderPipeline,
    RenderPipelineDescriptor, ShaderStage, SwapChainTexture, TextureDescriptor, TextureDimension,
    TextureFormat, TextureUsage, TextureView, VertexAttributeDescriptor, VertexBufferDescriptor,
    VertexFormat, VertexStateDescriptor,
};
use winit::event::{ElementState, KeyboardInput, VirtualKeyCode, WindowEvent};
use winit::window::WindowBuilder;

use crate::camera::{Camera, Projection};
use crate::harness::{self, Application, ConfigureStage, Reaction, RenderStage};

use Reaction::Abort;
use Reaction::Continue;

#[derive(Clone, Copy, Debug)]
pub struct Color4<T>(pub Vector4<T>)
where
    T: Scalar;

impl<T> Color4<T>
where
    T: Scalar,
{
    pub fn white() -> Self
    where
        T: One,
    {
        Color4(Vector4::repeat(One::one()))
    }

    pub fn random() -> Self
    where
        T: One,
        Standard: Distribution<T>,
        Vector3<T>: Extend<Vector4<T>, Item = T>,
    {
        let mut rng = rand::thread_rng();
        Color4(Vector3::from_fn(|_, _| rng.gen()).extend(One::one()))
    }
}

impl<T> AsRef<Vector4<T>> for Color4<T>
where
    T: Scalar,
{
    fn as_ref(&self) -> &Vector4<T> {
        &self.0
    }
}

impl<T> Default for Color4<T>
where
    T: One + Scalar,
{
    fn default() -> Self {
        Color4::white()
    }
}

impl<T> From<Vector4<T>> for Color4<T>
where
    T: Scalar,
{
    fn from(vector: Vector4<T>) -> Self {
        Color4(vector)
    }
}

impl<T> Into<Vector4<T>> for Color4<T>
where
    T: Scalar,
{
    fn into(self) -> Vector4<T> {
        self.0
    }
}

impl<T> UnitGeometry for Color4<T> where T: One + Scalar {}

#[derive(Clone, Copy)]
#[repr(C)]
pub struct Vertex {
    pub position: [f32; 4],
    pub normal: [f32; 4],
    pub color: [f32; 4],
}

impl Eq for Vertex {}

impl Hash for Vertex {
    fn hash<H>(&self, state: &mut H)
    where
        H: Hasher,
    {
        self.position.float_hash(state);
        self.normal.float_hash(state);
        self.color.float_hash(state);
    }
}

impl PartialEq for Vertex {
    fn eq(&self, other: &Self) -> bool {
        and!(
            self.position.float_eq(&other.position),
            self.normal.float_eq(&other.normal),
            self.color.float_eq(&other.color),
        )
    }
}

unsafe impl Pod for Vertex {}

unsafe impl Zeroable for Vertex {}

struct RenderState {
    camera: Camera,
    from: Point3<f32>,
    buffer: MeshBuffer<Flat<U3, u32>, Vertex>,
}

struct RenderApplication {
    camera: Camera,
    _viewpoint: Buffer,
    transform: Buffer,
    vertices: Buffer,
    indices: Buffer,
    depth: TextureView,
    n: u32,
    bind_group: BindGroup,
    pipeline: RenderPipeline,
}

impl RenderApplication {
    fn configure_depth_buffer(stage: &impl ConfigureStage) -> TextureView {
        stage
            .device()
            .create_texture(&TextureDescriptor {
                label: None,
                size: Extent3d {
                    width: stage.swap_chain_descriptor().width,
                    height: stage.swap_chain_descriptor().height,
                    depth: 1,
                },
                mip_level_count: 1,
                sample_count: 1,
                dimension: TextureDimension::D2,
                format: TextureFormat::Depth32Float,
                usage: TextureUsage::COPY_DST | TextureUsage::OUTPUT_ATTACHMENT,
            })
            .create_view(&Default::default())
    }
}

impl Application for RenderApplication {
    type State = RenderState;
    type Error = ();

    fn configure(state: Self::State, stage: &impl ConfigureStage) -> Result<Self, Self::Error> {
        let RenderState {
            mut camera,
            from,
            buffer,
        } = state;
        camera.reproject(stage.swap_chain_descriptor());
        let vertices = stage.device().create_buffer_init(&BufferInitDescriptor {
            label: None,
            contents: bytemuck::cast_slice(buffer.as_vertex_slice()),
            usage: BufferUsage::VERTEX,
        });
        let indices = stage.device().create_buffer_init(&BufferInitDescriptor {
            label: None,
            contents: bytemuck::cast_slice(buffer.as_index_slice()),
            usage: BufferUsage::INDEX,
        });
        let transform = stage.device().create_buffer_init(&BufferInitDescriptor {
            label: None,
            contents: bytemuck::cast_slice(camera.transform().as_slice()),
            usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
        });
        let viewpoint = stage.device().create_buffer_init(&BufferInitDescriptor {
            label: None,
            contents: bytemuck::cast_slice(from.coords.as_slice()),
            usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
        });
        let depth = Self::configure_depth_buffer(stage);
        let bind_group_layout =
            stage
                .device()
                .create_bind_group_layout(&BindGroupLayoutDescriptor {
                    label: None,
                    entries: &[
                        BindGroupLayoutEntry {
                            binding: 0,
                            visibility: ShaderStage::VERTEX,
                            ty: BindingType::UniformBuffer {
                                dynamic: false,
                                min_binding_size: BufferSize::new(64),
                            },
                            count: None,
                        },
                        BindGroupLayoutEntry {
                            binding: 1,
                            visibility: ShaderStage::VERTEX,
                            ty: BindingType::UniformBuffer {
                                dynamic: false,
                                min_binding_size: BufferSize::new(12),
                            },
                            count: None,
                        },
                    ],
                });
        let bind_group = stage.device().create_bind_group(&BindGroupDescriptor {
            label: None,
            layout: &bind_group_layout,
            entries: &[
                BindGroupEntry {
                    binding: 0,
                    resource: transform.as_entire_binding(),
                },
                BindGroupEntry {
                    binding: 1,
                    resource: viewpoint.as_entire_binding(),
                },
            ],
        });
        let pipeline =
            stage
                .device()
                .create_render_pipeline(&RenderPipelineDescriptor {
                    label: None,
                    layout: Some(&stage.device().create_pipeline_layout(
                        &PipelineLayoutDescriptor {
                            label: None,
                            bind_group_layouts: &[&bind_group_layout],
                            push_constant_ranges: &[],
                        },
                    )),
                    vertex_stage: ProgrammableStageDescriptor {
                        module: &stage
                            .device()
                            .create_shader_module(include_spirv!("shader.spv.vert")),
                        entry_point: "main",
                    },
                    fragment_stage: Some(ProgrammableStageDescriptor {
                        module: &stage
                            .device()
                            .create_shader_module(include_spirv!("shader.spv.frag")),
                        entry_point: "main",
                    }),
                    vertex_state: VertexStateDescriptor {
                        index_format: IndexFormat::Uint32,
                        vertex_buffers: &[VertexBufferDescriptor {
                            stride: mem::size_of::<Vertex>() as BufferAddress,
                            step_mode: InputStepMode::Vertex,
                            attributes: &[
                                #[allow(clippy::erasing_op)]
                                VertexAttributeDescriptor {
                                    format: VertexFormat::Float4,
                                    offset: 0 * 4 * 4,
                                    shader_location: 0,
                                },
                                #[allow(clippy::identity_op)]
                                VertexAttributeDescriptor {
                                    format: VertexFormat::Float4,
                                    offset: 1 * 4 * 4,
                                    shader_location: 1,
                                },
                                VertexAttributeDescriptor {
                                    format: VertexFormat::Float4,
                                    offset: 2 * 4 * 4,
                                    shader_location: 2,
                                },
                            ],
                        }],
                    },
                    primitive_topology: PrimitiveTopology::TriangleList,
                    rasterization_state: Some(RasterizationStateDescriptor {
                        front_face: FrontFace::Ccw,
                        cull_mode: CullMode::Back,
                        ..Default::default()
                    }),
                    color_states: &[ColorStateDescriptor {
                        format: stage.swap_chain_descriptor().format,
                        color_blend: BlendDescriptor::REPLACE,
                        alpha_blend: BlendDescriptor::REPLACE,
                        write_mask: ColorWrite::ALL,
                    }],
                    depth_stencil_state: Some(DepthStencilStateDescriptor {
                        format: TextureFormat::Depth32Float,
                        depth_write_enabled: true,
                        depth_compare: CompareFunction::Less,
                        stencil: Default::default(),
                    }),
                    alpha_to_coverage_enabled: false,
                    sample_count: 1,
                    sample_mask: !0,
                });
        Ok(RenderApplication {
            camera,
            _viewpoint: viewpoint,
            transform,
            vertices,
            indices,
            depth,
            n: buffer.as_index_slice().len() as u32,
            bind_group,
            pipeline,
        })
    }

    fn react(&mut self, event: WindowEvent) -> Reaction {
        match event {
            WindowEvent::KeyboardInput { input, .. } => match input {
                KeyboardInput {
                    virtual_keycode: Some(VirtualKeyCode::Escape),
                    state: ElementState::Pressed,
                    ..
                } => Abort,
                _ => Continue,
            },
            _ => Continue,
        }
    }

    fn resize(&mut self, stage: &impl ConfigureStage) {
        self.camera.reproject(stage.swap_chain_descriptor());
        stage.queue().write_buffer(
            &self.transform,
            0,
            bytemuck::cast_slice(self.camera.transform().as_slice()),
        );
        self.depth = Self::configure_depth_buffer(stage);
    }

    fn render(&mut self, stage: &impl RenderStage, frame: &SwapChainTexture, _: &impl LocalSpawn) {
        let mut encoder = stage
            .device()
            .create_command_encoder(&CommandEncoderDescriptor { label: None });
        let mut pass = encoder.begin_render_pass(&RenderPassDescriptor {
            color_attachments: &[RenderPassColorAttachmentDescriptor {
                attachment: &frame.view,
                resolve_target: None,
                ops: Operations {
                    load: LoadOp::Clear(Color {
                        r: 0.1,
                        g: 0.2,
                        b: 0.3,
                        a: 1.0,
                    }),
                    store: true,
                },
            }],
            depth_stencil_attachment: Some(RenderPassDepthStencilAttachmentDescriptor {
                attachment: &self.depth,
                depth_ops: Some(Operations {
                    load: LoadOp::Clear(1.0),
                    store: true,
                }),
                stencil_ops: None,
            }),
        });
        pass.set_pipeline(&self.pipeline);
        pass.set_bind_group(0, &self.bind_group, &[]);
        pass.set_index_buffer(self.indices.slice(..));
        pass.set_vertex_buffer(0, self.vertices.slice(..));
        pass.draw_indexed(0..self.n, 0, 0..1);
        drop(pass); // Release `encoder`.
        stage.queue().submit(Some(encoder.finish()));
    }
}

pub fn render_mesh_buffer_with<M, G, F>(from: Point3<f32>, to: Point3<f32>, f: F)
where
    M: IntoFlatIndex<U3, G, Item = u32>,
    Vertex: FromGeometry<G>,
    F: FnOnce() -> M,
{
    let camera = {
        let mut camera = Camera::from(Projection::perspective(1.0, FRAC_PI_4, 0.1, 8.0));
        //let mut camera = Camera::from(Projection::orthographic(-4.0, 4.0, -4.0, 4.0, -8.0, 8.0));
        camera.look_at(&from, &to);
        camera
    };
    let buffer = f()
        .into_flat_index()
        .map_vertices(|vertex| vertex.into_geometry());
    harness::run::<RenderApplication, _>(
        RenderState {
            camera,
            from,
            buffer,
        },
        |reactor| {
            WindowBuilder::default()
                .with_title("Plexus")
                .build(reactor)
                .unwrap()
        },
    );
}
<|endoftext|>


<commit_before>extern crate image;
extern crate rand;

use image::ColorType;
use rand::distributions::{IndependentSample, Range};
use std::cmp::{min, max};
use std::env;
use std::path::Path;
use std::process;

fn help() {
    println!("Usage: brownian_tree <output_path> <mote_count> <edge_length>");
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut output_path = Path::new("out.png");
    let mut mote_count: u32 = 10000;
    let mut width: usize = 512;
    let mut height: usize = 512;

    match args.len() {
        1 => {}
        4 => {
            output_path = Path::new(&args[1]);
            mote_count = args[2].parse::<u32>().unwrap();
            width = args[3].parse::<usize>().unwrap();
            height = width;
        }
        _ => {
            help();
            process::exit(0);
        }
    }

    assert!(width >= 2);

    // Base 1d array
    let mut field_raw = vec![0u8; width * height];
    populate_tree(&mut field_raw, width, height, mote_count);

    // Balance image for 8-bit grayscale
    let our_max = field_raw.iter().fold(0u8, |champ, e| max(champ, *e));
    let fudge = std::u8::MAX / our_max;
    let balanced: Vec<u8> = field_raw.iter().map(|e| e * fudge).collect();

    match image::save_buffer(output_path,
                             &balanced,
                             width as u32,
                             height as u32,
                             ColorType::Gray(8)) {
        Err(e) => println!("Error writing output image:\n{}", e),
        Ok(_) => println!("Output written to:\n{}", output_path.to_str().unwrap()),
    }
}

fn populate_tree(raw: &mut Vec<u8>, width: usize, height: usize, mc: u32) {
    // Vector of 'width' elements slices
    let mut field_base: Vec<_> = raw.as_mut_slice().chunks_mut(width).collect();
    // Addressable 2d vector
    let mut field: &mut [&mut [u8]] = field_base.as_mut_slice();

    // Seed mote
    field[width / 2][height / 2] = 1;

    let walk_range = Range::new(-1i32, 2i32);
    let x_spawn_range = Range::new(1usize, width - 1);
    let y_spawn_range = Range::new(1usize, height - 1);
    let mut rng = rand::thread_rng();

    for i in 0..mc {
        if i % 100 == 0 {
            println!("{}", i)
        }

        // Spawn mote
        let mut x = x_spawn_range.ind_sample(&mut rng);
        let mut y = y_spawn_range.ind_sample(&mut rng);

        // Increment field value when motes spawn on top of the structure
        if field[x][y] > 0 {
            field[x][y] = min(field[x][y] as u32 + 1, std::u8::MAX as u32) as u8;
            continue;
        }

        loop {
            let contacts = field[x - 1][y - 1] + field[x][y - 1] + field[x + 1][y - 1] +
                           field[x - 1][y] + field[x + 1][y] +
                           field[x - 1][y + 1] + field[x][y + 1] +
                           field[x + 1][y + 1];

            if contacts > 0 {
                field[x][y] = min(field[x][y] as u32 + 1, std::u8::MAX as u32) as u8;
                break;
            } else {
                let xw = walk_range.ind_sample(&mut rng) + x as i32;
                let yw = walk_range.ind_sample(&mut rng) + y as i32;
                if xw < 1 || xw >= (width as i32 - 1) || yw < 1 || yw >= (height as i32 - 1) {
                    // println!("wandered off");
                    break;
                }
                x = xw as usize;
                y = yw as usize;
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::populate_tree;
    use std::cmp::max;

    #[test]
    fn test_brownian_tree() {
        let width = 128;
        let height = 128;
        let mote_count = 1000;
        let mut field_raw = vec![0u8; width * height];
        populate_tree(&mut field_raw, width, height, mote_count);
        let our_max = field_raw.iter().fold(0u8, |champ, e| max(champ, *e));
        assert!(our_max >= 1);
    }
}
<commit_msg>remove unused `mut`<commit_after>extern crate image;
extern crate rand;

use image::ColorType;
use rand::distributions::{IndependentSample, Range};
use std::cmp::{min, max};
use std::env;
use std::path::Path;
use std::process;

fn help() {
    println!("Usage: brownian_tree <output_path> <mote_count> <edge_length>");
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut output_path = Path::new("out.png");
    let mut mote_count: u32 = 10000;
    let mut width: usize = 512;
    let mut height: usize = 512;

    match args.len() {
        1 => {}
        4 => {
            output_path = Path::new(&args[1]);
            mote_count = args[2].parse::<u32>().unwrap();
            width = args[3].parse::<usize>().unwrap();
            height = width;
        }
        _ => {
            help();
            process::exit(0);
        }
    }

    assert!(width >= 2);

    // Base 1d array
    let mut field_raw = vec![0u8; width * height];
    populate_tree(&mut field_raw, width, height, mote_count);

    // Balance image for 8-bit grayscale
    let our_max = field_raw.iter().fold(0u8, |champ, e| max(champ, *e));
    let fudge = std::u8::MAX / our_max;
    let balanced: Vec<u8> = field_raw.iter().map(|e| e * fudge).collect();

    match image::save_buffer(output_path,
                             &balanced,
                             width as u32,
                             height as u32,
                             ColorType::Gray(8)) {
        Err(e) => println!("Error writing output image:\n{}", e),
        Ok(_) => println!("Output written to:\n{}", output_path.to_str().unwrap()),
    }
}

fn populate_tree(raw: &mut Vec<u8>, width: usize, height: usize, mc: u32) {
    // Vector of 'width' elements slices
    let mut field_base: Vec<_> = raw.as_mut_slice().chunks_mut(width).collect();
    // Addressable 2d vector
    let field = field_base.as_mut_slice();

    // Seed mote
    field[width / 2][height / 2] = 1;

    let walk_range = Range::new(-1i32, 2i32);
    let x_spawn_range = Range::new(1usize, width - 1);
    let y_spawn_range = Range::new(1usize, height - 1);
    let mut rng = rand::thread_rng();

    for i in 0..mc {
        if i % 100 == 0 {
            println!("{}", i)
        }

        // Spawn mote
        let mut x = x_spawn_range.ind_sample(&mut rng);
        let mut y = y_spawn_range.ind_sample(&mut rng);

        // Increment field value when motes spawn on top of the structure
        if field[x][y] > 0 {
            field[x][y] = min(field[x][y] as u32 + 1, std::u8::MAX as u32) as u8;
            continue;
        }

        loop {
            let contacts = field[x - 1][y - 1] + field[x][y - 1] + field[x + 1][y - 1] +
                           field[x - 1][y] + field[x + 1][y] +
                           field[x - 1][y + 1] + field[x][y + 1] +
                           field[x + 1][y + 1];

            if contacts > 0 {
                field[x][y] = min(field[x][y] as u32 + 1, std::u8::MAX as u32) as u8;
                break;
            } else {
                let xw = walk_range.ind_sample(&mut rng) + x as i32;
                let yw = walk_range.ind_sample(&mut rng) + y as i32;
                if xw < 1 || xw >= (width as i32 - 1) || yw < 1 || yw >= (height as i32 - 1) {
                    // println!("wandered off");
                    break;
                }
                x = xw as usize;
                y = yw as usize;
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::populate_tree;
    use std::cmp::max;

    #[test]
    fn test_brownian_tree() {
        let width = 128;
        let height = 128;
        let mote_count = 1000;
        let mut field_raw = vec![0u8; width * height];
        populate_tree(&mut field_raw, width, height, mote_count);
        let our_max = field_raw.iter().fold(0u8, |champ, e| max(champ, *e));
        assert!(our_max >= 1);
    }
}
<|endoftext|>