<commit_before>use std::env;
use std::fs;
use std::fs::File;
use std::io::{BufWriter, Write};
use std::os::unix::fs::symlink;
use std::path::Path;
use std::path::PathBuf;

fn main() {
    generate_srgb_tables();
    generate_convenience_lib().unwrap();
}

/// Converts an sRGB color value to a linear sRGB color value (undoes the gamma correction).
///
/// The input and the output are supposed to be in the [0, 1] range.
#[inline]
fn linearize(c: f64) -> f64 {
    if c <= (12.92 * 0.0031308) {
        c / 12.92
    } else {
        ((c + 0.055) / 1.055).powf(2.4)
    }
}

/// Converts a linear sRGB color value to a normal sRGB color value (applies the gamma correction).
///
/// The input and the output are supposed to be in the [0, 1] range.
#[inline]
fn unlinearize(c: f64) -> f64 {
    if c <= 0.0031308 {
        12.92 * c
    } else {
        1.055 * c.powf(1f64 / 2.4) - 0.055
    }
}

fn compute_table<F: Fn(f64) -> f64>(f: F) -> [u8; 256] {
    let mut table = [0; 256];

    for i in 0..=255 {
        let c = i as f64 / 255.0;
        let x = f(c);
        table[i] = (x * 255.0).round() as u8;
    }

    table
}

fn print_table<W: Write>(w: &mut W, name: &str, table: &[u8]) {
    writeln!(w, "const {}: [u8; {}] = [", name, table.len()).unwrap();

    for x in table {
        writeln!(w, "    {},", x).unwrap();
    }

    writeln!(w, "];").unwrap();
}

fn generate_srgb_tables() {
    let linearize_table = compute_table(linearize);
    let unlinearize_table = compute_table(unlinearize);

    let path = Path::new(&env::var("OUT_DIR").unwrap()).join("srgb-codegen.rs");
    let mut file = BufWriter::new(File::create(&path).unwrap());

    print_table(&mut file, "LINEARIZE", &linearize_table);
    print_table(&mut file, "UNLINEARIZE", &unlinearize_table);
}

/// Generate libtool archive file librsvg_internals.la
/// From: https://docs.rs/libtool/0.1.1/libtool/
pub fn generate_convenience_lib() -> std::io::Result<()> {
    let target = env::var("TARGET").expect("TARGET was not set");
    let build_dir = env::var("LIBRSVG_BUILD_DIR").expect("LIBRSVG_BUILD_DIR was not set");
    let target_dir = env::var("LIBRSVG_TARGET_DIR").expect("LIBRSVG_TARGET_DIR was not set");
    let libs_dir = format!("{}/.libs", build_dir);
    let libs_path = PathBuf::from(&libs_dir);
    let la_path = PathBuf::from(format!("{}/librsvg_internals.la", build_dir));
    let rust_lib = if target.contains("windows") {
        /* https://github.com/rust-lang/rust/issues/43749 */
        "rsvg_internals.lib"
    } else {
        "librsvg_internals.a"
    };
    let old_lib_path = PathBuf::from(format!("{}/{}", target_dir, rust_lib));
    let new_lib_path = PathBuf::from(format!("{}/librsvg_internals.a", libs_dir));

    match fs::create_dir_all(&libs_path) {
        Ok(()) => println!("libs_path created"),
        _ => panic!("Failed to create libs_path"),
    }

    if la_path.exists() {
        fs::remove_file(&la_path)?;
    }

    /* PathBuf.exists() traverses symlinks so just try and remove it */
    match fs::remove_file(&new_lib_path) {
        Ok(_v) => {},
        Err(e) => println!("Error removing symlink: {:?}", e),
    }

    let mut file = File::create(&la_path).unwrap();
    writeln!(file, "# librsvg_internals.la - a libtool library file")?;
    writeln!(file, "# Generated by libtool-rust")?;
    writeln!(file, "dlname=''")?;
    writeln!(file, "library_names=''")?;
    writeln!(file, "old_library='librsvg_internals.a'")?;
    writeln!(file, "inherited_linker_flags=''")?;
    writeln!(file, "installed=no")?;
    writeln!(file, "shouldnotlink=no")?;
    symlink(&old_lib_path, &new_lib_path)?;
    Ok(())
}
<commit_msg>rsvg_internals/build.rs: Fix native, non-cross Windows builds<commit_after>use std::env;
use std::fs::File;
use std::io::{BufWriter, Write};
use std::path::Path;

#[cfg(unix)]
use std::os::unix::fs::symlink;

#[cfg(all(windows, not(target_env = "msvc")))]
use std::os::windows::fs::symlink_file;

#[cfg(not(target_env = "msvc"))]
use std::fs;
#[cfg(not(target_env = "msvc"))]
use std::path::PathBuf;

fn main() {
    generate_srgb_tables();

    #[cfg(not (target_env = "msvc"))]
    generate_convenience_lib().unwrap();
}

/// Converts an sRGB color value to a linear sRGB color value (undoes the gamma correction).
///
/// The input and the output are supposed to be in the [0, 1] range.
#[inline]
fn linearize(c: f64) -> f64 {
    if c <= (12.92 * 0.0031308) {
        c / 12.92
    } else {
        ((c + 0.055) / 1.055).powf(2.4)
    }
}

/// Converts a linear sRGB color value to a normal sRGB color value (applies the gamma correction).
///
/// The input and the output are supposed to be in the [0, 1] range.
#[inline]
fn unlinearize(c: f64) -> f64 {
    if c <= 0.0031308 {
        12.92 * c
    } else {
        1.055 * c.powf(1f64 / 2.4) - 0.055
    }
}

fn compute_table<F: Fn(f64) -> f64>(f: F) -> [u8; 256] {
    let mut table = [0; 256];

    for i in 0..=255 {
        let c = i as f64 / 255.0;
        let x = f(c);
        table[i] = (x * 255.0).round() as u8;
    }

    table
}

fn print_table<W: Write>(w: &mut W, name: &str, table: &[u8]) {
    writeln!(w, "const {}: [u8; {}] = [", name, table.len()).unwrap();

    for x in table {
        writeln!(w, "    {},", x).unwrap();
    }

    writeln!(w, "];").unwrap();
}

fn generate_srgb_tables() {
    let linearize_table = compute_table(linearize);
    let unlinearize_table = compute_table(unlinearize);

    let path = Path::new(&env::var("OUT_DIR").unwrap()).join("srgb-codegen.rs");
    let mut file = BufWriter::new(File::create(&path).unwrap());

    print_table(&mut file, "LINEARIZE", &linearize_table);
    print_table(&mut file, "UNLINEARIZE", &unlinearize_table);
}

/// Generate libtool archive file librsvg_internals.la
/// From: https://docs.rs/libtool/0.1.1/libtool/
#[cfg(not (target_env = "msvc"))]
pub fn generate_convenience_lib() -> std::io::Result<()> {
    let target = env::var("TARGET").expect("TARGET was not set");
    let build_dir = env::var("LIBRSVG_BUILD_DIR").expect("LIBRSVG_BUILD_DIR was not set");
    let target_dir = env::var("LIBRSVG_TARGET_DIR").expect("LIBRSVG_TARGET_DIR was not set");
    let libs_dir = format!("{}/.libs", build_dir);
    let libs_path = PathBuf::from(&libs_dir);
    let la_path = PathBuf::from(format!("{}/librsvg_internals.la", build_dir));
    let rust_lib = if target.contains("windows") {
        /* https://github.com/rust-lang/rust/issues/43749 */
        "rsvg_internals.lib"
    } else {
        "librsvg_internals.a"
    };
    let old_lib_path = PathBuf::from(format!("{}/{}", target_dir, rust_lib));
    let new_lib_path = PathBuf::from(format!("{}/librsvg_internals.a", libs_dir));

    match fs::create_dir_all(&libs_path) {
        Ok(()) => println!("libs_path created"),
        _ => panic!("Failed to create libs_path"),
    }

    if la_path.exists() {
        fs::remove_file(&la_path)?;
    }

    /* PathBuf.exists() traverses symlinks so just try and remove it */
    match fs::remove_file(&new_lib_path) {
        Ok(_v) => {},
        Err(e) => println!("Error removing symlink: {:?}", e),
    }

    let mut file = File::create(&la_path).unwrap();
    writeln!(file, "# librsvg_internals.la - a libtool library file")?;
    writeln!(file, "# Generated by libtool-rust")?;
    writeln!(file, "dlname=''")?;
    writeln!(file, "library_names=''")?;
    writeln!(file, "old_library='librsvg_internals.a'")?;
    writeln!(file, "inherited_linker_flags=''")?;
    writeln!(file, "installed=no")?;
    writeln!(file, "shouldnotlink=no")?;
    symlink(&old_lib_path, &new_lib_path)?;
    Ok(())
}
<|endoftext|>


<commit_before>#![feature(globs)]
#![feature(quote)]

extern crate syntax;

use std::str;
use std::io::{stdin,stdout,stderr};
use std::io::fs::File;
use std::os;
use translate::{compile_grammar};

mod translate;
mod grammar;
mod rustast;
mod fake_extctxt;

fn print_usage(prog: &str) {
	println!("Usage: {} [file]", prog)
}

fn main() {
	let args = os::args();

	let source_utf8 = match args.as_slice() {
		[ref progname, ref arg] if arg.as_slice() == "-h" => return print_usage(progname.as_slice()),
		[_, ref fname] => File::open(&Path::new(fname.as_slice())).read_to_end().unwrap(),
		[_] => stdin().read_to_end().unwrap(),
		[ref progname, ..] => return print_usage(progname.as_slice()),
		_ => panic!("No program name argument")
	};

	let source = str::from_utf8(source_utf8.as_slice()).unwrap();
	let grammar_def = grammar::grammar(source);

	match grammar_def {
		Ok(grammar) => {
			fake_extctxt::with_fake_extctxt(|e| {

				let ast = compile_grammar(e, &grammar);
				let mut out = stdout();

				out.write_line("// Generated by rust-peg. Do not edit.").unwrap();
				out.write_line("#![allow(non_snake_case, unused)]").unwrap();

				for item in ast.view_items.iter() {
					out.write_line(rustast::view_item_to_string(item).as_slice()).unwrap();
				}

				for item in ast.items.iter() {
					out.write_line(rustast::item_to_string(&**item).as_slice()).unwrap();
				}
			})
		}

		Err(msg) => {
			(writeln!(&mut stderr() as &mut Writer, "Error parsing language specification: {}", msg)).unwrap();
			os::set_exit_status(1);
		}
	}
}
<commit_msg>rust: Fix borrowck error<commit_after>#![feature(globs)]
#![feature(quote)]

extern crate syntax;

use std::str;
use std::io::{stdin,stdout,stderr};
use std::io::fs::File;
use std::os;
use translate::{compile_grammar};

mod translate;
mod grammar;
mod rustast;
mod fake_extctxt;

fn print_usage(prog: &str) {
	println!("Usage: {} [file]", prog)
}

fn main() {
	let args = os::args();

	let source_utf8 = match args.as_slice() {
		[ref progname, ref arg] if arg.as_slice() == "-h" => return print_usage(progname.as_slice()),
		[_, ref fname] => File::open(&Path::new(fname.as_slice())).read_to_end().unwrap(),
		[_] => stdin().read_to_end().unwrap(),
		[ref progname, ..] => return print_usage(progname.as_slice()),
		_ => panic!("No program name argument")
	};

	let source = str::from_utf8(source_utf8.as_slice()).unwrap();
	let grammar_def = grammar::grammar(source);

	match grammar_def {
		Ok(grammar) => {
			fake_extctxt::with_fake_extctxt(|e| {

				let ast = compile_grammar(e, &grammar);
				let mut out = stdout();

				out.write_line("// Generated by rust-peg. Do not edit.").unwrap();
				out.write_line("#![allow(non_snake_case, unused)]").unwrap();

				for item in ast.view_items.iter() {
					out.write_line(rustast::view_item_to_string(item).as_slice()).unwrap();
				}

				for item in ast.items.iter() {
					out.write_line(rustast::item_to_string(&**item).as_slice()).unwrap();
				}
			})
		}

		Err(msg) => {
			let mut e = stderr();
			(writeln!(&mut e, "Error parsing language specification: {}", msg)).unwrap();
			os::set_exit_status(1);
		}
	}
}
<|endoftext|>


<commit_before>//! Compile time optimized maps
#[crate_id="github.com/sfackler/rust-phf/phf"];
#[doc(html_root_url="http://www.rust-ci.org/sfackler/rust-phf/doc")];
#[crate_type="rlib"];
#[crate_type="dylib"];
#[warn(missing_doc)];

use std::iter;
use std::slice;
use std::hash::Hasher;
use std::hash::sip::SipHasher;

/// An immutable map constructed at compile time.
///
/// `PhfMap`s may be created with the `phf_map` macro:
///
/// ```rust
/// # #[feature(phase)];
/// extern crate phf;
/// #[phase(syntax)]
/// extern crate phf_mac;
///
/// use phf::PhfMap;
///
/// static my_map: PhfMap<int> = phf_map!(
///    "hello" => 10,
///    "world" => 11,
/// );
///
/// # fn main() {}
/// ```
///
/// # Note
///
/// The fields of this struct are public so that they may be initialized by the
/// `phf_map` macro. They are subject to change at any time and should never
/// be accessed directly.
pub struct PhfMap<T> {
    #[doc(hidden)]
    len: uint,
    #[doc(hidden)]
    k1: u64,
    #[doc(hidden)]
    k2: u64,
    #[doc(hidden)]
    disps: &'static [(uint, uint)],
    #[doc(hidden)]
    entries: &'static [Option<(&'static str, T)>],
}

static LOG_MAX_SIZE: uint = 21;

#[doc(hidden)]
pub static MAX_SIZE: uint = 1 << LOG_MAX_SIZE;

#[doc(hidden)]
#[inline]
pub fn hash(s: &str, k1: u64, k2: u64) -> (uint, uint, uint) {
    let hash = SipHasher::new_with_keys(k1, k2).hash(&s);
    let mask = (MAX_SIZE - 1) as u64;

    ((hash & mask) as uint,
     ((hash >> LOG_MAX_SIZE) & mask) as uint,
     ((hash >> (2 * LOG_MAX_SIZE)) & mask) as uint)
}

#[doc(hidden)]
#[inline]
pub fn displace(f1: uint, f2: uint, d1: uint, d2: uint) -> uint {
    d2 + f1 * d1 + f2
}

impl<T> Container for PhfMap<T> {
    fn len(&self) -> uint {
        self.len
    }
}

impl<'a, T> Map<&'a str, T> for PhfMap<T> {
    fn find<'a>(&'a self, key: & &str) -> Option<&'a T> {
        let (g, f1, f2) = hash(*key, self.k1, self.k2);
        let (d1, d2) = self.disps[g % self.disps.len()];
        match self.entries[displace(f1, f2, d1, d2) % self.entries.len()] {
            Some((s, ref value)) if s == *key => Some(value),
            _ => None
        }
    }
}

impl<T> PhfMap<T> {
    /// Returns an iterator over the key/value pairs in the map.
    ///
    /// Entries are retuned in an arbitrary order.
    #[inline]
    pub fn entries<'a>(&'a self) -> PhfMapEntries<'a, T> {
        PhfMapEntries {
            iter: self.entries.iter().filter_map(|e| {
                match *e {
                    Some((key, ref value)) => Some((key, value)),
                    None => None
                }
            })
        }
    }

    /// Returns an iterator over the keys in the map.
    ///
    /// Keys are returned in an arbitrary order.
    #[inline]
    pub fn keys<'a>(&'a self) -> PhfMapKeys<'a, T> {
        PhfMapKeys { iter: self.entries() }
    }

    /// Returns an iterator over the values in the map.
    ///
    /// Values are returned in an arbitrary order.
    #[inline]
    pub fn values<'a>(&'a self) -> PhfMapValues<'a, T> {
        PhfMapValues { iter: self.entries() }
    }
}

/// An iterator over the key/value pairs in a `PhfMap`.
pub struct PhfMapEntries<'a, T> {
    priv iter: iter::FilterMap<'a,
                               &'a Option<(&'static str, T)>,
                               (&'static str, &'a T),
                               slice::Items<'a, Option<(&'static str, T)>>>,
}

impl<'a, T> Iterator<(&'static str, &'a T)> for PhfMapEntries<'a, T> {
    fn next(&mut self) -> Option<(&'static str, &'a T)> {
        self.iter.next()
    }

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

/// An iterator over the keys in a `PhfMap`.
pub struct PhfMapKeys<'a, T> {
    priv iter: PhfMapEntries<'a, T>,
}

impl<'a, T> Iterator<&'static str> for PhfMapKeys<'a, T> {
    fn next(&mut self) -> Option<&'static str> {
        self.iter.next().map(|(key, _)| key)
    }

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

/// An iterator over the values in a `PhfMap`.
pub struct PhfMapValues<'a, T> {
    priv iter: PhfMapEntries<'a, T>,
}

impl<'a, T> Iterator<&'a T> for PhfMapValues<'a, T> {
    fn next(&mut self) -> Option<&'a T> {
        self.iter.next().map(|(_, value)| value)
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        self.iter.size_hint()
    }
}
<commit_msg>Clean up entries iterator a bit<commit_after>//! Compile time optimized maps
#[crate_id="github.com/sfackler/rust-phf/phf"];
#[doc(html_root_url="http://www.rust-ci.org/sfackler/rust-phf/doc")];
#[crate_type="rlib"];
#[crate_type="dylib"];
#[warn(missing_doc)];

use std::slice;
use std::hash::Hasher;
use std::hash::sip::SipHasher;

/// An immutable map constructed at compile time.
///
/// `PhfMap`s may be created with the `phf_map` macro:
///
/// ```rust
/// # #[feature(phase)];
/// extern crate phf;
/// #[phase(syntax)]
/// extern crate phf_mac;
///
/// use phf::PhfMap;
///
/// static my_map: PhfMap<int> = phf_map!(
///    "hello" => 10,
///    "world" => 11,
/// );
///
/// # fn main() {}
/// ```
///
/// # Note
///
/// The fields of this struct are public so that they may be initialized by the
/// `phf_map` macro. They are subject to change at any time and should never
/// be accessed directly.
pub struct PhfMap<T> {
    #[doc(hidden)]
    len: uint,
    #[doc(hidden)]
    k1: u64,
    #[doc(hidden)]
    k2: u64,
    #[doc(hidden)]
    disps: &'static [(uint, uint)],
    #[doc(hidden)]
    entries: &'static [Option<(&'static str, T)>],
}

static LOG_MAX_SIZE: uint = 21;

#[doc(hidden)]
pub static MAX_SIZE: uint = 1 << LOG_MAX_SIZE;

#[doc(hidden)]
#[inline]
pub fn hash(s: &str, k1: u64, k2: u64) -> (uint, uint, uint) {
    let hash = SipHasher::new_with_keys(k1, k2).hash(&s);
    let mask = (MAX_SIZE - 1) as u64;

    ((hash & mask) as uint,
     ((hash >> LOG_MAX_SIZE) & mask) as uint,
     ((hash >> (2 * LOG_MAX_SIZE)) & mask) as uint)
}

#[doc(hidden)]
#[inline]
pub fn displace(f1: uint, f2: uint, d1: uint, d2: uint) -> uint {
    d2 + f1 * d1 + f2
}

impl<T> Container for PhfMap<T> {
    fn len(&self) -> uint {
        self.len
    }
}

impl<'a, T> Map<&'a str, T> for PhfMap<T> {
    fn find<'a>(&'a self, key: & &str) -> Option<&'a T> {
        let (g, f1, f2) = hash(*key, self.k1, self.k2);
        let (d1, d2) = self.disps[g % self.disps.len()];
        match self.entries[displace(f1, f2, d1, d2) % self.entries.len()] {
            Some((s, ref value)) if s == *key => Some(value),
            _ => None
        }
    }
}

impl<T> PhfMap<T> {
    /// Returns an iterator over the key/value pairs in the map.
    ///
    /// Entries are retuned in an arbitrary order.
    #[inline]
    pub fn entries<'a>(&'a self) -> PhfMapEntries<'a, T> {
        PhfMapEntries {
            iter: self.entries.iter()
        }
    }

    /// Returns an iterator over the keys in the map.
    ///
    /// Keys are returned in an arbitrary order.
    #[inline]
    pub fn keys<'a>(&'a self) -> PhfMapKeys<'a, T> {
        PhfMapKeys { iter: self.entries() }
    }

    /// Returns an iterator over the values in the map.
    ///
    /// Values are returned in an arbitrary order.
    #[inline]
    pub fn values<'a>(&'a self) -> PhfMapValues<'a, T> {
        PhfMapValues { iter: self.entries() }
    }
}

/// An iterator over the key/value pairs in a `PhfMap`.
pub struct PhfMapEntries<'a, T> {
    priv iter: slice::Items<'a, Option<(&'static str, T)>>,
}

impl<'a, T> Iterator<(&'static str, &'a T)> for PhfMapEntries<'a, T> {
    fn next(&mut self) -> Option<(&'static str, &'a T)> {
        self.iter.by_ref().filter_map(|e| {
                match *e {
                    Some((key, ref value)) => Some((key, value)),
                    None => None
                }
            }).next()
    }

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

/// An iterator over the keys in a `PhfMap`.
pub struct PhfMapKeys<'a, T> {
    priv iter: PhfMapEntries<'a, T>,
}

impl<'a, T> Iterator<&'static str> for PhfMapKeys<'a, T> {
    fn next(&mut self) -> Option<&'static str> {
        self.iter.next().map(|(key, _)| key)
    }

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

/// An iterator over the values in a `PhfMap`.
pub struct PhfMapValues<'a, T> {
    priv iter: PhfMapEntries<'a, T>,
}

impl<'a, T> Iterator<&'a T> for PhfMapValues<'a, T> {
    fn next(&mut self) -> Option<&'a T> {
        self.iter.next().map(|(_, value)| value)
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        self.iter.size_hint()
    }
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2011-2017, UDI Contributors
// All rights reserved.
//
// 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/.
//
#![deny(warnings)]

extern crate goblin;

use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
use std::io::Read;
use std::path::PathBuf;
use std::process::Command;

const SIMPLE_BINARY: &'static str =
    "simple-debug-noopt-dynamic.cd52194667df0781720ff834a56df134fef7fb51";

const WAITTHREAD_BINARY: &'static str =
    "waitthread-debug-noopt-dynamic.9bb7ace83d00e653b003e05b15ee7f9944c7f261";

const ZIP_NAME: &'static str = "native-file-tests.zip";

pub fn setup(out_path: &PathBuf, manifest_dir: &PathBuf, url: &str) {

    let dest_path = out_path.join(ZIP_NAME);

    // Only download the zip if it's not present in the manifest directory
    let manifest_zip_path = manifest_dir.join(ZIP_NAME);
    if manifest_zip_path.exists() {
        Command::new("cp").arg(manifest_zip_path.to_str().unwrap())
                          .arg(dest_path.to_str().unwrap())
                          .spawn()
                          .expect("Failed to start copy of native file tests zip")
                          .wait()
                          .expect("Failed to copy of native file tests zip");
    } else {
        Command::new("curl").arg("-sSf")
                            .arg("-o")
                            .arg(dest_path.to_str().unwrap())
                            .arg(url)
                            .spawn()
                            .expect("Failed to start download of native file tests zip")
                            .wait()
                            .expect("Failed to download native file tests zip");
    }

    let dest_dir = out_path.join("native-file-tests");
    Command::new("unzip").arg("-j")
                         .arg(dest_path.to_str().unwrap())
                         .arg("-d")
                         .arg(dest_dir.to_str().unwrap())
                         .spawn()
                         .expect("Failed to start extract of native file tests zip")
                         .wait()
                         .expect("Failed to extract native file tests zip");

    let simple_path = dest_dir.join(SIMPLE_BINARY);
    let waitthread_path = dest_dir.join(WAITTHREAD_BINARY);

    let mod_file_path = out_path.join("native_file_tests.rs");
    let mut mod_file = File::create(&mod_file_path).unwrap();

    let symbols = build_symbols(&dest_dir);

    let sym_defs = symbols.iter()
                          .map(|e| format!("pub const {}: u64 = {};\n", e.0, e.1))
                          .fold("".to_owned(), |acc, elem| acc + &elem);

    let mod_file_content = format!("
pub const SIMPLE_EXEC_PATH: &'static str = \"{}\";
pub const WAITTHREAD_EXEC_PATH: &'static str = \"{}\";

{}
",
    simple_path.to_str().unwrap(),
    waitthread_path.to_str().unwrap(),
    sym_defs);

    mod_file.write_all(&mod_file_content.into_bytes())
            .expect("Failed to write native file tests module");
}

fn build_symbols(dest_dir: &PathBuf) -> HashMap<&str, String> {
    let mut symbols = HashMap::new();

    add_simple_binary_symbols(dest_dir, &mut symbols);
    add_waitthread_binary_symbols(dest_dir, &mut symbols);

    symbols
}

fn add_simple_binary_symbols(dest_dir: &PathBuf, symbols: &mut HashMap<&str, String>) {
    let path = dest_dir.join(SIMPLE_BINARY);

    for_each_symbols(&path, |name, value, size| {
        if name == "function1" {
            symbols.insert("SIMPLE_FUNCTION1", format!("0x{:x}", value));
        } else if name == "function2" {
            symbols.insert("SIMPLE_FUNCTION2", format!("0x{:x}", value));
            symbols.insert("SIMPLE_FUNCTION2_LENGTH", size.to_string());
        }
    });
}

fn add_waitthread_binary_symbols(dest_dir: &PathBuf, symbols: &mut HashMap<&str, String>) {
    let path = dest_dir.join(WAITTHREAD_BINARY);

    for_each_symbols(&path, |name, value, _| {
        if name == "breakpoint_func" {
            symbols.insert("THREAD_BREAK_FUNC", format!("0x{:x}", value));
        }
    });
}

fn for_each_symbols<F>(path: &PathBuf, mut func: F)
    where F: FnMut(&String, u64, u64) {

    let mut binary_file = File::open(&path).expect(&format!("Symbol file {:?} error",
                                                           path));
    let mut buffer = vec![];
    binary_file.read_to_end(&mut buffer).unwrap();

    match goblin::parse(&buffer).unwrap() {
        goblin::Object::Elf(elf) => {
            let strtab = &(elf.strtab);
            for sym in &(elf.syms) {
                func(&(strtab.get(sym.st_name).unwrap().to_owned()),
                     sym.st_value,
                     sym.st_size);
            }
        },
        _ => {
            panic!(format!("Unsupported file type"));
        }
    }
}
<commit_msg>rust-binding: take zip path as input instead of downloading<commit_after>//
// Copyright (c) 2011-2017, UDI Contributors
// All rights reserved.
//
// 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/.
//
#![deny(warnings)]

extern crate goblin;

use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
use std::io::Read;
use std::path::PathBuf;
use std::process::Command;

const SIMPLE_BINARY: &'static str =
    "simple-debug-noopt-dynamic.cd52194667df0781720ff834a56df134fef7fb51";

const WAITTHREAD_BINARY: &'static str =
    "waitthread-debug-noopt-dynamic.9bb7ace83d00e653b003e05b15ee7f9944c7f261";

pub fn setup(out_path: &PathBuf, zip_path: &PathBuf) {

    let dest_dir = out_path.join("native-file-tests");
    Command::new("unzip").arg("-j")
                         .arg(zip_path.to_str().unwrap())
                         .arg("-d")
                         .arg(dest_dir.to_str().unwrap())
                         .spawn()
                         .expect("Failed to start extract of native file tests zip")
                         .wait()
                         .expect("Failed to extract native file tests zip");

    let simple_path = dest_dir.join(SIMPLE_BINARY);
    let waitthread_path = dest_dir.join(WAITTHREAD_BINARY);

    let mod_file_path = out_path.join("native_file_tests.rs");
    let mut mod_file = File::create(&mod_file_path).unwrap();

    let symbols = build_symbols(&dest_dir);

    let sym_defs = symbols.iter()
                          .map(|e| format!("pub const {}: u64 = {};\n", e.0, e.1))
                          .fold("".to_owned(), |acc, elem| acc + &elem);

    let mod_file_content = format!("
pub const SIMPLE_EXEC_PATH: &'static str = \"{}\";
pub const WAITTHREAD_EXEC_PATH: &'static str = \"{}\";

{}
",
    simple_path.to_str().unwrap(),
    waitthread_path.to_str().unwrap(),
    sym_defs);

    mod_file.write_all(&mod_file_content.into_bytes())
            .expect("Failed to write native file tests module");
}

fn build_symbols(dest_dir: &PathBuf) -> HashMap<&str, String> {
    let mut symbols = HashMap::new();

    add_simple_binary_symbols(dest_dir, &mut symbols);
    add_waitthread_binary_symbols(dest_dir, &mut symbols);

    symbols
}

fn add_simple_binary_symbols(dest_dir: &PathBuf, symbols: &mut HashMap<&str, String>) {
    let path = dest_dir.join(SIMPLE_BINARY);

    for_each_symbols(&path, |name, value, size| {
        if name == "function1" {
            symbols.insert("SIMPLE_FUNCTION1", format!("0x{:x}", value));
        } else if name == "function2" {
            symbols.insert("SIMPLE_FUNCTION2", format!("0x{:x}", value));
            symbols.insert("SIMPLE_FUNCTION2_LENGTH", size.to_string());
        }
    });
}

fn add_waitthread_binary_symbols(dest_dir: &PathBuf, symbols: &mut HashMap<&str, String>) {
    let path = dest_dir.join(WAITTHREAD_BINARY);

    for_each_symbols(&path, |name, value, _| {
        if name == "breakpoint_func" {
            symbols.insert("THREAD_BREAK_FUNC", format!("0x{:x}", value));
        }
    });
}

fn for_each_symbols<F>(path: &PathBuf, mut func: F)
    where F: FnMut(&String, u64, u64) {

    let mut binary_file = File::open(&path).expect(&format!("Symbol file {:?} error",
                                                           path));
    let mut buffer = vec![];
    binary_file.read_to_end(&mut buffer).unwrap();

    match goblin::parse(&buffer).unwrap() {
        goblin::Object::Elf(elf) => {
            let strtab = &(elf.strtab);
            for sym in &(elf.syms) {
                func(&(strtab.get(sym.st_name).unwrap().to_owned()),
                     sym.st_value,
                     sym.st_size);
            }
        },
        _ => {
            panic!(format!("Unsupported file type"));
        }
    }
}
<|endoftext|>


<commit_before>extern crate git2;

use prompt_buffer;
use prompt_buffer::{PromptLine, PromptBufferPlugin, PromptLineBuilder};
use git2::{Repository, Error, StatusOptions, STATUS_WT_NEW};
use std::{os, fmt};
use term::color;

enum StatusTypes {
    New,
    Modified,
    Deleted,
    Renamed,
    TypeChange,
    Untracked,
    Clean
}

impl fmt::Show for StatusTypes {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            StatusTypes::New => "A",
            StatusTypes::Modified => "M",
            StatusTypes::Deleted => "D",
            StatusTypes::Renamed => "R",
            StatusTypes::TypeChange => "T",
            StatusTypes::Untracked => "?",
            StatusTypes::Clean => " "
        })
    }
}

struct GitStatus {
    index: StatusTypes,
    workdir: StatusTypes
}

impl GitStatus {
    fn new(f: git2::Status) -> GitStatus {
        GitStatus {
            index:
                     if f.contains(git2::STATUS_INDEX_NEW) { StatusTypes::New }
                else if f.contains(git2::STATUS_INDEX_MODIFIED) { StatusTypes::Modified }
                else if f.contains(git2::STATUS_INDEX_DELETED) { StatusTypes::Deleted }
                else if f.contains(git2::STATUS_INDEX_RENAMED) { StatusTypes::Renamed }
                else if f.contains(git2::STATUS_INDEX_TYPECHANGE) { StatusTypes::TypeChange }
                else if f.contains(git2::STATUS_WT_NEW) { StatusTypes::Untracked }
                else { StatusTypes::Clean },
            workdir:
                     if f.contains(git2::STATUS_WT_NEW) { StatusTypes::Untracked }
                else if f.contains(git2::STATUS_WT_MODIFIED) { StatusTypes::Modified }
                else if f.contains(git2::STATUS_WT_DELETED) { StatusTypes::Deleted }
                else if f.contains(git2::STATUS_WT_RENAMED) { StatusTypes::Renamed }
                else if f.contains(git2::STATUS_WT_TYPECHANGE) { StatusTypes::TypeChange }
                else { StatusTypes::Clean },
        }
    }
}

impl fmt::Show for GitStatus {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}{}", self.index, self.workdir)
    }
}

fn get_git(path: &Path) -> Option<Repository> {
    match Repository::discover(path) {
        Ok(repo) => Some(repo),
        _ => None
    }
}

fn status(buffer: &mut Vec<PromptLine>, path: &Path, repo: &Repository) -> bool {
    let st = repo.statuses(Some(StatusOptions::new()
        .include_untracked(true)
        .renames_head_to_index(true)
    ));

    let make_path_relative = |current: Path| {
        let mut fullpath = repo.workdir().unwrap();
        fullpath.push(current);

        fullpath.path_relative_from(path).unwrap()
    };

    match st {
        Ok(statuses) => {
            if statuses.len() <= 0 { return false }

            buffer.push(PromptLineBuilder::new()
                .colored_block(&"Git Status", color::CYAN)
                .build());

            for stat in statuses.iter() {
                let mut line = PromptLineBuilder::new_free();

                let status = GitStatus::new(stat.status());

                let diff = match stat.head_to_index() {
                    Some(delta) => Some(delta),
                    None => match stat.index_to_workdir() {
                        Some(delta) => Some(delta),
                        None => None
                    }
                };

                let val = format!("{} {}", status, match diff {
                    Some(delta) => {
                        let old = make_path_relative(delta.old_file().path().unwrap());
                        let new = make_path_relative(delta.new_file().path().unwrap());

                        if old != new {
                            format!("{} -> {}", old.display(), new.display())
                        } else {
                            format!("{}", old.display())
                        }
                    },
                    None => format!("{}", Path::new(stat.path().unwrap()).display())
                });

                line = match status.index {
                    StatusTypes::Clean => line.colored_block(&val, file_state_color(status.workdir)),
                    _ => match status.workdir {
                        StatusTypes::Clean | StatusTypes::Untracked =>
                            line.bold_colored_block(&val, file_state_color(status.index)),
                        _ => line.bold_colored_block(&val, color::RED)
                    }
                };

                buffer.push(line.indent().build());
            }

            return true
        },
        _ => { return false }
    }

    fn file_state_color(state: StatusTypes) -> u16 {
        match state {
            StatusTypes::Clean | StatusTypes::Untracked => color::WHITE,
            StatusTypes::Deleted => color::RED,
            StatusTypes::Modified => color::BLUE,
            StatusTypes::New => color::GREEN,
            StatusTypes::Renamed => color::CYAN,
            StatusTypes::TypeChange => color::YELLOW,
        }
    }
}

struct BranchInfo {
    name: Option<String>,
    upstream: Option<String>
}

fn git_branch(repo: &Repository) -> Result<BranchInfo, git2::Error> {
    let mut branches = repo.branches(None).ok().expect("Unable to load branches");

    for (mut branch, _) in branches {
        if !branch.is_head() {
            continue;
        }

        let name = branch.name();
        return Ok(BranchInfo {
            name: match name {
                Ok(n) => match n {
                    Some(value) => Some(value.to_string()),
                    _ => None
                },
                _ => None
            },
            upstream: match branch.upstream() {
                Ok(upstream) => {
                    match upstream.name() {
                        Ok(n) => match n {
                            Some(value) => Some(value.to_string()),
                            _ => None
                        },
                        _ => None
                    }
                },
                Err(_) => None
            }
        });
    }

    match repo.head() {
        Ok(r) => match repo.find_object(r.target().unwrap(), None) {
            Ok(obj) => {
                let sid = obj.short_id().ok().unwrap();
                let s = sid.as_str();
                let short_id = s.unwrap();
                Ok(BranchInfo {
                    name: Some(format!("{}", short_id)),
                    upstream: Some("?".to_string())
                })
            },
            Err(e) => Err(e)
        },
        Err(e) => Err(e)
    }
}

fn outgoing(buffer: &mut Vec<PromptLine>, repo: &Repository, has_status: bool) -> bool {
    match do_outgoing(buffer, repo, has_status) {
        Ok(r) => r,
        Err(e) => {
            println!("Error from outgoing: {}", e);
            false
        }
    }
}

fn do_outgoing(buffer: &mut Vec<PromptLine>, repo: &Repository, has_status: bool) -> Result<bool, git2::Error> {
    let branches = try!(git_branch(repo));

    let mut revwalk = try!(repo.revwalk());
    revwalk.set_sorting(git2::SORT_REVERSE);

    let from = try!(repo.revparse_single(branches.upstream.unwrap().as_slice())).id();
    let to = try!(repo.revparse_single(branches.name.unwrap().as_slice())).id();

    try!(revwalk.push(to));
    try!(revwalk.hide(from));

    let mut log_shown = false;

    for id in revwalk {
        let mut commit = try!(repo.find_commit(id));

        if !log_shown {
            buffer.push(PromptLineBuilder::new()
                .colored_block(&"Git Outgoing", color::CYAN)
                .indent_by(if has_status { 1 } else { 0 })
                .build());
            log_shown = true;
        }

        buffer.push(PromptLineBuilder::new_free()
            .indent()
            .colored_block(&format!("{} {}",
                String::from_utf8_lossy(
                    try!(try!(repo.find_object(commit.id(), None)).short_id()).get()
                ),
                String::from_utf8_lossy(match commit.summary_bytes() {
                    Some(b) => b,
                    None => continue
                })), color::WHITE)
            .build());
    }

    return Ok(log_shown);
}

fn end(buffer: &mut Vec<PromptLine>, repo: &Repository, indented: bool) {
    match git_branch(repo) {
        Ok(branches) => {
            buffer.push(PromptLineBuilder::new()
                .colored_block(
                    &match (branches.name, branches.upstream) {
                        (None, None) => "New Repository".to_string(),
                        (Some(name), None) => name,
                        (Some(name), Some(remote)) => format!("{}{} -> {}{}",
                            name,
                            prompt_buffer::reset(),
                            prompt_buffer::col(color::MAGENTA),
                            remote),
                        _ => "Unknown branch state".to_string()
                    }, color::CYAN)
                .indent_by(if indented { 1 } else { 0 })
                .build());
        },
        Err(_) => {}
    };
}

pub struct GitPlugin {
    repo: Option<Repository>,
    path: Path
}

impl GitPlugin {
    pub fn new() -> GitPlugin {
        GitPlugin {
            repo: None,
            path: os::make_absolute(&Path::new(".")).unwrap()
        }
    }
}

impl PromptBufferPlugin for GitPlugin {
    fn run(&mut self, path: &Path, lines: &mut Vec<PromptLine>) {
        if self.path != *path || self.repo.is_none() {
            self.path = path.clone();
            self.repo = get_git(&self.path);
        }

        match self.repo {
            Some(ref r) => {
                let st = status(lines, path, r);
                let out = outgoing(lines, r, st);
                end(lines, r, st || out);
            },
            _ => { }
        }
    }
}
<commit_msg>Stop showing submodule status<commit_after>extern crate git2;

use prompt_buffer;
use prompt_buffer::{PromptLine, PromptBufferPlugin, PromptLineBuilder};
use git2::{Repository, Error, StatusOptions, STATUS_WT_NEW};
use std::{os, fmt};
use term::color;

enum StatusTypes {
    New,
    Modified,
    Deleted,
    Renamed,
    TypeChange,
    Untracked,
    Clean
}

impl fmt::Show for StatusTypes {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            StatusTypes::New => "A",
            StatusTypes::Modified => "M",
            StatusTypes::Deleted => "D",
            StatusTypes::Renamed => "R",
            StatusTypes::TypeChange => "T",
            StatusTypes::Untracked => "?",
            StatusTypes::Clean => " "
        })
    }
}

struct GitStatus {
    index: StatusTypes,
    workdir: StatusTypes
}

impl GitStatus {
    fn new(f: git2::Status) -> GitStatus {
        GitStatus {
            index:
                     if f.contains(git2::STATUS_INDEX_NEW) { StatusTypes::New }
                else if f.contains(git2::STATUS_INDEX_MODIFIED) { StatusTypes::Modified }
                else if f.contains(git2::STATUS_INDEX_DELETED) { StatusTypes::Deleted }
                else if f.contains(git2::STATUS_INDEX_RENAMED) { StatusTypes::Renamed }
                else if f.contains(git2::STATUS_INDEX_TYPECHANGE) { StatusTypes::TypeChange }
                else if f.contains(git2::STATUS_WT_NEW) { StatusTypes::Untracked }
                else { StatusTypes::Clean },
            workdir:
                     if f.contains(git2::STATUS_WT_NEW) { StatusTypes::Untracked }
                else if f.contains(git2::STATUS_WT_MODIFIED) { StatusTypes::Modified }
                else if f.contains(git2::STATUS_WT_DELETED) { StatusTypes::Deleted }
                else if f.contains(git2::STATUS_WT_RENAMED) { StatusTypes::Renamed }
                else if f.contains(git2::STATUS_WT_TYPECHANGE) { StatusTypes::TypeChange }
                else { StatusTypes::Clean },
        }
    }
}

impl fmt::Show for GitStatus {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}{}", self.index, self.workdir)
    }
}

fn get_git(path: &Path) -> Option<Repository> {
    match Repository::discover(path) {
        Ok(repo) => Some(repo),
        _ => None
    }
}

fn status(buffer: &mut Vec<PromptLine>, path: &Path, repo: &Repository) -> bool {
    let st = repo.statuses(Some(StatusOptions::new()
        .include_untracked(true)
        .renames_head_to_index(true)
        .exclude_submodules(true)
    ));

    let make_path_relative = |current: Path| {
        let mut fullpath = repo.workdir().unwrap();
        fullpath.push(current);

        fullpath.path_relative_from(path).unwrap()
    };

    match st {
        Ok(statuses) => {
            if statuses.len() <= 0 { return false }

            buffer.push(PromptLineBuilder::new()
                .colored_block(&"Git Status", color::CYAN)
                .build());

            for stat in statuses.iter() {
                let mut line = PromptLineBuilder::new_free();

                let status = GitStatus::new(stat.status());

                let diff = match stat.head_to_index() {
                    Some(delta) => Some(delta),
                    None => match stat.index_to_workdir() {
                        Some(delta) => Some(delta),
                        None => None
                    }
                };

                let val = format!("{} {}", status, match diff {
                    Some(delta) => {
                        let old = make_path_relative(delta.old_file().path().unwrap());
                        let new = make_path_relative(delta.new_file().path().unwrap());

                        if old != new {
                            format!("{} -> {}", old.display(), new.display())
                        } else {
                            format!("{}", old.display())
                        }
                    },
                    None => format!("{}", Path::new(stat.path().unwrap()).display())
                });

                line = match status.index {
                    StatusTypes::Clean => line.colored_block(&val, file_state_color(status.workdir)),
                    _ => match status.workdir {
                        StatusTypes::Clean | StatusTypes::Untracked =>
                            line.bold_colored_block(&val, file_state_color(status.index)),
                        _ => line.bold_colored_block(&val, color::RED)
                    }
                };

                buffer.push(line.indent().build());
            }

            return true
        },
        _ => { return false }
    }

    fn file_state_color(state: StatusTypes) -> u16 {
        match state {
            StatusTypes::Clean | StatusTypes::Untracked => color::WHITE,
            StatusTypes::Deleted => color::RED,
            StatusTypes::Modified => color::BLUE,
            StatusTypes::New => color::GREEN,
            StatusTypes::Renamed => color::CYAN,
            StatusTypes::TypeChange => color::YELLOW,
        }
    }
}

struct BranchInfo {
    name: Option<String>,
    upstream: Option<String>
}

fn git_branch(repo: &Repository) -> Result<BranchInfo, git2::Error> {
    let mut branches = repo.branches(None).ok().expect("Unable to load branches");

    for (mut branch, _) in branches {
        if !branch.is_head() {
            continue;
        }

        let name = branch.name();
        return Ok(BranchInfo {
            name: match name {
                Ok(n) => match n {
                    Some(value) => Some(value.to_string()),
                    _ => None
                },
                _ => None
            },
            upstream: match branch.upstream() {
                Ok(upstream) => {
                    match upstream.name() {
                        Ok(n) => match n {
                            Some(value) => Some(value.to_string()),
                            _ => None
                        },
                        _ => None
                    }
                },
                Err(_) => None
            }
        });
    }

    match repo.head() {
        Ok(r) => match repo.find_object(r.target().unwrap(), None) {
            Ok(obj) => {
                let sid = obj.short_id().ok().unwrap();
                let s = sid.as_str();
                let short_id = s.unwrap();
                Ok(BranchInfo {
                    name: Some(format!("{}", short_id)),
                    upstream: Some("?".to_string())
                })
            },
            Err(e) => Err(e)
        },
        Err(e) => Err(e)
    }
}

fn outgoing(buffer: &mut Vec<PromptLine>, repo: &Repository, has_status: bool) -> bool {
    match do_outgoing(buffer, repo, has_status) {
        Ok(r) => r,
        Err(e) => {
            println!("Error from outgoing: {}", e);
            false
        }
    }
}

fn do_outgoing(buffer: &mut Vec<PromptLine>, repo: &Repository, has_status: bool) -> Result<bool, git2::Error> {
    let branches = try!(git_branch(repo));

    let mut revwalk = try!(repo.revwalk());
    revwalk.set_sorting(git2::SORT_REVERSE);

    let from = try!(repo.revparse_single(branches.upstream.unwrap().as_slice())).id();
    let to = try!(repo.revparse_single(branches.name.unwrap().as_slice())).id();

    try!(revwalk.push(to));
    try!(revwalk.hide(from));

    let mut log_shown = false;

    for id in revwalk {
        let mut commit = try!(repo.find_commit(id));

        if !log_shown {
            buffer.push(PromptLineBuilder::new()
                .colored_block(&"Git Outgoing", color::CYAN)
                .indent_by(if has_status { 1 } else { 0 })
                .build());
            log_shown = true;
        }

        buffer.push(PromptLineBuilder::new_free()
            .indent()
            .colored_block(&format!("{} {}",
                String::from_utf8_lossy(
                    try!(try!(repo.find_object(commit.id(), None)).short_id()).get()
                ),
                String::from_utf8_lossy(match commit.summary_bytes() {
                    Some(b) => b,
                    None => continue
                })), color::WHITE)
            .build());
    }

    return Ok(log_shown);
}

fn end(buffer: &mut Vec<PromptLine>, repo: &Repository, indented: bool) {
    match git_branch(repo) {
        Ok(branches) => {
            buffer.push(PromptLineBuilder::new()
                .colored_block(
                    &match (branches.name, branches.upstream) {
                        (None, None) => "New Repository".to_string(),
                        (Some(name), None) => name,
                        (Some(name), Some(remote)) => format!("{}{} -> {}{}",
                            name,
                            prompt_buffer::reset(),
                            prompt_buffer::col(color::MAGENTA),
                            remote),
                        _ => "Unknown branch state".to_string()
                    }, color::CYAN)
                .indent_by(if indented { 1 } else { 0 })
                .build());
        },
        Err(_) => {}
    };
}

pub struct GitPlugin {
    repo: Option<Repository>,
    path: Path
}

impl GitPlugin {
    pub fn new() -> GitPlugin {
        GitPlugin {
            repo: None,
            path: os::make_absolute(&Path::new(".")).unwrap()
        }
    }
}

impl PromptBufferPlugin for GitPlugin {
    fn run(&mut self, path: &Path, lines: &mut Vec<PromptLine>) {
        if self.path != *path || self.repo.is_none() {
            self.path = path.clone();
            self.repo = get_git(&self.path);
        }

        match self.repo {
            Some(ref r) => {
                let st = status(lines, path, r);
                let out = outgoing(lines, r, st);
                end(lines, r, st || out);
            },
            _ => { }
        }
    }
}
<|endoftext|>


<commit_before>use audio::{AudioData, Operation as AudioOperation};
use camera::Projection;
use color::{self, Color};
use light::{ShadowMap, ShadowProjection};
use material::Material;
use mesh::DynamicMesh;
use node::{NodeInternal, NodePointer, TransformInternal};
use object::Base;
use render::{BackendResources, GpuData};
use skeleton::{Bone, Skeleton};
use text::{Operation as TextOperation, TextData};

use cgmath::Transform;
use froggy;
use gfx;
use mint;

use std::{mem, ops};
use std::sync::{Arc, Mutex};
use std::sync::mpsc;

#[derive(Clone, Debug)]
pub(crate) enum SubLight {
    Ambient,
    Directional,
    Hemisphere { ground: Color },
    Point,
}

#[derive(Clone, Debug)]
pub(crate) struct LightData {
    pub color: Color,
    pub intensity: f32,
    pub sub_light: SubLight,
    pub shadow: Option<(ShadowMap, ShadowProjection)>,
}

#[derive(Clone, Debug)]
pub(crate) struct SkeletonData {
    pub bones: Vec<Bone>,
    pub gpu_buffer_view: gfx::handle::ShaderResourceView<BackendResources, [f32; 4]>,
    pub gpu_buffer: gfx::handle::Buffer<BackendResources, [f32; 4]>,
}

#[derive(Clone, Debug)]
pub(crate) struct VisualData {
    pub material: Material,
    pub gpu: GpuData,
    pub skeleton: Option<Skeleton>,
}

#[derive(Debug)]
pub(crate) enum SubNode {
    /// Camera for rendering a scene.
    Camera(Projection),
    /// Group can be a parent to other objects.
    Group { first_child: Option<NodePointer> },
    /// Audio data.
    Audio(AudioData),
    /// Renderable text for 2D user interface.
    UiText(TextData),
    /// Renderable 3D content, such as a mesh.
    Visual(Material, GpuData, Option<Skeleton>),
    /// Lighting information for illumination and shadow casting.
    Light(LightData),
    /// A single bone.
    Bone { index: usize, inverse_bind_matrix: mint::ColumnMatrix4<f32> },
    /// Skeleton root.
    Skeleton(SkeletonData),
}

pub(crate) type Message = (froggy::WeakPointer<NodeInternal>, Operation);

#[derive(Debug)]
pub(crate) enum Operation {
    AddChild(NodePointer),
    RemoveChild(NodePointer),
    SetAudio(AudioOperation),
    SetVisible(bool),
    SetText(TextOperation),
    SetTransform(
        Option<mint::Point3<f32>>,
        Option<mint::Quaternion<f32>>,
        Option<f32>,
    ),
    SetMaterial(Material),
    SetSkeleton(Skeleton),
    SetShadow(ShadowMap, ShadowProjection),
    SetTexelRange(mint::Point2<i16>, mint::Vector2<u16>),
    SetWeights(Vec<f32>),
    SetName(String),
    SetProjection(Projection),
}

pub(crate) type HubPtr = Arc<Mutex<Hub>>;

pub(crate) struct Hub {
    pub(crate) nodes: froggy::Storage<NodeInternal>,
    pub(crate) message_tx: mpsc::Sender<Message>,
    message_rx: mpsc::Receiver<Message>,
}

impl<T: AsRef<Base>> ops::Index<T> for Hub {
    type Output = NodeInternal;
    fn index(&self, i: T) -> &Self::Output {
        let base: &Base = i.as_ref();
        &self.nodes[&base.node]
    }
}

impl<T: AsRef<Base>> ops::IndexMut<T> for Hub {
    fn index_mut(&mut self, i: T) -> &mut Self::Output {
        let base: &Base = i.as_ref();
        &mut self.nodes[&base.node]
    }
}

impl Hub {
    pub(crate) fn new() -> HubPtr {
        let (tx, rx) = mpsc::channel();
        let hub = Hub {
            nodes: froggy::Storage::new(),
            message_tx: tx,
            message_rx: rx,
        };
        Arc::new(Mutex::new(hub))
    }

    pub(crate) fn spawn(
        &mut self,
        sub: SubNode,
    ) -> Base {
        Base {
            node: self.nodes.create(sub.into()),
            tx: self.message_tx.clone(),
        }
    }

    pub(crate) fn spawn_visual(
        &mut self,
        mat: Material,
        gpu_data: GpuData,
        skeleton: Option<Skeleton>,
    ) -> Base {
        self.spawn(SubNode::Visual(mat, gpu_data, skeleton))
    }

    pub(crate) fn spawn_light(
        &mut self,
        data: LightData,
    ) -> Base {
        self.spawn(SubNode::Light(data))
    }

    pub(crate) fn spawn_skeleton(
        &mut self,
        data: SkeletonData,
    ) -> Base {
        self.spawn(SubNode::Skeleton(data))
    }

    /// Upgrades a `NodePointer` to a `Base`.
    pub(crate) fn upgrade_ptr(&self, ptr: NodePointer) -> Base {
        Base {
            node: ptr,
            tx: self.message_tx.clone(),
        }
    }

    pub(crate) fn process_messages(&mut self) {
        while let Ok((weak_ptr, operation)) = self.message_rx.try_recv() {
            let ptr = match weak_ptr.upgrade() {
                Ok(ptr) => ptr,
                Err(_) => continue,
            };
            match operation {
                Operation::SetAudio(operation) => {
                    if let SubNode::Audio(ref mut data) = self.nodes[&ptr].sub_node {
                        Hub::process_audio(operation, data);
                    }
                },
                Operation::SetVisible(visible) => {
                    self.nodes[&ptr].visible = visible;
                }
                Operation::SetTransform(pos, rot, scale) => {
                    let transform = &mut self.nodes[&ptr].transform;
                    if let Some(pos) = pos {

                        transform.disp = mint::Vector3::from(pos).into();
                    }
                    if let Some(rot) = rot {
                        transform.rot = rot.into();
                    }
                    if let Some(scale) = scale {
                        transform.scale = scale;
                    }
                }
                Operation::AddChild(child_ptr) => {
                    let sibling = match self.nodes[&ptr].sub_node {
                        SubNode::Group { ref mut first_child } =>
                            mem::replace(first_child, Some(child_ptr.clone())),
                        _ => unreachable!(),
                    };
                    let child = &mut self.nodes[&child_ptr];
                    if child.next_sibling.is_some() {
                        error!("Element {:?} is added to a group while still having old parent - {}",
                            child.sub_node, "discarding siblings");
                    }
                    child.next_sibling = sibling;
                }
                Operation::RemoveChild(child_ptr) => {
                    let next_sibling = self.nodes[&child_ptr].next_sibling.clone();
                    let target_maybe = Some(child_ptr);
                    let mut cur_ptr = match self.nodes[&ptr].sub_node {
                        SubNode::Group { ref mut first_child } => {
                            if *first_child == target_maybe {
                                *first_child = next_sibling;
                                continue;
                            }
                            first_child.clone()
                        }
                        _ => unreachable!()
                    };

                    //TODO: consolidate the code with `Scene::remove()`
                    loop {
                        let node = match cur_ptr.take() {
                            Some(next_ptr) => &mut self.nodes[&next_ptr],
                            None => {
                                error!("Unable to find child for removal");
                                break;
                            }
                        };
                        if node.next_sibling == target_maybe {
                            node.next_sibling = next_sibling;
                            break;
                        }
                        cur_ptr = node.next_sibling.clone(); //TODO: avoid clone
                    }
                }
                Operation::SetText(operation) => {
                    match self.nodes[&ptr].sub_node {
                        SubNode::UiText(ref mut data) => {
                            Hub::process_text(operation, data);
                        }
                        _ => unreachable!()
                    }
                }
                Operation::SetMaterial(material) => {
                    match self.nodes[&ptr].sub_node {
                        SubNode::Visual(ref mut mat, _, _) => {
                            *mat = material;
                        }
                        _ => unreachable!()
                    }
                }
                Operation::SetSkeleton(sleketon) => {
                    match self.nodes[&ptr].sub_node {
                        SubNode::Visual(_, _, ref mut skel) => {
                            *skel = Some(sleketon);
                        }
                        _ => unreachable!()
                    }
                }
                Operation::SetShadow(map, proj) => {
                    match self.nodes[&ptr].sub_node {
                        SubNode::Light(ref mut data) => {
                            data.shadow = Some((map, proj));
                        },
                    _ => unreachable!()
                    }
                }
                Operation::SetTexelRange(base, size) => {
                    match self.nodes[&ptr].sub_node {
                        SubNode::Visual(Material::Sprite(ref mut params), _, _) => {
                            params.map.set_texel_range(base, size);
                        }
                        _ => unreachable!()
                    }
                }
                Operation::SetWeights(weights) => {
                    fn set_weights(
                        gpu_data: &mut GpuData,
                        weights: &[f32],
                    ) {
                        use std::iter::repeat;
                        for (out, input) in gpu_data.displacement_contributions
                            .iter_mut()
                            .zip(weights.iter().chain(repeat(&0.0)))
                        {
                            out.weight = *input;
                        }
                    }

                    let mut x = match self.nodes[&ptr].sub_node {
                        SubNode::Visual(_, ref mut gpu_data, _) => {
                            set_weights(gpu_data, &weights);
                            continue;
                        }
                        SubNode::Group { ref first_child } => first_child.clone(),
                        _ => continue,
                    };

                    while let Some(ptr) = x {
                        if let SubNode::Visual(_, ref mut gpu_data, _) = self.nodes[&ptr].sub_node {
                            set_weights(gpu_data, &weights);
                        }
                        x = self.nodes[&ptr].next_sibling.clone();
                    }
                }
                Operation::SetName(name) => {
                    self.nodes[&ptr].name = Some(name);
                }
                Operation::SetProjection(projection) => {
                    match self.nodes[&ptr].sub_node {
                        SubNode::Camera(ref mut internal_projection) => {
                            *internal_projection = projection;
                        }
                        _ => unreachable!()
                    }
                }
            }
        }

        self.nodes.sync_pending();
    }

    fn process_audio(
        operation: AudioOperation,
        data: &mut AudioData,
    ) {
        match operation {
            AudioOperation::Append(clip) => data.source.append(clip),
            AudioOperation::Pause => data.source.pause(),
            AudioOperation::Resume => data.source.resume(),
            AudioOperation::Stop => data.source.stop(),
            AudioOperation::SetVolume(volume) => data.source.set_volume(volume),
        }
    }

    fn process_text(
        operation: TextOperation,
        data: &mut TextData,
    ) {
        use gfx_glyph::Scale;
        match operation {
            TextOperation::Color(color) => {
                let rgb = color::to_linear_rgb(color);
                data.section.text[0].color = [rgb[0], rgb[1], rgb[2], 1.0];
            }
            TextOperation::Font(font) => data.font = font,
            TextOperation::Layout(layout) => data.layout = layout,
            TextOperation::Opacity(opacity) => data.section.text[0].color[3] = opacity,
            TextOperation::Pos(point) => data.section.screen_position = (point.x, point.y),
            // TODO: somehow grab window::hdpi_factor and multiply size
            TextOperation::Scale(scale) => data.section.text[0].scale = Scale::uniform(scale),
            TextOperation::Size(size) => data.section.bounds = (size.x, size.y),
            TextOperation::Text(text) => data.section.text[0].text = text,
        }
    }

    pub(crate) fn update_mesh(
        &mut self,
        mesh: &DynamicMesh,
    ) {
        match self[mesh].sub_node {
            SubNode::Visual(_, ref mut gpu_data, _) => gpu_data.pending = Some(mesh.dynamic.clone()),
            _ => unreachable!(),
        }
    }

    fn walk_impl(
        &self, base: &Option<NodePointer>, only_visible: bool
    ) -> TreeWalker {
        let default_stack_size = 10;
        let mut walker = TreeWalker {
            hub: self,
            only_visible,
            stack: Vec::with_capacity(default_stack_size),
        };
        walker.descend(base);
        walker
    }

    pub(crate) fn walk<'a>(&'a self, base: &Option<NodePointer>) -> TreeWalker<'a> {
        self.walk_impl(base, true)
    }

    pub(crate) fn walk_all<'a>(&'a self, base: &Option<NodePointer>) -> TreeWalker<'a> {
        self.walk_impl(base, false)
    }
}

#[derive(Debug)]
pub(crate) struct WalkedNode<'a> {
    pub(crate) node_ptr: NodePointer,
    pub(crate) node: &'a NodeInternal,
    pub(crate) world_visible: bool,
    pub(crate) world_transform: TransformInternal,
}

pub(crate) struct TreeWalker<'a> {
    hub: &'a Hub,
    only_visible: bool,
    stack: Vec<WalkedNode<'a>>,
}

impl<'a> TreeWalker<'a> {
    fn descend(&mut self, base: &Option<NodePointer>) -> Option<&NodeInternal> {
        // Unwrap the base pointer, returning `None` if `base` is `None`.
        let mut ptr = base.as_ref()?;

        // Note: this is a CPU hotspot, presumably for copying stuff around
        // TODO: profile carefully and optimize
        let mut node = &self.hub.nodes[ptr];

        loop {
            let wn = match self.stack.last() {
                Some(parent) => WalkedNode {
                    node_ptr: ptr.clone(),
                    node,
                    world_visible: parent.world_visible && node.visible,
                    world_transform: parent.world_transform.concat(&node.transform),
                },
                None => WalkedNode {
                    node_ptr: ptr.clone(),
                    node,
                    world_visible: node.visible,
                    world_transform: node.transform,
                },
            };
            self.stack.push(wn);

            if self.only_visible && !node.visible {
                break;
            }

            match node.sub_node {
                SubNode::Group { first_child: Some(ref child_ptr) } => {
                    ptr = child_ptr;
                    node = &self.hub.nodes[&ptr];
                },
                _ => break,
            }
        }

        Some(node)
    }
}

impl<'a> Iterator for TreeWalker<'a> {
    type Item = WalkedNode<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        while let Some(top) = self.stack.pop() {
            self.descend(&top.node.next_sibling);
            if !self.only_visible || top.world_visible {
                return Some(top)
            }
        }
        None
    }
}
<commit_msg>Undo unnecessary changes in hub.rs<commit_after>use audio::{AudioData, Operation as AudioOperation};
use camera::Projection;
use color::{self, Color};
use light::{ShadowMap, ShadowProjection};
use material::Material;
use mesh::DynamicMesh;
use node::{NodeInternal, NodePointer, TransformInternal};
use object::Base;
use render::{BackendResources, GpuData};
use skeleton::{Bone, Skeleton};
use text::{Operation as TextOperation, TextData};

use cgmath::Transform;
use froggy;
use gfx;
use mint;

use std::{mem, ops};
use std::sync::{Arc, Mutex};
use std::sync::mpsc;

#[derive(Clone, Debug)]
pub(crate) enum SubLight {
    Ambient,
    Directional,
    Hemisphere { ground: Color },
    Point,
}

#[derive(Clone, Debug)]
pub(crate) struct LightData {
    pub color: Color,
    pub intensity: f32,
    pub sub_light: SubLight,
    pub shadow: Option<(ShadowMap, ShadowProjection)>,
}

#[derive(Clone, Debug)]
pub(crate) struct SkeletonData {
    pub bones: Vec<Bone>,
    pub gpu_buffer_view: gfx::handle::ShaderResourceView<BackendResources, [f32; 4]>,
    pub gpu_buffer: gfx::handle::Buffer<BackendResources, [f32; 4]>,
}

#[derive(Clone, Debug)]
pub(crate) struct VisualData {
    pub material: Material,
    pub gpu: GpuData,
    pub skeleton: Option<Skeleton>,
}

#[derive(Debug)]
pub(crate) enum SubNode {
    /// Camera for rendering a scene.
    Camera(Projection),
    /// Group can be a parent to other objects.
    Group { first_child: Option<NodePointer> },
    /// Audio data.
    Audio(AudioData),
    /// Renderable text for 2D user interface.
    UiText(TextData),
    /// Renderable 3D content, such as a mesh.
    Visual(Material, GpuData, Option<Skeleton>),
    /// Lighting information for illumination and shadow casting.
    Light(LightData),
    /// A single bone.
    Bone { index: usize, inverse_bind_matrix: mint::ColumnMatrix4<f32> },
    /// Skeleton root.
    Skeleton(SkeletonData),
}

pub(crate) type Message = (froggy::WeakPointer<NodeInternal>, Operation);

#[derive(Debug)]
pub(crate) enum Operation {
    AddChild(NodePointer),
    RemoveChild(NodePointer),
    SetAudio(AudioOperation),
    SetVisible(bool),
    SetText(TextOperation),
    SetTransform(
        Option<mint::Point3<f32>>,
        Option<mint::Quaternion<f32>>,
        Option<f32>,
    ),
    SetMaterial(Material),
    SetSkeleton(Skeleton),
    SetShadow(ShadowMap, ShadowProjection),
    SetTexelRange(mint::Point2<i16>, mint::Vector2<u16>),
    SetWeights(Vec<f32>),
    SetName(String),
    SetProjection(Projection),
}

pub(crate) type HubPtr = Arc<Mutex<Hub>>;

pub(crate) struct Hub {
    pub(crate) nodes: froggy::Storage<NodeInternal>,
    pub(crate) message_tx: mpsc::Sender<Message>,
    message_rx: mpsc::Receiver<Message>,
}

impl<T: AsRef<Base>> ops::Index<T> for Hub {
    type Output = NodeInternal;
    fn index(&self, i: T) -> &Self::Output {
        let base: &Base = i.as_ref();
        &self.nodes[&base.node]
    }
}

impl<T: AsRef<Base>> ops::IndexMut<T> for Hub {
    fn index_mut(&mut self, i: T) -> &mut Self::Output {
        let base: &Base = i.as_ref();
        &mut self.nodes[&base.node]
    }
}

impl Hub {
    pub(crate) fn new() -> HubPtr {
        let (tx, rx) = mpsc::channel();
        let hub = Hub {
            nodes: froggy::Storage::new(),
            message_tx: tx,
            message_rx: rx,
        };
        Arc::new(Mutex::new(hub))
    }

    pub(crate) fn spawn(
        &mut self,
        sub: SubNode,
    ) -> Base {
        Base {
            node: self.nodes.create(sub.into()),
            tx: self.message_tx.clone(),
        }
    }

    pub(crate) fn spawn_visual(
        &mut self,
        mat: Material,
        gpu_data: GpuData,
        skeleton: Option<Skeleton>,
    ) -> Base {
        self.spawn(SubNode::Visual(mat, gpu_data, skeleton))
    }

    pub(crate) fn spawn_light(
        &mut self,
        data: LightData,
    ) -> Base {
        self.spawn(SubNode::Light(data))
    }

    pub(crate) fn spawn_skeleton(
        &mut self,
        data: SkeletonData,
    ) -> Base {
        self.spawn(SubNode::Skeleton(data))
    }

    /// Upgrades a `NodePointer` to a `Base`.
    pub(crate) fn upgrade_ptr(&self, ptr: NodePointer) -> Base {
        Base {
            node: ptr,
            tx: self.message_tx.clone(),
        }
    }

    pub(crate) fn process_messages(&mut self) {
        while let Ok((weak_ptr, operation)) = self.message_rx.try_recv() {
            let ptr = match weak_ptr.upgrade() {
                Ok(ptr) => ptr,
                Err(_) => continue,
            };
            match operation {
                Operation::SetAudio(operation) => {
                    if let SubNode::Audio(ref mut data) = self.nodes[&ptr].sub_node {
                        Hub::process_audio(operation, data);
                    }
                },
                Operation::SetVisible(visible) => {
                    self.nodes[&ptr].visible = visible;
                }
                Operation::SetTransform(pos, rot, scale) => {
                    let transform = &mut self.nodes[&ptr].transform;
                    if let Some(pos) = pos {

                        transform.disp = mint::Vector3::from(pos).into();
                    }
                    if let Some(rot) = rot {
                        transform.rot = rot.into();
                    }
                    if let Some(scale) = scale {
                        transform.scale = scale;
                    }
                }
                Operation::AddChild(child_ptr) => {
                    let sibling = match self.nodes[&ptr].sub_node {
                        SubNode::Group { ref mut first_child } =>
                            mem::replace(first_child, Some(child_ptr.clone())),
                        _ => unreachable!(),
                    };
                    let child = &mut self.nodes[&child_ptr];
                    if child.next_sibling.is_some() {
                        error!("Element {:?} is added to a group while still having old parent - {}",
                            child.sub_node, "discarding siblings");
                    }
                    child.next_sibling = sibling;
                }
                Operation::RemoveChild(child_ptr) => {
                    let next_sibling = self.nodes[&child_ptr].next_sibling.clone();
                    let target_maybe = Some(child_ptr);
                    let mut cur_ptr = match self.nodes[&ptr].sub_node {
                        SubNode::Group { ref mut first_child } => {
                            if *first_child == target_maybe {
                                *first_child = next_sibling;
                                continue;
                            }
                            first_child.clone()
                        }
                        _ => unreachable!()
                    };

                    //TODO: consolidate the code with `Scene::remove()`
                    loop {
                        let node = match cur_ptr.take() {
                            Some(next_ptr) => &mut self.nodes[&next_ptr],
                            None => {
                                error!("Unable to find child for removal");
                                break;
                            }
                        };
                        if node.next_sibling == target_maybe {
                            node.next_sibling = next_sibling;
                            break;
                        }
                        cur_ptr = node.next_sibling.clone(); //TODO: avoid clone
                    }
                }
                Operation::SetText(operation) => {
                    match self.nodes[&ptr].sub_node {
                        SubNode::UiText(ref mut data) => {
                            Hub::process_text(operation, data);
                        }
                        _ => unreachable!()
                    }
                }
                Operation::SetMaterial(material) => {
                    match self.nodes[&ptr].sub_node {
                        SubNode::Visual(ref mut mat, _, _) => {
                            *mat = material;
                        }
                        _ => unreachable!()
                    }
                }
                Operation::SetSkeleton(sleketon) => {
                    match self.nodes[&ptr].sub_node {
                        SubNode::Visual(_, _, ref mut skel) => {
                            *skel = Some(sleketon);
                        }
                        _ => unreachable!()
                    }
                }
                Operation::SetShadow(map, proj) => {
                    match self.nodes[&ptr].sub_node {
                        SubNode::Light(ref mut data) => {
                            data.shadow = Some((map, proj));
                        },
                    _ => unreachable!()
                    }
                }
                Operation::SetTexelRange(base, size) => {
                    match self.nodes[&ptr].sub_node {
                        SubNode::Visual(Material::Sprite(ref mut params), _, _) => {
                            params.map.set_texel_range(base, size);
                        }
                        _ => unreachable!()
                    }
                }
                Operation::SetWeights(weights) => {
                    fn set_weights(
                        gpu_data: &mut GpuData,
                        weights: &[f32],
                    ) {
                        use std::iter::repeat;
                        for (out, input) in gpu_data.displacement_contributions
                            .iter_mut()
                            .zip(weights.iter().chain(repeat(&0.0)))
                        {
                            out.weight = *input;
                        }
                    }

                    let mut x = match self.nodes[&ptr].sub_node {
                        SubNode::Visual(_, ref mut gpu_data, _) => {
                            set_weights(gpu_data, &weights);
                            continue;
                        }
                        SubNode::Group { ref first_child } => first_child.clone(),
                        _ => continue,
                    };

                    while let Some(ptr) = x {
                        if let SubNode::Visual(_, ref mut gpu_data, _) = self.nodes[&ptr].sub_node {
                            set_weights(gpu_data, &weights);
                        }
                        x = self.nodes[&ptr].next_sibling.clone();
                    }
                }
                Operation::SetName(name) => {
                    self.nodes[&ptr].name = Some(name);
                }
                Operation::SetProjection(projection) => {
                    match self.nodes[&ptr].sub_node {
                        SubNode::Camera(ref mut internal_projection) => {
                            *internal_projection = projection;
                        }
                        _ => unreachable!()
                    }
                }
            }
        }

        self.nodes.sync_pending();
    }

    fn process_audio(
        operation: AudioOperation,
        data: &mut AudioData,
    ) {
        match operation {
            AudioOperation::Append(clip) => data.source.append(clip),
            AudioOperation::Pause => data.source.pause(),
            AudioOperation::Resume => data.source.resume(),
            AudioOperation::Stop => data.source.stop(),
            AudioOperation::SetVolume(volume) => data.source.set_volume(volume),
        }
    }

    fn process_text(
        operation: TextOperation,
        data: &mut TextData,
    ) {
        use gfx_glyph::Scale;
        match operation {
            TextOperation::Color(color) => {
                let rgb = color::to_linear_rgb(color);
                data.section.text[0].color = [rgb[0], rgb[1], rgb[2], 1.0];
            }
            TextOperation::Font(font) => data.font = font,
            TextOperation::Layout(layout) => data.layout = layout,
            TextOperation::Opacity(opacity) => data.section.text[0].color[3] = opacity,
            TextOperation::Pos(point) => data.section.screen_position = (point.x, point.y),
            // TODO: somehow grab window::hdpi_factor and multiply size
            TextOperation::Scale(scale) => data.section.text[0].scale = Scale::uniform(scale),
            TextOperation::Size(size) => data.section.bounds = (size.x, size.y),
            TextOperation::Text(text) => data.section.text[0].text = text,
        }
    }

    pub(crate) fn update_mesh(
        &mut self,
        mesh: &DynamicMesh,
    ) {
        match self[mesh].sub_node {
            SubNode::Visual(_, ref mut gpu_data, _) => gpu_data.pending = Some(mesh.dynamic.clone()),
            _ => unreachable!(),
        }
    }

    fn walk_impl(
        &self, base: &Option<NodePointer>, only_visible: bool
    ) -> TreeWalker {
        let default_stack_size = 10;
        let mut walker = TreeWalker {
            hub: self,
            only_visible,
            stack: Vec::with_capacity(default_stack_size),
        };
        walker.descend(base);
        walker
    }

    pub(crate) fn walk(&self, base: &Option<NodePointer>) -> TreeWalker {
        self.walk_impl(base, true)
    }

    pub(crate) fn walk_all(&self, base: &Option<NodePointer>) -> TreeWalker {
        self.walk_impl(base, false)
    }
}

#[derive(Debug)]
pub(crate) struct WalkedNode<'a> {
    pub(crate) node_ptr: NodePointer,
    pub(crate) node: &'a NodeInternal,
    pub(crate) world_visible: bool,
    pub(crate) world_transform: TransformInternal,
}

pub(crate) struct TreeWalker<'a> {
    hub: &'a Hub,
    only_visible: bool,
    stack: Vec<WalkedNode<'a>>,
}

impl<'a> TreeWalker<'a> {
    fn descend(&mut self, base: &Option<NodePointer>) -> Option<&NodeInternal> {
        // Unwrap the base pointer, returning `None` if `base` is `None`.
        let mut ptr = base.as_ref()?;

        // Note: this is a CPU hotspot, presumably for copying stuff around
        // TODO: profile carefully and optimize
        let mut node = &self.hub.nodes[ptr];

        loop {
            let wn = match self.stack.last() {
                Some(parent) => WalkedNode {
                    node_ptr: ptr.clone(),
                    node,
                    world_visible: parent.world_visible && node.visible,
                    world_transform: parent.world_transform.concat(&node.transform),
                },
                None => WalkedNode {
                    node_ptr: ptr.clone(),
                    node,
                    world_visible: node.visible,
                    world_transform: node.transform,
                },
            };
            self.stack.push(wn);

            if self.only_visible && !node.visible {
                break;
            }

            match node.sub_node {
                SubNode::Group { first_child: Some(ref child_ptr) } => {
                    ptr = child_ptr;
                    node = &self.hub.nodes[&ptr];
                },
                _ => break,
            }
        }

        Some(node)
    }
}

impl<'a> Iterator for TreeWalker<'a> {
    type Item = WalkedNode<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        while let Some(top) = self.stack.pop() {
            self.descend(&top.node.next_sibling);
            if !self.only_visible || top.world_visible {
                return Some(top)
            }
        }
        None
    }
}
<|endoftext|>


<commit_before>//! Points on the 2D character grid.

use XY;
use direction::Orientation;
use std::cmp::{Ordering, max, min};

use std::ops::{Add, Div, Mul, Sub};

/// Simple 2D size, in cells.
///
/// Note: due to a bug in rustdoc ([#32077]), the documentation for `Vec2` is
/// currently shown on the [`XY`] page.
///
/// [#32077]: https://github.com/rust-lang/rust/issues/32077
/// [`XY`]: ../struct.XY.html
pub type Vec2 = XY<usize>;

impl PartialOrd for XY<usize> {
    /// `a < b` <=> `a.x < b.x && a.y < b.y`
    fn partial_cmp(&self, other: &Vec2) -> Option<Ordering> {
        if self == other {
            Some(Ordering::Equal)
        } else if self.x < other.x && self.y < other.y {
            Some(Ordering::Less)
        } else if self.x > other.x && self.y > other.y {
            Some(Ordering::Greater)
        } else {
            None
        }
    }
}

impl XY<usize> {
    /// Returns a new Vec2 that is a maximum per coordinate.
    pub fn max<A: Into<Vec2>, B: Into<Vec2>>(a: A, b: B) -> Self {
        let a = a.into();
        let b = b.into();
        a.zip_map(b, max)
    }

    /// Returns a new Vec2 that is no larger than any input in both dimensions.
    pub fn min<A: Into<Vec2>, B: Into<Vec2>>(a: A, b: B) -> Self {
        let a = a.into();
        let b = b.into();
        a.zip_map(b, min)
    }

    /// Returns the minimum of `self` and `other`.
    pub fn or_min<T: Into<Vec2>>(self, other: T) -> Self {
        Vec2::min(self, other)
    }

    /// Returns the maximum of `self` and `other`.
    pub fn or_max<T: Into<Vec2>>(self, other: T) -> Self {
        Vec2::max(self, other)
    }

    /// Returns a vector with the X component of self, and y=0.
    pub fn keep_x(&self) -> Self {
        Vec2::new(self.x, 0)
    }

    /// Returns a vector with the Y component of self, and x=0.
    pub fn keep_y(&self) -> Self {
        Vec2::new(0, self.y)
    }

    /// Alias for `Vec2::new(0,0)`.
    pub fn zero() -> Self {
        Vec2::new(0, 0)
    }

    /// Returns (max(self.x,other.x), self.y+other.y)
    pub fn stack_vertical(&self, other: &Vec2) -> Vec2 {
        Vec2::new(max(self.x, other.x), self.y + other.y)
    }

    /// Returns (self.x+other.x, max(self.y,other.y))
    pub fn stack_horizontal(&self, other: &Vec2) -> Vec2 {
        Vec2::new(self.x + other.x, max(self.y, other.y))
    }

    /// Returns `true` if `self` could fit inside `other`.
    ///
    /// Shortcut for `self.x <= other.x && self.y <= other.y`.
    pub fn fits_in<T: Into<Vec2>>(&self, other: T) -> bool {
        let other = other.into();
        self.x <= other.x && self.y <= other.y
    }

    /// Returns a new `Vec2` with the axis `o` set to `value`.
    pub fn with_axis(&self, o: Orientation, value: usize) -> Self {
        let mut new = *self;
        *o.get_ref(&mut new) = value;
        new
    }

    /// Returns a new `Vec2` with the axis `o` set to the value from `other`.
    pub fn with_axis_from(&self, o: Orientation, other: &Vec2) -> Self {
        let mut new = *self;
        new.set_axis_from(o, other);
        new
    }

    /// Sets the axis `o` on `self` to the value from `other`.
    pub fn set_axis_from(&mut self, o: Orientation, other: &Vec2) {
        *o.get_ref(self) = o.get(other);
    }
}

impl From<(i32, i32)> for XY<usize> {
    fn from((x, y): (i32, i32)) -> Self {
        (x as usize, y as usize).into()
    }
}

impl From<(u32, u32)> for XY<usize> {
    fn from((x, y): (u32, u32)) -> Self {
        (x as usize, y as usize).into()
    }
}

impl<T: Into<Vec2>> Add<T> for XY<usize> {
    type Output = Vec2;

    fn add(self, other: T) -> Vec2 {
        self.zip_map(other.into(), Add::add)
    }
}

impl<T: Into<Vec2>> Sub<T> for XY<usize> {
    type Output = Vec2;

    fn sub(self, other: T) -> Vec2 {
        self.zip_map(other.into(), Sub::sub)
    }
}

impl Div<usize> for XY<usize> {
    type Output = Vec2;

    fn div(self, other: usize) -> Vec2 {
        self.map(|s| s / other)
    }
}

impl Mul<usize> for XY<usize> {
    type Output = Vec2;

    fn mul(self, other: usize) -> Vec2 {
        self.map(|s| s * other)
    }
}

/// Four values representing each direction.
#[derive(Clone,Copy)]
pub struct Vec4 {
    /// Left margin
    pub left: usize,
    /// Right margin
    pub right: usize,
    /// Top margin
    pub top: usize,
    /// Bottom margin
    pub bottom: usize,
}

impl Vec4 {
    /// Creates a new Vec4.
    pub fn new(left: usize, right: usize, top: usize, bottom: usize) -> Self {
        Vec4 {
            left: left,
            right: right,
            top: top,
            bottom: bottom,
        }
    }

    /// Returns left + right.
    pub fn horizontal(&self) -> usize {
        self.left + self.right
    }

    /// Returns top + bottom.
    pub fn vertical(&self) -> usize {
        self.top + self.bottom
    }

    /// Returns (left+right, top+bottom).
    pub fn combined(&self) -> Vec2 {
        Vec2::new(self.horizontal(), self.vertical())
    }

    /// Returns (left, top).
    pub fn top_left(&self) -> Vec2 {
        Vec2::new(self.left, self.top)
    }

    /// Returns (right, bottom).
    pub fn bot_right(&self) -> Vec2 {
        Vec2::new(self.right, self.bottom)
    }
}

impl From<(usize, usize, usize, usize)> for Vec4 {
    fn from((left, right, top, bottom): (usize, usize, usize, usize)) -> Vec4 {
        Vec4::new(left, right, top, bottom)
    }
}

impl From<(i32, i32, i32, i32)> for Vec4 {
    fn from((left, right, top, bottom): (i32, i32, i32, i32)) -> Vec4 {
        (left as usize, right as usize, top as usize, bottom as usize).into()
    }
}

impl<T: Into<Vec4>> Add<T> for Vec4 {
    type Output = Vec4;

    fn add(self, other: T) -> Vec4 {
        let ov = other.into();

        Vec4 {
            left: self.left + ov.left,
            right: self.right + ov.right,
            top: self.top + ov.top,
            bottom: self.bottom + ov.bottom,
        }
    }
}

impl<T: Into<Vec4>> Sub<T> for Vec4 {
    type Output = Vec4;

    fn sub(self, other: T) -> Vec4 {
        let ov = other.into();

        Vec4 {
            left: self.left - ov.left,
            right: self.right - ov.right,
            top: self.top - ov.top,
            bottom: self.bottom - ov.bottom,
        }
    }
}

impl Div<usize> for Vec4 {
    type Output = Vec4;

    fn div(self, other: usize) -> Vec4 {
        Vec4 {
            left: self.left / other,
            right: self.right / other,
            top: self.top / other,
            bottom: self.bottom / other,
        }
    }
}

impl Mul<usize> for Vec4 {
    type Output = Vec4;

    fn mul(self, other: usize) -> Vec4 {
        Vec4 {
            left: self.left * other,
            right: self.right * other,
            top: self.top * other,
            bottom: self.bottom * other,
        }
    }
}

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

    #[test]
    fn test_from() {
        let vi32 = Vec2::from((4i32, 5i32));
        let vu32 = Vec2::from((4u32, 5u32));

        let vusize = Vec2::from((4usize, 5usize));
        let vvec = Vec2::from(Vec2::new(4, 5));

        assert_eq!(vi32 - vu32, vusize - vvec);
    }
}
<commit_msg>Add From<((left,right), (top, bottom))> to Vec4<commit_after>//! Points on the 2D character grid.

use XY;
use direction::Orientation;
use std::cmp::{Ordering, max, min};

use std::ops::{Add, Div, Mul, Sub};

/// Simple 2D size, in cells.
///
/// Note: due to a bug in rustdoc ([#32077]), the documentation for `Vec2` is
/// currently shown on the [`XY`] page.
///
/// [#32077]: https://github.com/rust-lang/rust/issues/32077
/// [`XY`]: ../struct.XY.html
pub type Vec2 = XY<usize>;

impl PartialOrd for XY<usize> {
    /// `a < b` <=> `a.x < b.x && a.y < b.y`
    fn partial_cmp(&self, other: &Vec2) -> Option<Ordering> {
        if self == other {
            Some(Ordering::Equal)
        } else if self.x < other.x && self.y < other.y {
            Some(Ordering::Less)
        } else if self.x > other.x && self.y > other.y {
            Some(Ordering::Greater)
        } else {
            None
        }
    }
}

impl XY<usize> {
    /// Returns a new Vec2 that is a maximum per coordinate.
    pub fn max<A: Into<Vec2>, B: Into<Vec2>>(a: A, b: B) -> Self {
        let a = a.into();
        let b = b.into();
        a.zip_map(b, max)
    }

    /// Returns a new Vec2 that is no larger than any input in both dimensions.
    pub fn min<A: Into<Vec2>, B: Into<Vec2>>(a: A, b: B) -> Self {
        let a = a.into();
        let b = b.into();
        a.zip_map(b, min)
    }

    /// Returns the minimum of `self` and `other`.
    pub fn or_min<T: Into<Vec2>>(self, other: T) -> Self {
        Vec2::min(self, other)
    }

    /// Returns the maximum of `self` and `other`.
    pub fn or_max<T: Into<Vec2>>(self, other: T) -> Self {
        Vec2::max(self, other)
    }

    /// Returns a vector with the X component of self, and y=0.
    pub fn keep_x(&self) -> Self {
        Vec2::new(self.x, 0)
    }

    /// Returns a vector with the Y component of self, and x=0.
    pub fn keep_y(&self) -> Self {
        Vec2::new(0, self.y)
    }

    /// Alias for `Vec2::new(0,0)`.
    pub fn zero() -> Self {
        Vec2::new(0, 0)
    }

    /// Returns (max(self.x,other.x), self.y+other.y)
    pub fn stack_vertical(&self, other: &Vec2) -> Vec2 {
        Vec2::new(max(self.x, other.x), self.y + other.y)
    }

    /// Returns (self.x+other.x, max(self.y,other.y))
    pub fn stack_horizontal(&self, other: &Vec2) -> Vec2 {
        Vec2::new(self.x + other.x, max(self.y, other.y))
    }

    /// Returns `true` if `self` could fit inside `other`.
    ///
    /// Shortcut for `self.x <= other.x && self.y <= other.y`.
    pub fn fits_in<T: Into<Vec2>>(&self, other: T) -> bool {
        let other = other.into();
        self.x <= other.x && self.y <= other.y
    }

    /// Returns a new `Vec2` with the axis `o` set to `value`.
    pub fn with_axis(&self, o: Orientation, value: usize) -> Self {
        let mut new = *self;
        *o.get_ref(&mut new) = value;
        new
    }

    /// Returns a new `Vec2` with the axis `o` set to the value from `other`.
    pub fn with_axis_from(&self, o: Orientation, other: &Vec2) -> Self {
        let mut new = *self;
        new.set_axis_from(o, other);
        new
    }

    /// Sets the axis `o` on `self` to the value from `other`.
    pub fn set_axis_from(&mut self, o: Orientation, other: &Vec2) {
        *o.get_ref(self) = o.get(other);
    }
}

impl From<(i32, i32)> for XY<usize> {
    fn from((x, y): (i32, i32)) -> Self {
        (x as usize, y as usize).into()
    }
}

impl From<(u32, u32)> for XY<usize> {
    fn from((x, y): (u32, u32)) -> Self {
        (x as usize, y as usize).into()
    }
}

impl<T: Into<Vec2>> Add<T> for XY<usize> {
    type Output = Vec2;

    fn add(self, other: T) -> Vec2 {
        self.zip_map(other.into(), Add::add)
    }
}

impl<T: Into<Vec2>> Sub<T> for XY<usize> {
    type Output = Vec2;

    fn sub(self, other: T) -> Vec2 {
        self.zip_map(other.into(), Sub::sub)
    }
}

impl Div<usize> for XY<usize> {
    type Output = Vec2;

    fn div(self, other: usize) -> Vec2 {
        self.map(|s| s / other)
    }
}

impl Mul<usize> for XY<usize> {
    type Output = Vec2;

    fn mul(self, other: usize) -> Vec2 {
        self.map(|s| s * other)
    }
}

/// Four values representing each direction.
#[derive(Clone,Copy)]
pub struct Vec4 {
    /// Left margin
    pub left: usize,
    /// Right margin
    pub right: usize,
    /// Top margin
    pub top: usize,
    /// Bottom margin
    pub bottom: usize,
}

impl Vec4 {
    /// Creates a new Vec4.
    pub fn new(left: usize, right: usize, top: usize, bottom: usize) -> Self {
        Vec4 {
            left: left,
            right: right,
            top: top,
            bottom: bottom,
        }
    }

    /// Returns left + right.
    pub fn horizontal(&self) -> usize {
        self.left + self.right
    }

    /// Returns top + bottom.
    pub fn vertical(&self) -> usize {
        self.top + self.bottom
    }

    /// Returns (left+right, top+bottom).
    pub fn combined(&self) -> Vec2 {
        Vec2::new(self.horizontal(), self.vertical())
    }

    /// Returns (left, top).
    pub fn top_left(&self) -> Vec2 {
        Vec2::new(self.left, self.top)
    }

    /// Returns (right, bottom).
    pub fn bot_right(&self) -> Vec2 {
        Vec2::new(self.right, self.bottom)
    }
}

impl From<(usize, usize, usize, usize)> for Vec4 {
    fn from((left, right, top, bottom): (usize, usize, usize, usize)) -> Vec4 {
        Vec4::new(left, right, top, bottom)
    }
}

impl From<(i32, i32, i32, i32)> for Vec4 {
    fn from((left, right, top, bottom): (i32, i32, i32, i32)) -> Vec4 {
        (left as usize, right as usize, top as usize, bottom as usize).into()
    }
}

impl From<((i32, i32), (i32, i32))> for Vec4 {
    fn from(((left, right), (top, bottom)): ((i32, i32), (i32, i32))) -> Vec4 {
        (left, right, top, bottom).into()
    }
}
impl From<((usize, usize), (usize, usize))> for Vec4 {
    fn from(((left, right), (top, bottom)): ((usize, usize), (usize, usize)))
            -> Vec4 {
        (left, right, top, bottom).into()
    }
}

impl<T: Into<Vec4>> Add<T> for Vec4 {
    type Output = Vec4;

    fn add(self, other: T) -> Vec4 {
        let ov = other.into();

        Vec4 {
            left: self.left + ov.left,
            right: self.right + ov.right,
            top: self.top + ov.top,
            bottom: self.bottom + ov.bottom,
        }
    }
}

impl<T: Into<Vec4>> Sub<T> for Vec4 {
    type Output = Vec4;

    fn sub(self, other: T) -> Vec4 {
        let ov = other.into();

        Vec4 {
            left: self.left - ov.left,
            right: self.right - ov.right,
            top: self.top - ov.top,
            bottom: self.bottom - ov.bottom,
        }
    }
}

impl Div<usize> for Vec4 {
    type Output = Vec4;

    fn div(self, other: usize) -> Vec4 {
        Vec4 {
            left: self.left / other,
            right: self.right / other,
            top: self.top / other,
            bottom: self.bottom / other,
        }
    }
}

impl Mul<usize> for Vec4 {
    type Output = Vec4;

    fn mul(self, other: usize) -> Vec4 {
        Vec4 {
            left: self.left * other,
            right: self.right * other,
            top: self.top * other,
            bottom: self.bottom * other,
        }
    }
}

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

    #[test]
    fn test_from() {
        let vi32 = Vec2::from((4i32, 5i32));
        let vu32 = Vec2::from((4u32, 5u32));

        let vusize = Vec2::from((4usize, 5usize));
        let vvec = Vec2::from(Vec2::new(4, 5));

        assert_eq!(vi32 - vu32, vusize - vvec);
    }
}
<|endoftext|>