<commit_before>use crate::back::write::create_informational_target_machine;
use crate::llvm;
use libc::c_int;
use rustc_codegen_ssa::target_features::supported_target_features;
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::bug;
use rustc_session::config::PrintRequest;
use rustc_session::Session;
use rustc_span::symbol::Symbol;
use rustc_target::spec::{MergeFunctions, PanicStrategy};
use std::ffi::{CStr, CString};

use std::slice;
use std::str;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;

static POISONED: AtomicBool = AtomicBool::new(false);
static INIT: Once = Once::new();

pub(crate) fn init(sess: &Session) {
    unsafe {
        // Before we touch LLVM, make sure that multithreading is enabled.
        INIT.call_once(|| {
            if llvm::LLVMStartMultithreaded() != 1 {
                // use an extra bool to make sure that all future usage of LLVM
                // cannot proceed despite the Once not running more than once.
                POISONED.store(true, Ordering::SeqCst);
            }

            configure_llvm(sess);
        });

        if POISONED.load(Ordering::SeqCst) {
            bug!("couldn't enable multi-threaded LLVM");
        }
    }
}

fn require_inited() {
    INIT.call_once(|| bug!("llvm is not initialized"));
    if POISONED.load(Ordering::SeqCst) {
        bug!("couldn't enable multi-threaded LLVM");
    }
}

unsafe fn configure_llvm(sess: &Session) {
    let n_args = sess.opts.cg.llvm_args.len() + sess.target.llvm_args.len();
    let mut llvm_c_strs = Vec::with_capacity(n_args + 1);
    let mut llvm_args = Vec::with_capacity(n_args + 1);

    llvm::LLVMRustInstallFatalErrorHandler();

    fn llvm_arg_to_arg_name(full_arg: &str) -> &str {
        full_arg.trim().split(|c: char| c == '=' || c.is_whitespace()).next().unwrap_or("")
    }

    let cg_opts = sess.opts.cg.llvm_args.iter();
    let tg_opts = sess.target.llvm_args.iter();
    let sess_args = cg_opts.chain(tg_opts);

    let user_specified_args: FxHashSet<_> =
        sess_args.clone().map(|s| llvm_arg_to_arg_name(s)).filter(|s| !s.is_empty()).collect();

    {
        // This adds the given argument to LLVM. Unless `force` is true
        // user specified arguments are *not* overridden.
        let mut add = |arg: &str, force: bool| {
            if force || !user_specified_args.contains(llvm_arg_to_arg_name(arg)) {
                let s = CString::new(arg).unwrap();
                llvm_args.push(s.as_ptr());
                llvm_c_strs.push(s);
            }
        };
        // Set the llvm "program name" to make usage and invalid argument messages more clear.
        add("rustc -Cllvm-args=\"...\" with", true);
        if sess.time_llvm_passes() {
            add("-time-passes", false);
        }
        if sess.print_llvm_passes() {
            add("-debug-pass=Structure", false);
        }
        if !sess.opts.debugging_opts.no_generate_arange_section {
            add("-generate-arange-section", false);
        }
        match sess.opts.debugging_opts.merge_functions.unwrap_or(sess.target.merge_functions) {
            MergeFunctions::Disabled | MergeFunctions::Trampolines => {}
            MergeFunctions::Aliases => {
                add("-mergefunc-use-aliases", false);
            }
        }

        if sess.target.os == "emscripten" && sess.panic_strategy() == PanicStrategy::Unwind {
            add("-enable-emscripten-cxx-exceptions", false);
        }

        // HACK(eddyb) LLVM inserts `llvm.assume` calls to preserve align attributes
        // during inlining. Unfortunately these may block other optimizations.
        add("-preserve-alignment-assumptions-during-inlining=false", false);

        for arg in sess_args {
            add(&(*arg), true);
        }
    }

    if sess.opts.debugging_opts.llvm_time_trace {
        // time-trace is not thread safe and running it in parallel will cause seg faults.
        if !sess.opts.debugging_opts.no_parallel_llvm {
            bug!("`-Z llvm-time-trace` requires `-Z no-parallel-llvm")
        }

        llvm::LLVMTimeTraceProfilerInitialize();
    }

    llvm::LLVMInitializePasses();

    rustc_llvm::initialize_available_targets();

    llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr());
}

pub fn time_trace_profiler_finish(file_name: &str) {
    unsafe {
        let file_name = CString::new(file_name).unwrap();
        llvm::LLVMTimeTraceProfilerFinish(file_name.as_ptr());
    }
}

// WARNING: the features after applying `to_llvm_feature` must be known
// to LLVM or the feature detection code will walk past the end of the feature
// array, leading to crashes.
// To find a list of LLVM's names, check llvm-project/llvm/include/llvm/Support/*TargetParser.def
// where the * matches the architecture's name
// Beware to not use the llvm github project for this, but check the git submodule
// found in src/llvm-project
// Though note that Rust can also be build with an external precompiled version of LLVM
// which might lead to failures if the oldest tested / supported LLVM version
// doesn't yet support the relevant intrinsics
pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
    let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch };
    match (arch, s) {
        ("x86", "pclmulqdq") => "pclmul",
        ("x86", "rdrand") => "rdrnd",
        ("x86", "bmi1") => "bmi",
        ("x86", "cmpxchg16b") => "cx16",
        ("x86", "avx512vaes") => "vaes",
        ("x86", "avx512gfni") => "gfni",
        ("x86", "avx512vpclmulqdq") => "vpclmulqdq",
        ("aarch64", "fp") => "fp-armv8",
        ("aarch64", "fp16") => "fullfp16",
        (_, s) => s,
    }
}

pub fn target_features(sess: &Session) -> Vec<Symbol> {
    let target_machine = create_informational_target_machine(sess);
    supported_target_features(sess)
        .iter()
        .filter_map(
            |&(feature, gate)| {
                if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None }
            },
        )
        .filter(|feature| {
            let llvm_feature = to_llvm_feature(sess, feature);
            let cstr = CString::new(llvm_feature).unwrap();
            unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) }
        })
        .map(|feature| Symbol::intern(feature))
        .collect()
}

pub fn print_version() {
    let (major, minor, patch) = get_version();
    println!("LLVM version: {}.{}.{}", major, minor, patch);
}

pub fn get_version() -> (u32, u32, u32) {
    // Can be called without initializing LLVM
    unsafe {
        (llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor(), llvm::LLVMRustVersionPatch())
    }
}

pub fn print_passes() {
    // Can be called without initializing LLVM
    unsafe {
        llvm::LLVMRustPrintPasses();
    }
}

pub(crate) fn print(req: PrintRequest, sess: &Session) {
    require_inited();
    let tm = create_informational_target_machine(sess);
    unsafe {
        match req {
            PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
            PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
            _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
        }
    }
}

fn handle_native(name: &str) -> &str {
    if name != "native" {
        return name;
    }

    unsafe {
        let mut len = 0;
        let ptr = llvm::LLVMRustGetHostCPUName(&mut len);
        str::from_utf8(slice::from_raw_parts(ptr as *const u8, len)).unwrap()
    }
}

pub fn target_cpu(sess: &Session) -> &str {
    let name = sess.opts.cg.target_cpu.as_ref().unwrap_or(&sess.target.cpu);
    handle_native(name)
}

pub fn handle_native_features(sess: &Session) -> Vec<String> {
    match sess.opts.cg.target_cpu {
        Some(ref s) => {
            if s != "native" {
                return vec![];
            }

            let features_string = unsafe {
                let ptr = llvm::LLVMGetHostCPUFeatures();
                let features_string = if !ptr.is_null() {
                    CStr::from_ptr(ptr)
                        .to_str()
                        .unwrap_or_else(|e| {
                            bug!("LLVM returned a non-utf8 features string: {}", e);
                        })
                        .to_owned()
                } else {
                    bug!("could not allocate host CPU features, LLVM returned a `null` string");
                };

                llvm::LLVMDisposeMessage(ptr);

                features_string
            };

            features_string.split(",").map(|s| s.to_owned()).collect()
        }
        None => vec![],
    }
}

pub fn tune_cpu(sess: &Session) -> Option<&str> {
    let name = sess.opts.debugging_opts.tune_cpu.as_ref()?;
    Some(handle_native(name))
}
<commit_msg>Import small cold functions<commit_after>use crate::back::write::create_informational_target_machine;
use crate::llvm;
use libc::c_int;
use rustc_codegen_ssa::target_features::supported_target_features;
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::bug;
use rustc_session::config::PrintRequest;
use rustc_session::Session;
use rustc_span::symbol::Symbol;
use rustc_target::spec::{MergeFunctions, PanicStrategy};
use std::ffi::{CStr, CString};

use std::slice;
use std::str;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;

static POISONED: AtomicBool = AtomicBool::new(false);
static INIT: Once = Once::new();

pub(crate) fn init(sess: &Session) {
    unsafe {
        // Before we touch LLVM, make sure that multithreading is enabled.
        INIT.call_once(|| {
            if llvm::LLVMStartMultithreaded() != 1 {
                // use an extra bool to make sure that all future usage of LLVM
                // cannot proceed despite the Once not running more than once.
                POISONED.store(true, Ordering::SeqCst);
            }

            configure_llvm(sess);
        });

        if POISONED.load(Ordering::SeqCst) {
            bug!("couldn't enable multi-threaded LLVM");
        }
    }
}

fn require_inited() {
    INIT.call_once(|| bug!("llvm is not initialized"));
    if POISONED.load(Ordering::SeqCst) {
        bug!("couldn't enable multi-threaded LLVM");
    }
}

unsafe fn configure_llvm(sess: &Session) {
    let n_args = sess.opts.cg.llvm_args.len() + sess.target.llvm_args.len();
    let mut llvm_c_strs = Vec::with_capacity(n_args + 1);
    let mut llvm_args = Vec::with_capacity(n_args + 1);

    llvm::LLVMRustInstallFatalErrorHandler();

    fn llvm_arg_to_arg_name(full_arg: &str) -> &str {
        full_arg.trim().split(|c: char| c == '=' || c.is_whitespace()).next().unwrap_or("")
    }

    let cg_opts = sess.opts.cg.llvm_args.iter();
    let tg_opts = sess.target.llvm_args.iter();
    let sess_args = cg_opts.chain(tg_opts);

    let user_specified_args: FxHashSet<_> =
        sess_args.clone().map(|s| llvm_arg_to_arg_name(s)).filter(|s| !s.is_empty()).collect();

    {
        // This adds the given argument to LLVM. Unless `force` is true
        // user specified arguments are *not* overridden.
        let mut add = |arg: &str, force: bool| {
            if force || !user_specified_args.contains(llvm_arg_to_arg_name(arg)) {
                let s = CString::new(arg).unwrap();
                llvm_args.push(s.as_ptr());
                llvm_c_strs.push(s);
            }
        };
        // Set the llvm "program name" to make usage and invalid argument messages more clear.
        add("rustc -Cllvm-args=\"...\" with", true);
        if sess.time_llvm_passes() {
            add("-time-passes", false);
        }
        if sess.print_llvm_passes() {
            add("-debug-pass=Structure", false);
        }
        if !sess.opts.debugging_opts.no_generate_arange_section {
            add("-generate-arange-section", false);
        }
        match sess.opts.debugging_opts.merge_functions.unwrap_or(sess.target.merge_functions) {
            MergeFunctions::Disabled | MergeFunctions::Trampolines => {}
            MergeFunctions::Aliases => {
                add("-mergefunc-use-aliases", false);
            }
        }

        if sess.target.os == "emscripten" && sess.panic_strategy() == PanicStrategy::Unwind {
            add("-enable-emscripten-cxx-exceptions", false);
        }

        // HACK(eddyb) LLVM inserts `llvm.assume` calls to preserve align attributes
        // during inlining. Unfortunately these may block other optimizations.
        add("-preserve-alignment-assumptions-during-inlining=false", false);

        // Use non-zero `import-instr-limit` multiplier for cold callsites.
        add("-import-cold-multiplier=0.1", false);

        for arg in sess_args {
            add(&(*arg), true);
        }
    }

    if sess.opts.debugging_opts.llvm_time_trace {
        // time-trace is not thread safe and running it in parallel will cause seg faults.
        if !sess.opts.debugging_opts.no_parallel_llvm {
            bug!("`-Z llvm-time-trace` requires `-Z no-parallel-llvm")
        }

        llvm::LLVMTimeTraceProfilerInitialize();
    }

    llvm::LLVMInitializePasses();

    rustc_llvm::initialize_available_targets();

    llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr());
}

pub fn time_trace_profiler_finish(file_name: &str) {
    unsafe {
        let file_name = CString::new(file_name).unwrap();
        llvm::LLVMTimeTraceProfilerFinish(file_name.as_ptr());
    }
}

// WARNING: the features after applying `to_llvm_feature` must be known
// to LLVM or the feature detection code will walk past the end of the feature
// array, leading to crashes.
// To find a list of LLVM's names, check llvm-project/llvm/include/llvm/Support/*TargetParser.def
// where the * matches the architecture's name
// Beware to not use the llvm github project for this, but check the git submodule
// found in src/llvm-project
// Though note that Rust can also be build with an external precompiled version of LLVM
// which might lead to failures if the oldest tested / supported LLVM version
// doesn't yet support the relevant intrinsics
pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
    let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch };
    match (arch, s) {
        ("x86", "pclmulqdq") => "pclmul",
        ("x86", "rdrand") => "rdrnd",
        ("x86", "bmi1") => "bmi",
        ("x86", "cmpxchg16b") => "cx16",
        ("x86", "avx512vaes") => "vaes",
        ("x86", "avx512gfni") => "gfni",
        ("x86", "avx512vpclmulqdq") => "vpclmulqdq",
        ("aarch64", "fp") => "fp-armv8",
        ("aarch64", "fp16") => "fullfp16",
        (_, s) => s,
    }
}

pub fn target_features(sess: &Session) -> Vec<Symbol> {
    let target_machine = create_informational_target_machine(sess);
    supported_target_features(sess)
        .iter()
        .filter_map(
            |&(feature, gate)| {
                if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None }
            },
        )
        .filter(|feature| {
            let llvm_feature = to_llvm_feature(sess, feature);
            let cstr = CString::new(llvm_feature).unwrap();
            unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) }
        })
        .map(|feature| Symbol::intern(feature))
        .collect()
}

pub fn print_version() {
    let (major, minor, patch) = get_version();
    println!("LLVM version: {}.{}.{}", major, minor, patch);
}

pub fn get_version() -> (u32, u32, u32) {
    // Can be called without initializing LLVM
    unsafe {
        (llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor(), llvm::LLVMRustVersionPatch())
    }
}

pub fn print_passes() {
    // Can be called without initializing LLVM
    unsafe {
        llvm::LLVMRustPrintPasses();
    }
}

pub(crate) fn print(req: PrintRequest, sess: &Session) {
    require_inited();
    let tm = create_informational_target_machine(sess);
    unsafe {
        match req {
            PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
            PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
            _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
        }
    }
}

fn handle_native(name: &str) -> &str {
    if name != "native" {
        return name;
    }

    unsafe {
        let mut len = 0;
        let ptr = llvm::LLVMRustGetHostCPUName(&mut len);
        str::from_utf8(slice::from_raw_parts(ptr as *const u8, len)).unwrap()
    }
}

pub fn target_cpu(sess: &Session) -> &str {
    let name = sess.opts.cg.target_cpu.as_ref().unwrap_or(&sess.target.cpu);
    handle_native(name)
}

pub fn handle_native_features(sess: &Session) -> Vec<String> {
    match sess.opts.cg.target_cpu {
        Some(ref s) => {
            if s != "native" {
                return vec![];
            }

            let features_string = unsafe {
                let ptr = llvm::LLVMGetHostCPUFeatures();
                let features_string = if !ptr.is_null() {
                    CStr::from_ptr(ptr)
                        .to_str()
                        .unwrap_or_else(|e| {
                            bug!("LLVM returned a non-utf8 features string: {}", e);
                        })
                        .to_owned()
                } else {
                    bug!("could not allocate host CPU features, LLVM returned a `null` string");
                };

                llvm::LLVMDisposeMessage(ptr);

                features_string
            };

            features_string.split(",").map(|s| s.to_owned()).collect()
        }
        None => vec![],
    }
}

pub fn tune_cpu(sess: &Session) -> Option<&str> {
    let name = sess.opts.debugging_opts.tune_cpu.as_ref()?;
    Some(handle_native(name))
}
<|endoftext|>


<commit_before>use gsgdt::{Edge, Graph, Node, NodeStyle};
use rustc_hir::def_id::DefId;
use rustc_index::vec::Idx;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;

/// Convert an MIR function into a gsgdt Graph
pub fn mir_fn_to_generic_graph<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Graph {
    let def_id = body.source.def_id();
    let def_name = graphviz_safe_def_name(def_id);
    let graph_name = format!("Mir_{}", def_name);
    let dark_mode = tcx.sess.opts.debugging_opts.graphviz_dark_mode;

    // Nodes
    let nodes: Vec<Node> = body
        .basic_blocks()
        .iter_enumerated()
        .map(|(block, _)| bb_to_graph_node(block, body, dark_mode))
        .collect();

    // Edges
    let mut edges = Vec::new();
    for (source, _) in body.basic_blocks().iter_enumerated() {
        let def_id = body.source.def_id();
        let terminator = body[source].terminator();
        let labels = terminator.kind.fmt_successor_labels();

        for (&target, label) in terminator.successors().zip(labels) {
            let src = node(def_id, source);
            let trg = node(def_id, target);
            edges.push(Edge::new(src, trg, label.to_string()));
        }
    }

    Graph::new(graph_name, nodes, edges)
}

fn bb_to_graph_node(block: BasicBlock, body: &Body<'_>, dark_mode: bool) -> Node {
    let def_id = body.source.def_id();
    let data = &body[block];
    let label = node(def_id, block);

    let (title, bgcolor) = if data.is_cleanup {
        (format!("{} (cleanup)", block.index()), "lightblue")
    } else {
        let color = if dark_mode { "dimgray" } else { "gray" };
        (format!("{}", block.index()), color)
    };

    let style = NodeStyle { title_bg: Some(bgcolor.to_owned()), ..Default::default() };
    let mut stmts: Vec<String> = data.statements.iter().map(|x| format!("{:?}", x)).collect();

    // add the terminator to the stmts, gsgdt can print it out seperately
    let mut terminator_head = String::new();
    data.terminator().kind.fmt_head(&mut terminator_head).unwrap();
    stmts.push(terminator_head);

    Node::new(stmts, label, title, style)
}

// Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so
// it does not have to be user friendly.
pub fn graphviz_safe_def_name(def_id: DefId) -> String {
    format!("{}_{}", def_id.krate.index(), def_id.index.index(),)
}

fn node(def_id: DefId, block: BasicBlock) -> String {
    format!("bb{}__{}", block.index(), graphviz_safe_def_name(def_id))
}
<commit_msg>add different color for cleanup nodes in dark mode<commit_after>use gsgdt::{Edge, Graph, Node, NodeStyle};
use rustc_hir::def_id::DefId;
use rustc_index::vec::Idx;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;

/// Convert an MIR function into a gsgdt Graph
pub fn mir_fn_to_generic_graph<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Graph {
    let def_id = body.source.def_id();
    let def_name = graphviz_safe_def_name(def_id);
    let graph_name = format!("Mir_{}", def_name);
    let dark_mode = tcx.sess.opts.debugging_opts.graphviz_dark_mode;

    // Nodes
    let nodes: Vec<Node> = body
        .basic_blocks()
        .iter_enumerated()
        .map(|(block, _)| bb_to_graph_node(block, body, dark_mode))
        .collect();

    // Edges
    let mut edges = Vec::new();
    for (source, _) in body.basic_blocks().iter_enumerated() {
        let def_id = body.source.def_id();
        let terminator = body[source].terminator();
        let labels = terminator.kind.fmt_successor_labels();

        for (&target, label) in terminator.successors().zip(labels) {
            let src = node(def_id, source);
            let trg = node(def_id, target);
            edges.push(Edge::new(src, trg, label.to_string()));
        }
    }

    Graph::new(graph_name, nodes, edges)
}

fn bb_to_graph_node(block: BasicBlock, body: &Body<'_>, dark_mode: bool) -> Node {
    let def_id = body.source.def_id();
    let data = &body[block];
    let label = node(def_id, block);

    let (title, bgcolor) = if data.is_cleanup {
        let color = if dark_mode { "royalblue" } else { "lightblue" };
        (format!("{} (cleanup)", block.index()), color)
    } else {
        let color = if dark_mode { "dimgray" } else { "gray" };
        (format!("{}", block.index()), color)
    };

    let style = NodeStyle { title_bg: Some(bgcolor.to_owned()), ..Default::default() };
    let mut stmts: Vec<String> = data.statements.iter().map(|x| format!("{:?}", x)).collect();

    // add the terminator to the stmts, gsgdt can print it out seperately
    let mut terminator_head = String::new();
    data.terminator().kind.fmt_head(&mut terminator_head).unwrap();
    stmts.push(terminator_head);

    Node::new(stmts, label, title, style)
}

// Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so
// it does not have to be user friendly.
pub fn graphviz_safe_def_name(def_id: DefId) -> String {
    format!("{}_{}", def_id.krate.index(), def_id.index.index(),)
}

fn node(def_id: DefId, block: BasicBlock) -> String {
    format!("bb{}__{}", block.index(), graphviz_safe_def_name(def_id))
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A collection of invalidations due to changes in which stylesheets affect a
//! document.

#![deny(unsafe_code)]

use Atom;
use CaseSensitivityExt;
use LocalName as SelectorLocalName;
use dom::{TDocument, TElement, TNode};
use fnv::FnvHashSet;
use invalidation::element::element_wrapper::{ElementSnapshot, ElementWrapper};
use invalidation::element::restyle_hints::RestyleHint;
use media_queries::Device;
use selector_parser::{SelectorImpl, Snapshot, SnapshotMap};
use selectors::attr::CaseSensitivity;
use selectors::parser::{Component, LocalName, Selector};
use shared_lock::SharedRwLockReadGuard;
use stylesheets::{CssRule, StylesheetInDocument};

/// A style sheet invalidation represents a kind of element or subtree that may
/// need to be restyled. Whether it represents a whole subtree or just a single
/// element is determined by whether the invalidation is stored in the
/// StylesheetInvalidationSet's invalid_scopes or invalid_elements table.
#[derive(Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
enum Invalidation {
    /// An element with a given id.
    ID(Atom),
    /// An element with a given class name.
    Class(Atom),
    /// An element with a given local name.
    LocalName { name: SelectorLocalName, lower_name: SelectorLocalName },
}

impl Invalidation {
    fn is_id(&self) -> bool {
        matches!(*self, Invalidation::ID(..))
    }

    fn is_id_or_class(&self) -> bool {
        matches!(*self, Invalidation::ID(..) | Invalidation::Class(..))
    }

    fn matches<E>(
        &self,
        element: E,
        snapshot: Option<&Snapshot>,
        case_sensitivity: CaseSensitivity,
    ) -> bool
    where
        E: TElement,
    {
        match *self {
            Invalidation::Class(ref class) => {
                if element.has_class(class, case_sensitivity) {
                    return true;
                }

                if let Some(snapshot) = snapshot {
                    if snapshot.has_class(class, case_sensitivity) {
                        return true;
                    }
                }
            }
            Invalidation::ID(ref id) => {
                if let Some(ref element_id) = element.get_id() {
                    if case_sensitivity.eq_atom(element_id, id) {
                        return true;
                    }
                }

                if let Some(snapshot) = snapshot {
                    if let Some(ref old_id) = snapshot.id_attr() {
                        if case_sensitivity.eq_atom(old_id, id) {
                            return true;
                        }
                    }
                }
            }
            Invalidation::LocalName { ref name, ref lower_name } => {
                // This could look at the quirks mode of the document, instead
                // of testing against both names, but it's probably not worth
                // it.
                let local_name = element.get_local_name();
                return *local_name == **name || *local_name == **lower_name
            }
        }

        false
    }
}

/// A set of invalidations due to stylesheet additions.
///
/// TODO(emilio): We might be able to do the same analysis for media query
/// changes too (or even selector changes?).
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
pub struct StylesheetInvalidationSet {
    /// The subtrees we know we have to restyle so far.
    invalid_scopes: FnvHashSet<Invalidation>,
    /// The elements we know we have to restyle so far.
    invalid_elements: FnvHashSet<Invalidation>,
    /// Whether the whole document should be restyled.
    fully_invalid: bool,
}

impl StylesheetInvalidationSet {
    /// Create an empty `StylesheetInvalidationSet`.
    pub fn new() -> Self {
        Self {
            invalid_scopes: FnvHashSet::default(),
            invalid_elements: FnvHashSet::default(),
            fully_invalid: false,
        }
    }

    /// Mark the DOM tree styles' as fully invalid.
    pub fn invalidate_fully(&mut self) {
        debug!("StylesheetInvalidationSet::invalidate_fully");
        self.invalid_scopes.clear();
        self.invalid_elements.clear();
        self.fully_invalid = true;
    }

    /// Analyze the given stylesheet, and collect invalidations from their
    /// rules, in order to avoid doing a full restyle when we style the document
    /// next time.
    pub fn collect_invalidations_for<S>(
        &mut self,
        device: &Device,
        stylesheet: &S,
        guard: &SharedRwLockReadGuard
    )
    where
        S: StylesheetInDocument,
    {
        debug!("StylesheetInvalidationSet::collect_invalidations_for");
        if self.fully_invalid {
            debug!(" > Fully invalid already");
            return;
        }

        if !stylesheet.enabled() ||
           !stylesheet.is_effective_for_device(device, guard) {
            debug!(" > Stylesheet was not effective");
            return; // Nothing to do here.
        }

        for rule in stylesheet.effective_rules(device, guard) {
            self.collect_invalidations_for_rule(rule, guard);
            if self.fully_invalid {
                self.invalid_scopes.clear();
                self.invalid_elements.clear();
                break;
            }
        }

        debug!(" > resulting subtree invalidations: {:?}", self.invalid_scopes);
        debug!(" > resulting self invalidations: {:?}", self.invalid_elements);
        debug!(" > fully_invalid: {}", self.fully_invalid);
    }

    /// Clears the invalidation set, invalidating elements as needed if
    /// `document_element` is provided.
    ///
    /// Returns true if any invalidations ocurred.
    pub fn flush<E>(
        &mut self,
        document_element: Option<E>,
        snapshots: Option<&SnapshotMap>,
    ) -> bool
    where
        E: TElement,
    {
        debug!("Stylist::flush({:?}, snapshots: {})", document_element, snapshots.is_some());
        let have_invalidations = match document_element {
            Some(e) => self.process_invalidations(e, snapshots),
            None => false,
        };
        self.clear();
        have_invalidations
    }

    /// Clears the invalidation set without processing.
    pub fn clear(&mut self) {
        self.invalid_scopes.clear();
        self.invalid_elements.clear();
        self.fully_invalid = false;
    }

    fn process_invalidations<E>(&self, element: E, snapshots: Option<&SnapshotMap>) -> bool
    where
        E: TElement,
    {
        debug!(
           "Stylist::process_invalidations({:?}, {:?}, {:?})",
           element,
           self.invalid_scopes,
           self.invalid_elements,
        );

        {
            let mut data = match element.mutate_data() {
                Some(data) => data,
                None => return false,
            };

            if self.fully_invalid {
                debug!("process_invalidations: fully_invalid({:?})",
                       element);
                data.hint.insert(RestyleHint::restyle_subtree());
                return true;
            }
        }

        if self.invalid_scopes.is_empty() && self.invalid_elements.is_empty() {
            debug!("process_invalidations: empty invalidation set");
            return false;
        }

        let case_sensitivity =
            element.as_node().owner_doc().quirks_mode().classes_and_ids_case_sensitivity();
        self.process_invalidations_in_subtree(element, snapshots, case_sensitivity)
    }

    /// Process style invalidations in a given subtree. This traverses the
    /// subtree looking for elements that match the invalidations in
    /// invalid_scopes and invalid_elements.
    ///
    /// Returns whether it invalidated at least one element's style.
    #[allow(unsafe_code)]
    fn process_invalidations_in_subtree<E>(
        &self,
        element: E,
        snapshots: Option<&SnapshotMap>,
        case_sensitivity: CaseSensitivity,
    ) -> bool
    where
        E: TElement,
    {
        debug!("process_invalidations_in_subtree({:?})", element);
        let mut data = match element.mutate_data() {
            Some(data) => data,
            None => return false,
        };

        if !data.has_styles() {
            return false;
        }

        if data.hint.contains_subtree() {
            debug!("process_invalidations_in_subtree: {:?} was already invalid",
                   element);
            return false;
        }

        let element_wrapper = snapshots.map(|s| ElementWrapper::new(element, s));
        let snapshot = element_wrapper.as_ref().and_then(|e| e.snapshot());
        for invalidation in &self.invalid_scopes {
            if invalidation.matches(element, snapshot, case_sensitivity) {
                debug!("process_invalidations_in_subtree: {:?} matched subtree {:?}",
                       element, invalidation);
                data.hint.insert(RestyleHint::restyle_subtree());
                return true;
            }
        }

        let mut self_invalid = false;

        if !data.hint.contains(RestyleHint::RESTYLE_SELF) {
            for invalidation in &self.invalid_elements {
                if invalidation.matches(element, snapshot, case_sensitivity) {
                    debug!("process_invalidations_in_subtree: {:?} matched self {:?}",
                           element, invalidation);
                    data.hint.insert(RestyleHint::RESTYLE_SELF);
                    self_invalid = true;
                    break;
                }
            }
        }

        let mut any_children_invalid = false;

        for child in element.traversal_children() {
            let child = match child.as_element() {
                Some(e) => e,
                None => continue,
            };

            any_children_invalid |=
                self.process_invalidations_in_subtree(child, snapshots, case_sensitivity);
        }

        if any_children_invalid {
            debug!("Children of {:?} changed, setting dirty descendants",
                   element);
            unsafe { element.set_dirty_descendants() }
        }

        return self_invalid || any_children_invalid
    }

    fn scan_component(
        component: &Component<SelectorImpl>,
        invalidation: &mut Option<Invalidation>)
    {
        match *component {
            Component::LocalName(LocalName { ref name, ref lower_name }) => {
                if invalidation.as_ref().map_or(true, |s| !s.is_id_or_class()) {
                    *invalidation = Some(Invalidation::LocalName {
                        name: name.clone(),
                        lower_name: lower_name.clone(),
                    });
                }
            }
            Component::Class(ref class) => {
                if invalidation.as_ref().map_or(true, |s| !s.is_id()) {
                    *invalidation = Some(Invalidation::Class(class.clone()));
                }
            }
            Component::ID(ref id) => {
                if invalidation.is_none() {
                    *invalidation = Some(Invalidation::ID(id.clone()));
                }
            }
            _ => {
                // Ignore everything else, at least for now.
            }
        }
    }

    /// Collect invalidations for a given selector.
    ///
    /// We look at the outermost local name, class, or ID selector to the left
    /// of an ancestor combinator, in order to restyle only a given subtree.
    ///
    /// If the selector has no ancestor combinator, then we do the same for
    /// the only sequence it has, but record it as an element invalidation
    /// instead of a subtree invalidation.
    ///
    /// We prefer IDs to classs, and classes to local names, on the basis
    /// that the former should be more specific than the latter. We also
    /// prefer to generate subtree invalidations for the outermost part
    /// of the selector, to reduce the amount of traversal we need to do
    /// when flushing invalidations.
    fn collect_invalidations(&mut self, selector: &Selector<SelectorImpl>) {
        debug!("StylesheetInvalidationSet::collect_invalidations({:?})", selector);

        let mut element_invalidation: Option<Invalidation> = None;
        let mut subtree_invalidation: Option<Invalidation> = None;

        let mut scan_for_element_invalidation = true;
        let mut scan_for_subtree_invalidation = false;

        let mut iter = selector.iter();

        loop {
            for component in &mut iter {
                if scan_for_element_invalidation {
                    Self::scan_component(component, &mut element_invalidation);
                } else if scan_for_subtree_invalidation {
                    Self::scan_component(component, &mut subtree_invalidation);
                }
            }
            match iter.next_sequence() {
                None => break,
                Some(combinator) => {
                    scan_for_subtree_invalidation = combinator.is_ancestor();
                }
            }
            scan_for_element_invalidation = false;
        }

        if let Some(s) = subtree_invalidation {
            debug!(" > Found subtree invalidation: {:?}", s);
            self.invalid_scopes.insert(s);
        } else if let Some(s) = element_invalidation {
            debug!(" > Found element invalidation: {:?}", s);
            self.invalid_elements.insert(s);
        } else {
            // The selector was of a form that we can't handle. Any element
            // could match it, so let's just bail out.
            debug!(" > Can't handle selector, marking fully invalid");
            self.fully_invalid = true;
        }
    }

    /// Collects invalidations for a given CSS rule.
    fn collect_invalidations_for_rule(
        &mut self,
        rule: &CssRule,
        guard: &SharedRwLockReadGuard)
    {
        use stylesheets::CssRule::*;
        debug!("StylesheetInvalidationSet::collect_invalidations_for_rule");
        debug_assert!(!self.fully_invalid, "Not worth to be here!");

        match *rule {
            Style(ref lock) => {
                let style_rule = lock.read_with(guard);
                for selector in &style_rule.selectors.0 {
                    self.collect_invalidations(selector);
                    if self.fully_invalid {
                        return;
                    }
                }
            }
            Document(..) |
            Namespace(..) |
            Import(..) |
            Media(..) |
            Supports(..) => {
                // Do nothing, relevant nested rules are visited as part of the
                // iteration.
            }
            FontFace(..) |
            CounterStyle(..) |
            Keyframes(..) |
            Page(..) |
            Viewport(..) |
            FontFeatureValues(..) => {
                debug!(" > Found unsupported rule, marking the whole subtree \
                       invalid.");

                // TODO(emilio): Can we do better here?
                //
                // At least in `@page`, we could check the relevant media, I
                // guess.
                self.fully_invalid = true;
            }
        }
    }
}
<commit_msg>style: Make insertion of @font-face rules not necessarily restyle the whole document.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A collection of invalidations due to changes in which stylesheets affect a
//! document.

#![deny(unsafe_code)]

use Atom;
use CaseSensitivityExt;
use LocalName as SelectorLocalName;
use dom::{TDocument, TElement, TNode};
use fnv::FnvHashSet;
use invalidation::element::element_wrapper::{ElementSnapshot, ElementWrapper};
use invalidation::element::restyle_hints::RestyleHint;
use media_queries::Device;
use selector_parser::{SelectorImpl, Snapshot, SnapshotMap};
use selectors::attr::CaseSensitivity;
use selectors::parser::{Component, LocalName, Selector};
use shared_lock::SharedRwLockReadGuard;
use stylesheets::{CssRule, StylesheetInDocument};

/// A style sheet invalidation represents a kind of element or subtree that may
/// need to be restyled. Whether it represents a whole subtree or just a single
/// element is determined by whether the invalidation is stored in the
/// StylesheetInvalidationSet's invalid_scopes or invalid_elements table.
#[derive(Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
enum Invalidation {
    /// An element with a given id.
    ID(Atom),
    /// An element with a given class name.
    Class(Atom),
    /// An element with a given local name.
    LocalName { name: SelectorLocalName, lower_name: SelectorLocalName },
}

impl Invalidation {
    fn is_id(&self) -> bool {
        matches!(*self, Invalidation::ID(..))
    }

    fn is_id_or_class(&self) -> bool {
        matches!(*self, Invalidation::ID(..) | Invalidation::Class(..))
    }

    fn matches<E>(
        &self,
        element: E,
        snapshot: Option<&Snapshot>,
        case_sensitivity: CaseSensitivity,
    ) -> bool
    where
        E: TElement,
    {
        match *self {
            Invalidation::Class(ref class) => {
                if element.has_class(class, case_sensitivity) {
                    return true;
                }

                if let Some(snapshot) = snapshot {
                    if snapshot.has_class(class, case_sensitivity) {
                        return true;
                    }
                }
            }
            Invalidation::ID(ref id) => {
                if let Some(ref element_id) = element.get_id() {
                    if case_sensitivity.eq_atom(element_id, id) {
                        return true;
                    }
                }

                if let Some(snapshot) = snapshot {
                    if let Some(ref old_id) = snapshot.id_attr() {
                        if case_sensitivity.eq_atom(old_id, id) {
                            return true;
                        }
                    }
                }
            }
            Invalidation::LocalName { ref name, ref lower_name } => {
                // This could look at the quirks mode of the document, instead
                // of testing against both names, but it's probably not worth
                // it.
                let local_name = element.get_local_name();
                return *local_name == **name || *local_name == **lower_name
            }
        }

        false
    }
}

/// A set of invalidations due to stylesheet additions.
///
/// TODO(emilio): We might be able to do the same analysis for media query
/// changes too (or even selector changes?).
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
pub struct StylesheetInvalidationSet {
    /// The subtrees we know we have to restyle so far.
    invalid_scopes: FnvHashSet<Invalidation>,
    /// The elements we know we have to restyle so far.
    invalid_elements: FnvHashSet<Invalidation>,
    /// Whether the whole document should be restyled.
    fully_invalid: bool,
}

impl StylesheetInvalidationSet {
    /// Create an empty `StylesheetInvalidationSet`.
    pub fn new() -> Self {
        Self {
            invalid_scopes: FnvHashSet::default(),
            invalid_elements: FnvHashSet::default(),
            fully_invalid: false,
        }
    }

    /// Mark the DOM tree styles' as fully invalid.
    pub fn invalidate_fully(&mut self) {
        debug!("StylesheetInvalidationSet::invalidate_fully");
        self.invalid_scopes.clear();
        self.invalid_elements.clear();
        self.fully_invalid = true;
    }

    /// Analyze the given stylesheet, and collect invalidations from their
    /// rules, in order to avoid doing a full restyle when we style the document
    /// next time.
    pub fn collect_invalidations_for<S>(
        &mut self,
        device: &Device,
        stylesheet: &S,
        guard: &SharedRwLockReadGuard
    )
    where
        S: StylesheetInDocument,
    {
        debug!("StylesheetInvalidationSet::collect_invalidations_for");
        if self.fully_invalid {
            debug!(" > Fully invalid already");
            return;
        }

        if !stylesheet.enabled() ||
           !stylesheet.is_effective_for_device(device, guard) {
            debug!(" > Stylesheet was not effective");
            return; // Nothing to do here.
        }

        for rule in stylesheet.effective_rules(device, guard) {
            self.collect_invalidations_for_rule(rule, guard);
            if self.fully_invalid {
                self.invalid_scopes.clear();
                self.invalid_elements.clear();
                break;
            }
        }

        debug!(" > resulting subtree invalidations: {:?}", self.invalid_scopes);
        debug!(" > resulting self invalidations: {:?}", self.invalid_elements);
        debug!(" > fully_invalid: {}", self.fully_invalid);
    }

    /// Clears the invalidation set, invalidating elements as needed if
    /// `document_element` is provided.
    ///
    /// Returns true if any invalidations ocurred.
    pub fn flush<E>(
        &mut self,
        document_element: Option<E>,
        snapshots: Option<&SnapshotMap>,
    ) -> bool
    where
        E: TElement,
    {
        debug!("Stylist::flush({:?}, snapshots: {})", document_element, snapshots.is_some());
        let have_invalidations = match document_element {
            Some(e) => self.process_invalidations(e, snapshots),
            None => false,
        };
        self.clear();
        have_invalidations
    }

    /// Clears the invalidation set without processing.
    pub fn clear(&mut self) {
        self.invalid_scopes.clear();
        self.invalid_elements.clear();
        self.fully_invalid = false;
    }

    fn process_invalidations<E>(&self, element: E, snapshots: Option<&SnapshotMap>) -> bool
    where
        E: TElement,
    {
        debug!(
           "Stylist::process_invalidations({:?}, {:?}, {:?})",
           element,
           self.invalid_scopes,
           self.invalid_elements,
        );

        {
            let mut data = match element.mutate_data() {
                Some(data) => data,
                None => return false,
            };

            if self.fully_invalid {
                debug!("process_invalidations: fully_invalid({:?})",
                       element);
                data.hint.insert(RestyleHint::restyle_subtree());
                return true;
            }
        }

        if self.invalid_scopes.is_empty() && self.invalid_elements.is_empty() {
            debug!("process_invalidations: empty invalidation set");
            return false;
        }

        let case_sensitivity =
            element.as_node().owner_doc().quirks_mode().classes_and_ids_case_sensitivity();
        self.process_invalidations_in_subtree(element, snapshots, case_sensitivity)
    }

    /// Process style invalidations in a given subtree. This traverses the
    /// subtree looking for elements that match the invalidations in
    /// invalid_scopes and invalid_elements.
    ///
    /// Returns whether it invalidated at least one element's style.
    #[allow(unsafe_code)]
    fn process_invalidations_in_subtree<E>(
        &self,
        element: E,
        snapshots: Option<&SnapshotMap>,
        case_sensitivity: CaseSensitivity,
    ) -> bool
    where
        E: TElement,
    {
        debug!("process_invalidations_in_subtree({:?})", element);
        let mut data = match element.mutate_data() {
            Some(data) => data,
            None => return false,
        };

        if !data.has_styles() {
            return false;
        }

        if data.hint.contains_subtree() {
            debug!("process_invalidations_in_subtree: {:?} was already invalid",
                   element);
            return false;
        }

        let element_wrapper = snapshots.map(|s| ElementWrapper::new(element, s));
        let snapshot = element_wrapper.as_ref().and_then(|e| e.snapshot());
        for invalidation in &self.invalid_scopes {
            if invalidation.matches(element, snapshot, case_sensitivity) {
                debug!("process_invalidations_in_subtree: {:?} matched subtree {:?}",
                       element, invalidation);
                data.hint.insert(RestyleHint::restyle_subtree());
                return true;
            }
        }

        let mut self_invalid = false;

        if !data.hint.contains(RestyleHint::RESTYLE_SELF) {
            for invalidation in &self.invalid_elements {
                if invalidation.matches(element, snapshot, case_sensitivity) {
                    debug!("process_invalidations_in_subtree: {:?} matched self {:?}",
                           element, invalidation);
                    data.hint.insert(RestyleHint::RESTYLE_SELF);
                    self_invalid = true;
                    break;
                }
            }
        }

        let mut any_children_invalid = false;

        for child in element.traversal_children() {
            let child = match child.as_element() {
                Some(e) => e,
                None => continue,
            };

            any_children_invalid |=
                self.process_invalidations_in_subtree(child, snapshots, case_sensitivity);
        }

        if any_children_invalid {
            debug!("Children of {:?} changed, setting dirty descendants",
                   element);
            unsafe { element.set_dirty_descendants() }
        }

        return self_invalid || any_children_invalid
    }

    fn scan_component(
        component: &Component<SelectorImpl>,
        invalidation: &mut Option<Invalidation>)
    {
        match *component {
            Component::LocalName(LocalName { ref name, ref lower_name }) => {
                if invalidation.as_ref().map_or(true, |s| !s.is_id_or_class()) {
                    *invalidation = Some(Invalidation::LocalName {
                        name: name.clone(),
                        lower_name: lower_name.clone(),
                    });
                }
            }
            Component::Class(ref class) => {
                if invalidation.as_ref().map_or(true, |s| !s.is_id()) {
                    *invalidation = Some(Invalidation::Class(class.clone()));
                }
            }
            Component::ID(ref id) => {
                if invalidation.is_none() {
                    *invalidation = Some(Invalidation::ID(id.clone()));
                }
            }
            _ => {
                // Ignore everything else, at least for now.
            }
        }
    }

    /// Collect invalidations for a given selector.
    ///
    /// We look at the outermost local name, class, or ID selector to the left
    /// of an ancestor combinator, in order to restyle only a given subtree.
    ///
    /// If the selector has no ancestor combinator, then we do the same for
    /// the only sequence it has, but record it as an element invalidation
    /// instead of a subtree invalidation.
    ///
    /// We prefer IDs to classs, and classes to local names, on the basis
    /// that the former should be more specific than the latter. We also
    /// prefer to generate subtree invalidations for the outermost part
    /// of the selector, to reduce the amount of traversal we need to do
    /// when flushing invalidations.
    fn collect_invalidations(&mut self, selector: &Selector<SelectorImpl>) {
        debug!("StylesheetInvalidationSet::collect_invalidations({:?})", selector);

        let mut element_invalidation: Option<Invalidation> = None;
        let mut subtree_invalidation: Option<Invalidation> = None;

        let mut scan_for_element_invalidation = true;
        let mut scan_for_subtree_invalidation = false;

        let mut iter = selector.iter();

        loop {
            for component in &mut iter {
                if scan_for_element_invalidation {
                    Self::scan_component(component, &mut element_invalidation);
                } else if scan_for_subtree_invalidation {
                    Self::scan_component(component, &mut subtree_invalidation);
                }
            }
            match iter.next_sequence() {
                None => break,
                Some(combinator) => {
                    scan_for_subtree_invalidation = combinator.is_ancestor();
                }
            }
            scan_for_element_invalidation = false;
        }

        if let Some(s) = subtree_invalidation {
            debug!(" > Found subtree invalidation: {:?}", s);
            self.invalid_scopes.insert(s);
        } else if let Some(s) = element_invalidation {
            debug!(" > Found element invalidation: {:?}", s);
            self.invalid_elements.insert(s);
        } else {
            // The selector was of a form that we can't handle. Any element
            // could match it, so let's just bail out.
            debug!(" > Can't handle selector, marking fully invalid");
            self.fully_invalid = true;
        }
    }

    /// Collects invalidations for a given CSS rule.
    fn collect_invalidations_for_rule(
        &mut self,
        rule: &CssRule,
        guard: &SharedRwLockReadGuard)
    {
        use stylesheets::CssRule::*;
        debug!("StylesheetInvalidationSet::collect_invalidations_for_rule");
        debug_assert!(!self.fully_invalid, "Not worth to be here!");

        match *rule {
            Style(ref lock) => {
                let style_rule = lock.read_with(guard);
                for selector in &style_rule.selectors.0 {
                    self.collect_invalidations(selector);
                    if self.fully_invalid {
                        return;
                    }
                }
            }
            Document(..) |
            Namespace(..) |
            Import(..) |
            Media(..) |
            Supports(..) => {
                // Do nothing, relevant nested rules are visited as part of the
                // iteration.
            }
            FontFace(..) => {
                // Do nothing, @font-face doesn't affect computed style
                // information. We'll restyle when the font face loads, if
                // needed.
            }
            Keyframes(..) |
            CounterStyle(..) |
            Page(..) |
            Viewport(..) |
            FontFeatureValues(..) => {
                debug!(" > Found unsupported rule, marking the whole subtree \
                       invalid.");

                // TODO(emilio): Can we do better here?
                //
                // At least in `@page`, we could check the relevant media, I
                // guess.
                self.fully_invalid = true;
            }
        }
    }
}
<|endoftext|>


<commit_before>
pub fn key_xor(data: &[u8], key: u8) -> Vec<u8> {
    data.iter().map(|&x| x ^ key ).collect()
}

fn rel_square_dist(values1: &[f64], values2: &[f64]) -> f64 {
    values1.iter()
           .zip(values2.iter())
           .fold(0.0, |s, (&a, &b)| {
               let rel = if a != 0.0 {b/a - 1.0} else {1.0};
               s + rel * rel
           })
           .sqrt()
}

fn count_letters(data: &[u8]) -> Vec<uint> {
    let mut act_count = Vec::from_fn(26, |x| 0 * x );

    for c in data.iter() {
        match *c as uint {
            uc@65...90 => act_count[uc-65] += 1,
            lc@97...122 => act_count[lc-97] += 1,
            _ => ()
        }
    }

    act_count
}

pub fn score(data: &[u8]) -> f64 {
    // normal frequencies of english letters a-z in %
    let nom_frequencies : &[f64] = [ 8.167, 1.492, 2.782, 4.253, 12.702, 2.228, 2.015, 6.094, 6.966, 0.153, 0.772, 4.025,
        2.406, 6.749, 7.507, 1.929, 0.095, 5.987, 6.327, 9.056, 2.758, 0.978, 2.360, 0.150, 1.974, 0.074 ];

    let act_count = count_letters(data);
    let total = act_count.iter().fold(0, |s, &a| s + a);

    if total == 0 {
        // no characters found at all
        return data.len() as f64;
    }

    let act_frequencies : Vec<f64> = act_count.iter().map(|&v| (v as f64) * 100f64 / (total as f64)).collect();

    (data.len() - total) as f64 + rel_square_dist(nom_frequencies, act_frequencies.as_slice())
}

pub fn decode_xor(data: &[u8]) -> (Vec<u8>, u8) {
    let mut best_score = 100.0f64;
    let mut best_result = vec![];
    let mut best_key = 0u8;

    for key in range(0u8, 255u8) {
        let plain = key_xor(data, key);
        let unprintable : uint = plain.iter().fold(0, |s, &c| s + if c < 32 { 1 } else { 0 } );

        // unprintable characters are out immediately
        if unprintable > 0 {
            continue;
        }

        let new_score = score(plain.as_slice());

        if new_score < best_score {
            best_result = plain;
            best_score = new_score;
            best_key = key;
        }
    }

    (best_result, best_key)
}

#[test]
fn test_key_xor() {
    assert_eq!(key_xor([255, 128, 0], 64), vec![191, 192, 64]);
}

#[test]
fn test_rel_square_dist() {
    assert_eq!(rel_square_dist([],[]), 0.0f64);
    assert_eq!(rel_square_dist([1.0, 1.0],[1.0, 1.0]), 0.0);
    assert_eq!(rel_square_dist([0.0, 1.0],[1.0, 0.0]), 2.0.sqrt());
    assert_eq!(rel_square_dist([-1.0, 1.0, 1.0],[1.0, -1.0, 0.0]), 3.0);}

#[test]
fn test_count_letters() {
    assert_eq!(count_letters([]), vec![0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
    assert_eq!(count_letters(b"abcdabc"), vec![2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
    assert_eq!(count_letters(b"zZzZxXxX"), vec![0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,4]);
    assert_eq!(count_letters(b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), vec![2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]);
}

#[test]
fn test_score_basics() {
    assert_eq!(score([]), score(b"232093582$%$!-_.,") );
    assert!(score([]) > score(b"A") );
    assert!(score(b"this is the end, my friend") < score(b"7ufhgvbnftz56ufgvghtzuh54") );
    assert_eq!(score(b"this is the end, my friend"), score(b"endmythisfriend!!!theis.") );
}
<commit_msg>Improve scoring function a bit by making invalid letters worse<commit_after>
pub fn key_xor(data: &[u8], key: u8) -> Vec<u8> {
    data.iter().map(|&x| x ^ key ).collect()
}

fn rel_square_dist(values1: &[f64], values2: &[f64]) -> f64 {
    values1.iter()
           .zip(values2.iter())
           .fold(0.0, |s, (&a, &b)| {
               let rel = if a != 0.0 { b/a - 1.0 } else { 1.0 };
               s + rel * rel
           })
           .sqrt()
}

fn count_letters(data: &[u8]) -> Vec<uint> {
    let mut act_count = Vec::from_fn(26, |x| 0 * x );

    for c in data.iter() {
        match *c as uint {
            uc@65...90 => act_count[uc-65] += 1,
            lc@97...122 => act_count[lc-97] += 1,
            _ => ()
        }
    }

    act_count
}

pub fn score(data: &[u8]) -> f64 {
    // normal frequencies of english letters a-z in %
    let nom_frequencies : &[f64] = [ 8.167, 1.492, 2.782, 4.253, 12.702, 2.228, 2.015, 6.094, 6.966, 0.153, 0.772, 4.025,
        2.406, 6.749, 7.507, 1.929, 0.095, 5.987, 6.327, 9.056, 2.758, 0.978, 2.360, 0.150, 1.974, 0.074 ];

    let act_count = count_letters(data);
    let total = act_count.iter().fold(0, |s, &a| s + a);

    if total == 0 {
        // no characters found at all
        return data.len() as f64 * 100.0;
    }

    let act_frequencies : Vec<f64> = act_count.iter().map(|&v| (v as f64) * 100f64 / (total as f64)).collect();

    (data.len() - total) as f64 + rel_square_dist(nom_frequencies, act_frequencies.as_slice())
}

pub fn decode_xor(data: &[u8]) -> (Vec<u8>, u8) {
    let mut best_score = 100.0f64;
    let mut best_result = vec![];
    let mut best_key = 0u8;

    for key in range(0u8, 255u8) {
        let plain = key_xor(data, key);
        let unprintable = plain.iter().filter( |&c| *c < 10 ).count();

        // unprintable characters are out immediately
        if unprintable > 0 {
            continue;
        }

        // score the remaining possibilities
        let new_score = score(plain.as_slice());

        if new_score < best_score {
            best_result = plain;
            best_score = new_score;
            best_key = key;
        }
    }

    (best_result, best_key)
}

#[test]
fn test_key_xor() {
    assert_eq!(key_xor([255, 128, 0], 64), vec![191, 192, 64]);
}

#[test]
fn test_rel_square_dist() {
    assert_eq!(rel_square_dist([],[]), 0.0f64);
    assert_eq!(rel_square_dist([1.0, 1.0],[1.0, 1.0]), 0.0);
    assert_eq!(rel_square_dist([0.0, 1.0],[1.0, 0.0]), 2.0.sqrt());
    assert_eq!(rel_square_dist([-1.0, 1.0, 1.0],[1.0, -1.0, 0.0]), 3.0);}

#[test]
fn test_count_letters() {
    assert_eq!(count_letters([]), vec![0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
    assert_eq!(count_letters(b"abcdabc"), vec![2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
    assert_eq!(count_letters(b"zZzZxXxX"), vec![0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,4]);
    assert_eq!(count_letters(b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), vec![2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]);
}

#[test]
fn test_score_basics() {
    assert_eq!(score([]), score(b"232093582$%$!-_.,") );
    assert!(score([]) > score(b"A") );
    assert!(score(b"this is the end, my friend") < score(b"7ufhgvbnftz56ufgvghtzuh54") );
    assert_eq!(score(b"this is the end, my friend"), score(b"endmythisfriend!!!theis.") );
}

#[test]
fn test_score_challenge() {
    assert!( score([11, 42, 50, 101, 49, 45, 36, 49, 101, 49, 45, 32, 101, 53, 36, 55, 49, 60, 101, 44, 54, 101, 47, 48, 40, 53, 44, 43, 34, 79])
           > score([78, 111, 119, 32, 116, 104, 97, 116, 32, 116, 104, 101, 32, 112, 97, 114, 116, 121, 32, 105, 115, 32, 106, 117, 109, 112, 105, 110, 103, 10]) )
}
<|endoftext|>


<commit_before>use super::{success_response, ApiResult};
use crate::{helpers::*, ApiError, UrlQuery};
use beacon_chain::BeaconChainTypes;
use bls::{AggregateSignature, PublicKey, Signature};
use hyper::{Body, Request};
use serde::{Deserialize, Serialize};
use types::beacon_state::EthSpec;
use types::{Attestation, BitList, Epoch, RelativeEpoch, Shard, Slot};

#[derive(Debug, Serialize, Deserialize)]
pub struct ValidatorDuty {
    /// The validator's BLS public key, uniquely identifying them. _48-bytes, hex encoded with 0x prefix, case insensitive._
    pub validator_pubkey: String,
    /// The slot at which the validator must attest.
    pub attestation_slot: Option<Slot>,
    /// The shard in which the validator must attest.
    pub attestation_shard: Option<Shard>,
    /// The slot in which a validator must propose a block, or `null` if block production is not required.
    pub block_proposal_slot: Option<Slot>,
}

impl ValidatorDuty {
    pub fn new() -> ValidatorDuty {
        ValidatorDuty {
            validator_pubkey: "".to_string(),
            attestation_slot: None,
            attestation_shard: None,
            block_proposal_slot: None,
        }
    }
}

/// HTTP Handler to retrieve a the duties for a set of validators during a particular epoch
pub fn get_validator_duties<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult {
    let beacon_chain = get_beacon_chain_from_request::<T>(&req)?;
    let head_state = &beacon_chain.head().beacon_state;

    // Parse and check query parameters
    let query = UrlQuery::from_request(&req)?;
    let current_epoch = head_state.current_epoch();
    let epoch = match query.first_of(&["epoch"]) {
        Ok((_, v)) => Epoch::new(v.parse::<u64>().map_err(|e| {
            ApiError::InvalidQueryParams(format!("Invalid epoch parameter, must be a u64. {:?}", e))
        })?),
        Err(_) => {
            // epoch not supplied, use the current epoch
            current_epoch
        }
    };
    let relative_epoch = RelativeEpoch::from_epoch(current_epoch, epoch).map_err(|e| {
        ApiError::InvalidQueryParams(format!(
            "Cannot get RelativeEpoch, epoch out of range: {:?}",
            e
        ))
    })?;
    let validators: Vec<PublicKey> = match query.all_of("validator_pubkeys") {
        Ok(v) => v
            .iter()
            .map(|pk| parse_pubkey(pk))
            .collect::<Result<Vec<_>, _>>()?,
        Err(e) => {
            return Err(e);
        }
    };
    let mut duties: Vec<ValidatorDuty> = Vec::new();

    // Get a list of all validators for this epoch
    let validator_proposers: Vec<usize> = epoch
        .slot_iter(T::EthSpec::slots_per_epoch())
        .map(|slot| {
            head_state
                .get_beacon_proposer_index(slot, relative_epoch, &beacon_chain.spec)
                .map_err(|e| {
                    ApiError::ServerError(format!(
                        "Unable to get proposer index for validator: {:?}",
                        e
                    ))
                })
        })
        .collect::<Result<Vec<usize>, _>>()?;

    // Look up duties for each validator
    for val_pk in validators {
        let mut duty = ValidatorDuty::new();
        duty.validator_pubkey = val_pk.as_hex_string();

        // Get the validator index
        // If it does not exist in the index, just add a null duty and move on.
        let val_index: usize = match head_state.get_validator_index(&val_pk) {
            Ok(Some(i)) => i,
            Ok(None) => {
                duties.append(&mut vec![duty]);
                continue;
            }
            Err(e) => {
                return Err(ApiError::ServerError(format!(
                    "Unable to read validator index cache. {:?}",
                    e
                )));
            }
        };

        // Set attestation duties
        match head_state.get_attestation_duties(val_index, relative_epoch) {
            Ok(Some(d)) => {
                duty.attestation_slot = Some(d.slot);
                duty.attestation_shard = Some(d.shard);
            }
            Ok(None) => {}
            Err(e) => {
                return Err(ApiError::ServerError(format!(
                    "unable to read cache for attestation duties: {:?}",
                    e
                )))
            }
        };

        // If the validator is to propose a block, identify the slot
        if let Some(slot) = validator_proposers.iter().position(|&v| val_index == v) {
            duty.block_proposal_slot = Some(Slot::new(
                relative_epoch
                    .into_epoch(current_epoch)
                    .start_slot(T::EthSpec::slots_per_epoch())
                    .as_u64()
                    + slot as u64,
            ));
        }

        duties.append(&mut vec![duty]);
    }
    let body = Body::from(
        serde_json::to_string(&duties)
            .expect("We should always be able to serialize the duties we created."),
    );
    Ok(success_response(body))
}

/// HTTP Handler to produce a new BeaconBlock from the current state, ready to be signed by a validator.
pub fn get_new_beacon_block<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult {
    let beacon_chain = get_beacon_chain_from_request::<T>(&req)?;

    let query = UrlQuery::from_request(&req)?;
    let slot = match query.first_of(&["slot"]) {
        Ok((_, v)) => Slot::new(v.parse::<u64>().map_err(|e| {
            ApiError::InvalidQueryParams(format!("Invalid slot parameter, must be a u64. {:?}", e))
        })?),
        Err(e) => {
            return Err(e);
        }
    };
    let randao_reveal = match query.first_of(&["randao_reveal"]) {
        Ok((_, v)) => Signature::from_bytes(
            hex::decode(&v)
                .map_err(|e| {
                    ApiError::InvalidQueryParams(format!(
                        "Invalid hex string for randao_reveal: {:?}",
                        e
                    ))
                })?
                .as_slice(),
        )
        .map_err(|e| {
            ApiError::InvalidQueryParams(format!("randao_reveal is not a valid signature: {:?}", e))
        })?,
        Err(e) => {
            return Err(e);
        }
    };

    let new_block = match beacon_chain.produce_block(randao_reveal, slot) {
        Ok((block, _state)) => block,
        Err(e) => {
            return Err(ApiError::ServerError(format!(
                "Beacon node is not able to produce a block: {:?}",
                e
            )));
        }
    };

    let body = Body::from(
        serde_json::to_string(&new_block)
            .expect("We should always be able to serialize a new block that we produced."),
    );
    Ok(success_response(body))
}

/// HTTP Handler to produce a new Attestation from the current state, ready to be signed by a validator.
pub fn get_new_attestation<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult {
    let beacon_chain = get_beacon_chain_from_request::<T>(&req)?;
    let head_state = &beacon_chain.head().beacon_state;

    let query = UrlQuery::from_request(&req)?;
    let val_pk: PublicKey = match query.first_of(&["validator_pubkey"]) {
        Ok((_, v)) => parse_pubkey(v.as_str())?,
        Err(e) => {
            return Err(e);
        }
    };
    // Get the validator index from the supplied public key
    // If it does not exist in the index, we cannot continue.
    let val_index: usize = match head_state.get_validator_index(&val_pk) {
        Ok(Some(i)) => i,
        Ok(None) => {
            return Err(ApiError::InvalidQueryParams(
                "The provided validator public key does not correspond to a validator index."
                    .into(),
            ));
        }
        Err(e) => {
            return Err(ApiError::ServerError(format!(
                "Unable to read validator index cache. {:?}",
                e
            )));
        }
    };
    // Get the duties of the validator, to make sure they match up.
    // If they don't have duties this epoch, then return an error
    let val_duty = match head_state.get_attestation_duties(val_index, RelativeEpoch::Current) {
        Ok(Some(d)) => d,
        Ok(None) => {
            return Err(ApiError::InvalidQueryParams("No validator duties could be found for the requested validator. Cannot provide valid attestation.".into()));
        }
        Err(e) => {
            return Err(ApiError::ServerError(format!(
                "unable to read cache for attestation duties: {:?}",
                e
            )))
        }
    };

    // Check that we are requesting an attestation during the slot where it is relevant.
    let present_slot = match beacon_chain.read_slot_clock() {
        Some(s) => s,
        None => {
            return Err(ApiError::ServerError(
                "Beacon node is unable to determine present slot, either the state isn't generated or the chain hasn't begun.".into()
            ));
        }
    };
    if val_duty.slot != present_slot {
        return Err(ApiError::InvalidQueryParams(format!("Validator is only able to request an attestation during the slot they are allocated. Current slot: {:?}, allocated slot: {:?}", head_state.slot, val_duty.slot)));
    }

    // Parse the POC bit and insert it into the aggregation bits
    let poc_bit: bool = match query.first_of(&["poc_bit"]) {
        Ok((_, v)) => v.parse::<bool>().map_err(|e| {
            ApiError::InvalidQueryParams(format!("poc_bit is not a valid boolean value: {:?}", e))
        })?,
        Err(e) => {
            return Err(e);
        }
    };
    let mut aggregation_bits = BitList::with_capacity(val_duty.committee_len)
        .expect("An empty BitList should always be created, or we have bigger problems.");
    aggregation_bits
        .set(val_duty.committee_index, poc_bit)
        .map_err(|e| {
            ApiError::ServerError(format!(
                "Unable to set aggregation bits for the attestation: {:?}",
                e
            ))
        })?;

    // Allow a provided slot parameter to check against the expected slot as a sanity check.
    // Presently, we don't support attestations at future or past slots.
    let _slot = match query.first_of(&["slot"]) {
        Ok((_, v)) => {
            let requested_slot = v.parse::<u64>().map_err(|e| {
                ApiError::InvalidQueryParams(format!(
                    "Invalid slot parameter, must be a u64. {:?}",
                    e
                ))
            })?;
            let current_slot = beacon_chain.head().beacon_state.slot.as_u64();
            if requested_slot != current_slot {
                return Err(ApiError::InvalidQueryParams(format!("Attestation data can only be requested for the current slot ({:?}), not your requested slot ({:?})", current_slot, requested_slot)));
            }
            Slot::new(requested_slot)
        }
        Err(ApiError::InvalidQueryParams(_)) => {
            // Just fill _slot with a dummy value for now, making the slot parameter optional
            // We'll get the real slot from the ValidatorDuty
            Slot::new(0)
        }
        Err(e) => {
            return Err(e);
        }
    };

    let shard: Shard = match query.first_of(&["shard"]) {
        Ok((_, v)) => v.parse::<u64>().map_err(|e| {
            ApiError::InvalidQueryParams(format!("Shard is not a valid u64 value: {:?}", e))
        })?,
        Err(e) => {
            // This is a mandatory parameter, return the error
            return Err(e);
        }
    };
    let attestation_data = match beacon_chain.produce_attestation_data(shard) {
        Ok(v) => v,
        Err(e) => {
            return Err(ApiError::ServerError(format!(
                "Could not produce an attestation: {:?}",
                e
            )));
        }
    };

    let attestation: Attestation<T::EthSpec> = Attestation {
        aggregation_bits,
        data: attestation_data,
        custody_bits: BitList::with_capacity(val_duty.committee_len)
            .expect("Should be able to create an empty BitList for the custody bits."),
        signature: AggregateSignature::new(),
    };

    let body = Body::from(
        serde_json::to_string(&attestation)
            .expect("We should always be able to serialize a new attestation that we produced."),
    );
    Ok(success_response(body))
}
<commit_msg>Replaced unnecessary match statements with map_err and ok_or<commit_after>use super::{success_response, ApiResult};
use crate::{helpers::*, ApiError, UrlQuery};
use beacon_chain::BeaconChainTypes;
use bls::{AggregateSignature, PublicKey, Signature};
use hyper::{Body, Request};
use serde::{Deserialize, Serialize};
use types::beacon_state::EthSpec;
use types::{Attestation, BitList, Epoch, RelativeEpoch, Shard, Slot};

#[derive(Debug, Serialize, Deserialize)]
pub struct ValidatorDuty {
    /// The validator's BLS public key, uniquely identifying them. _48-bytes, hex encoded with 0x prefix, case insensitive._
    pub validator_pubkey: String,
    /// The slot at which the validator must attest.
    pub attestation_slot: Option<Slot>,
    /// The shard in which the validator must attest.
    pub attestation_shard: Option<Shard>,
    /// The slot in which a validator must propose a block, or `null` if block production is not required.
    pub block_proposal_slot: Option<Slot>,
}

impl ValidatorDuty {
    pub fn new() -> ValidatorDuty {
        ValidatorDuty {
            validator_pubkey: "".to_string(),
            attestation_slot: None,
            attestation_shard: None,
            block_proposal_slot: None,
        }
    }
}

/// HTTP Handler to retrieve a the duties for a set of validators during a particular epoch
pub fn get_validator_duties<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult {
    let beacon_chain = get_beacon_chain_from_request::<T>(&req)?;
    let head_state = &beacon_chain.head().beacon_state;

    // Parse and check query parameters
    let query = UrlQuery::from_request(&req)?;
    let current_epoch = head_state.current_epoch();
    let epoch = match query.first_of(&["epoch"]) {
        Ok((_, v)) => Epoch::new(v.parse::<u64>().map_err(|e| {
            ApiError::InvalidQueryParams(format!("Invalid epoch parameter, must be a u64. {:?}", e))
        })?),
        Err(_) => {
            // epoch not supplied, use the current epoch
            current_epoch
        }
    };
    let relative_epoch = RelativeEpoch::from_epoch(current_epoch, epoch).map_err(|e| {
        ApiError::InvalidQueryParams(format!(
            "Cannot get RelativeEpoch, epoch out of range: {:?}",
            e
        ))
    })?;
    let validators: Vec<PublicKey> = query
        .all_of("validator_pubkeys")?
        .iter()
        .map(|pk| parse_pubkey(pk))
        .collect::<Result<Vec<_>, _>>()?;
    let mut duties: Vec<ValidatorDuty> = Vec::new();

    // Get a list of all validators for this epoch
    let validator_proposers: Vec<usize> = epoch
        .slot_iter(T::EthSpec::slots_per_epoch())
        .map(|slot| {
            head_state
                .get_beacon_proposer_index(slot, relative_epoch, &beacon_chain.spec)
                .map_err(|e| {
                    ApiError::ServerError(format!(
                        "Unable to get proposer index for validator: {:?}",
                        e
                    ))
                })
        })
        .collect::<Result<Vec<usize>, _>>()?;

    // Look up duties for each validator
    for val_pk in validators {
        let mut duty = ValidatorDuty::new();
        duty.validator_pubkey = val_pk.as_hex_string();

        // Get the validator index
        // If it does not exist in the index, just add a null duty and move on.
        let val_index: usize = match head_state.get_validator_index(&val_pk) {
            Ok(Some(i)) => i,
            Ok(None) => {
                duties.append(&mut vec![duty]);
                continue;
            }
            Err(e) => {
                return Err(ApiError::ServerError(format!(
                    "Unable to read validator index cache. {:?}",
                    e
                )));
            }
        };

        // Set attestation duties
        match head_state.get_attestation_duties(val_index, relative_epoch) {
            Ok(Some(d)) => {
                duty.attestation_slot = Some(d.slot);
                duty.attestation_shard = Some(d.shard);
            }
            Ok(None) => {}
            Err(e) => {
                return Err(ApiError::ServerError(format!(
                    "unable to read cache for attestation duties: {:?}",
                    e
                )))
            }
        };

        // If the validator is to propose a block, identify the slot
        if let Some(slot) = validator_proposers.iter().position(|&v| val_index == v) {
            duty.block_proposal_slot = Some(Slot::new(
                relative_epoch
                    .into_epoch(current_epoch)
                    .start_slot(T::EthSpec::slots_per_epoch())
                    .as_u64()
                    + slot as u64,
            ));
        }

        duties.append(&mut vec![duty]);
    }
    let body = Body::from(
        serde_json::to_string(&duties)
            .expect("We should always be able to serialize the duties we created."),
    );
    Ok(success_response(body))
}

/// HTTP Handler to produce a new BeaconBlock from the current state, ready to be signed by a validator.
pub fn get_new_beacon_block<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult {
    let beacon_chain = get_beacon_chain_from_request::<T>(&req)?;

    let query = UrlQuery::from_request(&req)?;
    let slot = match query.first_of(&["slot"]) {
        Ok((_, v)) => Slot::new(v.parse::<u64>().map_err(|e| {
            ApiError::InvalidQueryParams(format!("Invalid slot parameter, must be a u64. {:?}", e))
        })?),
        Err(e) => {
            return Err(e);
        }
    };
    let randao_reveal = match query.first_of(&["randao_reveal"]) {
        Ok((_, v)) => Signature::from_bytes(
            hex::decode(&v)
                .map_err(|e| {
                    ApiError::InvalidQueryParams(format!(
                        "Invalid hex string for randao_reveal: {:?}",
                        e
                    ))
                })?
                .as_slice(),
        )
        .map_err(|e| {
            ApiError::InvalidQueryParams(format!("randao_reveal is not a valid signature: {:?}", e))
        })?,
        Err(e) => {
            return Err(e);
        }
    };

    let (new_block, _state) = beacon_chain
        .produce_block(randao_reveal, slot)
        .map_err(|e| {
            ApiError::ServerError(format!(
                "Beacon node is not able to produce a block: {:?}",
                e
            ))
        })?;

    let body = Body::from(
        serde_json::to_string(&new_block)
            .expect("We should always be able to serialize a new block that we produced."),
    );
    Ok(success_response(body))
}

/// HTTP Handler to produce a new Attestation from the current state, ready to be signed by a validator.
pub fn get_new_attestation<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult {
    let beacon_chain = get_beacon_chain_from_request::<T>(&req)?;
    let head_state = &beacon_chain.head().beacon_state;

    let query = UrlQuery::from_request(&req)?;
    let val_pk: PublicKey = match query.first_of(&["validator_pubkey"]) {
        Ok((_, v)) => parse_pubkey(v.as_str())?,
        Err(e) => {
            return Err(e);
        }
    };
    // Get the validator index from the supplied public key
    // If it does not exist in the index, we cannot continue.
    let val_index: usize = match head_state.get_validator_index(&val_pk) {
        Ok(Some(i)) => i,
        Ok(None) => {
            return Err(ApiError::InvalidQueryParams(
                "The provided validator public key does not correspond to a validator index."
                    .into(),
            ));
        }
        Err(e) => {
            return Err(ApiError::ServerError(format!(
                "Unable to read validator index cache. {:?}",
                e
            )));
        }
    };
    // Get the duties of the validator, to make sure they match up.
    // If they don't have duties this epoch, then return an error
    let val_duty = match head_state.get_attestation_duties(val_index, RelativeEpoch::Current) {
        Ok(Some(d)) => d,
        Ok(None) => {
            return Err(ApiError::InvalidQueryParams("No validator duties could be found for the requested validator. Cannot provide valid attestation.".into()));
        }
        Err(e) => {
            return Err(ApiError::ServerError(format!(
                "unable to read cache for attestation duties: {:?}",
                e
            )))
        }
    };

    // Check that we are requesting an attestation during the slot where it is relevant.
    let present_slot = beacon_chain.read_slot_clock().ok_or(ApiError::ServerError(
        "Beacon node is unable to determine present slot, either the state isn't generated or the chain hasn't begun.".into()
    ))?;
    if val_duty.slot != present_slot {
        return Err(ApiError::InvalidQueryParams(format!("Validator is only able to request an attestation during the slot they are allocated. Current slot: {:?}, allocated slot: {:?}", head_state.slot, val_duty.slot)));
    }

    // Parse the POC bit and insert it into the aggregation bits
    let poc_bit: bool = match query.first_of(&["poc_bit"]) {
        Ok((_, v)) => v.parse::<bool>().map_err(|e| {
            ApiError::InvalidQueryParams(format!("poc_bit is not a valid boolean value: {:?}", e))
        })?,
        Err(e) => {
            return Err(e);
        }
    };
    let mut aggregation_bits = BitList::with_capacity(val_duty.committee_len)
        .expect("An empty BitList should always be created, or we have bigger problems.");
    aggregation_bits
        .set(val_duty.committee_index, poc_bit)
        .map_err(|e| {
            ApiError::ServerError(format!(
                "Unable to set aggregation bits for the attestation: {:?}",
                e
            ))
        })?;

    // Allow a provided slot parameter to check against the expected slot as a sanity check.
    // Presently, we don't support attestations at future or past slots.
    let _slot = match query.first_of(&["slot"]) {
        Ok((_, v)) => {
            let requested_slot = v.parse::<u64>().map_err(|e| {
                ApiError::InvalidQueryParams(format!(
                    "Invalid slot parameter, must be a u64. {:?}",
                    e
                ))
            })?;
            let current_slot = beacon_chain.head().beacon_state.slot.as_u64();
            if requested_slot != current_slot {
                return Err(ApiError::InvalidQueryParams(format!("Attestation data can only be requested for the current slot ({:?}), not your requested slot ({:?})", current_slot, requested_slot)));
            }
            Slot::new(requested_slot)
        }
        Err(ApiError::InvalidQueryParams(_)) => {
            // Just fill _slot with a dummy value for now, making the slot parameter optional
            // We'll get the real slot from the ValidatorDuty
            Slot::new(0)
        }
        Err(e) => {
            return Err(e);
        }
    };

    let shard: Shard = match query.first_of(&["shard"]) {
        Ok((_, v)) => v.parse::<u64>().map_err(|e| {
            ApiError::InvalidQueryParams(format!("Shard is not a valid u64 value: {:?}", e))
        })?,
        Err(e) => {
            // This is a mandatory parameter, return the error
            return Err(e);
        }
    };
    let attestation_data = beacon_chain
        .produce_attestation_data(shard)
        .map_err(|e| ApiError::ServerError(format!("Could not produce an attestation: {:?}", e)))?;

    let attestation: Attestation<T::EthSpec> = Attestation {
        aggregation_bits,
        data: attestation_data,
        custody_bits: BitList::with_capacity(val_duty.committee_len)
            .expect("Should be able to create an empty BitList for the custody bits."),
        signature: AggregateSignature::new(),
    };

    let body = Body::from(
        serde_json::to_string(&attestation)
            .expect("We should always be able to serialize a new attestation that we produced."),
    );
    Ok(success_response(body))
}
<|endoftext|>


<commit_before>use std;

fn isqrt(n: u64) -> u64 {
    let (min, max) = (0u64, n);
    while min < max {
        let mid = (min + max + 1u64) / 2u64;
        if (mid * mid) == n {
            ret mid;
        } else if (mid * mid) >= n {
            max = mid - 1u64;
        } else {
            min = mid;
        }
    }
    ret min;
}

fn find_pyrhagorean(sum: u64) -> [(u64, u64, u64)] {
    let answer = [];
    uint::range(2u64, sum - 2u) { |c|
        uint::range(1u64, (sum - c) / 2u) { |a|
            let b = sum - c - a;
            if a * a + b * b == c * c {
                answer += [(a, b, c)];
            }
        }
    }
    ret answer;
}

fn main() {
    for (a, b, c) in find_pyrhagorean(1000u) {
        std::io::println(#fmt("%u^2 + %u^2 = %u^2", a, b, c));
        std::io::println(#fmt("prod: %u", a * b * c));
    }
}
<commit_msg>Delete definition of `isqrt'<commit_after>use std;

fn find_pyrhagorean(sum: u64) -> [(u64, u64, u64)] {
    let answer = [];
    uint::range(2u64, sum - 2u) { |c|
        uint::range(1u64, (sum - c) / 2u) { |a|
            let b = sum - c - a;
            if a * a + b * b == c * c {
                answer += [(a, b, c)];
            }
        }
    }
    ret answer;
}

fn main() {
    for (a, b, c) in find_pyrhagorean(1000u) {
        std::io::println(#fmt("%u^2 + %u^2 = %u^2", a, b, c));
        std::io::println(#fmt("prod: %u", a * b * c));
    }
}
<|endoftext|>


<commit_before>#![no_main]

use arbitrary::Arbitrary;
use libfuzzer_sys::fuzz_target;

#[derive(Arbitrary, Debug)]
enum IntegerInput {
    I8(i8),
    U8(u8),
    I16(i16),
    U16(u16),
    I32(i32),
    U32(u32),
    I64(i64),
    U64(u64),
    I128(i128),
    U128(u128),
    ISIZE(isize),
    USIZE(usize),
}

fuzz_target!(|input: IntegerInput| {
    let mut buffer = itoa::Buffer::new();
    match input {
        IntegerInput::I8(val) => buffer.format(val),
        IntegerInput::U8(val) => buffer.format(val),
        IntegerInput::I16(val) => buffer.format(val),
        IntegerInput::U16(val) => buffer.format(val),
        IntegerInput::I32(val) => buffer.format(val),
        IntegerInput::U32(val) => buffer.format(val),
        IntegerInput::I64(val) => buffer.format(val),
        IntegerInput::U64(val) => buffer.format(val),
        IntegerInput::I128(val) => buffer.format(val),
        IntegerInput::U128(val) => buffer.format(val),
        IntegerInput::ISIZE(val) => buffer.format(val),
        IntegerInput::USIZE(val) => buffer.format(val),
    };
});
<commit_msg>Rename ptr sized integer variants<commit_after>#![no_main]

use arbitrary::Arbitrary;
use libfuzzer_sys::fuzz_target;

#[derive(Arbitrary, Debug)]
enum IntegerInput {
    I8(i8),
    U8(u8),
    I16(i16),
    U16(u16),
    I32(i32),
    U32(u32),
    I64(i64),
    U64(u64),
    I128(i128),
    U128(u128),
    Isize(isize),
    Usize(usize),
}

fuzz_target!(|input: IntegerInput| {
    let mut buffer = itoa::Buffer::new();
    match input {
        IntegerInput::I8(val) => buffer.format(val),
        IntegerInput::U8(val) => buffer.format(val),
        IntegerInput::I16(val) => buffer.format(val),
        IntegerInput::U16(val) => buffer.format(val),
        IntegerInput::I32(val) => buffer.format(val),
        IntegerInput::U32(val) => buffer.format(val),
        IntegerInput::I64(val) => buffer.format(val),
        IntegerInput::U64(val) => buffer.format(val),
        IntegerInput::I128(val) => buffer.format(val),
        IntegerInput::U128(val) => buffer.format(val),
        IntegerInput::Isize(val) => buffer.format(val),
        IntegerInput::Usize(val) => buffer.format(val),
    };
});
<|endoftext|>


<commit_before>//mod old;
mod container;
mod tree;
pub mod layout;

pub use self::container::{Container, ContainerType, Handle, Layout};

pub use self::tree::Node;
<commit_msg>Update mod.rs<commit_after>mod container;
mod tree;
pub mod layout;

pub use self::container::{Container, ContainerType, Handle, Layout};

pub use self::tree::Node;
<|endoftext|>


<commit_before>use std::cmp::Ordering;
use std::iter::Fuse;
use std::fmt;

use super::adaptors::{PutBack, put_back};
use either_or_both::EitherOrBoth;

/// Return an iterator adaptor that merge-joins items from the two base iterators in ascending order.
///
/// See [`.merge_join_by()`](trait.Itertools.html#method.merge_join_by) for more information.
pub fn merge_join_by<I, J, F>(left: I, right: J, cmp_fn: F)
    -> MergeJoinBy<I::IntoIter, J::IntoIter, F>
    where I: IntoIterator,
          J: IntoIterator,
          F: FnMut(&I::Item, &J::Item) -> Ordering
{
    MergeJoinBy {
        left: put_back(left.into_iter().fuse()),
        right: put_back(right.into_iter().fuse()),
        cmp_fn: cmp_fn
    }
}

/// An iterator adaptor that merge-joins items from the two base iterators in ascending order.
///
/// See [`.merge_join_by()`](../trait.Itertools.html#method.merge_join_by) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct MergeJoinBy<I: Iterator, J: Iterator, F> {
    left: PutBack<Fuse<I>>,
    right: PutBack<Fuse<J>>,
    cmp_fn: F
}

impl<I, J, F> fmt::Debug for MergeJoinBy<I, J, F>
    where I: Iterator + fmt::Debug,
          I::Item: fmt::Debug,
          J: Iterator + fmt::Debug,
          J::Item: fmt::Debug,
{
    debug_fmt_fields!(MergeJoinBy, left, right);
}

impl<I, J, F> Iterator for MergeJoinBy<I, J, F>
    where I: Iterator,
          J: Iterator,
          F: FnMut(&I::Item, &J::Item) -> Ordering
{
    type Item = EitherOrBoth<I::Item, J::Item>;

    fn next(&mut self) -> Option<Self::Item> {
        match (self.left.next(), self.right.next()) {
            (None, None) => None,
            (Some(left), None) =>
                Some(EitherOrBoth::Left(left)),
            (None, Some(right)) =>
                Some(EitherOrBoth::Right(right)),
            (Some(left), Some(right)) => {
                match (self.cmp_fn)(&left, &right) {
                    Ordering::Equal =>
                        Some(EitherOrBoth::Both(left, right)),
                    Ordering::Less => {
                        self.right.put_back(right);
                        Some(EitherOrBoth::Left(left))
                    },
                    Ordering::Greater => {
                        self.left.put_back(left);
                        Some(EitherOrBoth::Right(right))
                    }
                }
            }
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let (a_lower, a_upper) = self.left.size_hint();
        let (b_lower, b_upper) = self.right.size_hint();

        let lower = ::std::cmp::max(a_lower, b_lower);

        let upper = match (a_upper, b_upper) {
            (Some(x), Some(y)) => Some(x + y),
            _ => None,
        };

        (lower, upper)
    }
}
<commit_msg>Implement missing specializations on the MergeJoinBy Iterator<commit_after>use std::cmp::Ordering;
use std::iter::Fuse;
use std::fmt;

use super::adaptors::{PutBack, put_back};
use either_or_both::EitherOrBoth;

/// Return an iterator adaptor that merge-joins items from the two base iterators in ascending order.
///
/// See [`.merge_join_by()`](trait.Itertools.html#method.merge_join_by) for more information.
pub fn merge_join_by<I, J, F>(left: I, right: J, cmp_fn: F)
    -> MergeJoinBy<I::IntoIter, J::IntoIter, F>
    where I: IntoIterator,
          J: IntoIterator,
          F: FnMut(&I::Item, &J::Item) -> Ordering
{
    MergeJoinBy {
        left: put_back(left.into_iter().fuse()),
        right: put_back(right.into_iter().fuse()),
        cmp_fn: cmp_fn
    }
}

/// An iterator adaptor that merge-joins items from the two base iterators in ascending order.
///
/// See [`.merge_join_by()`](../trait.Itertools.html#method.merge_join_by) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct MergeJoinBy<I: Iterator, J: Iterator, F> {
    left: PutBack<Fuse<I>>,
    right: PutBack<Fuse<J>>,
    cmp_fn: F
}

impl<I, J, F> fmt::Debug for MergeJoinBy<I, J, F>
    where I: Iterator + fmt::Debug,
          I::Item: fmt::Debug,
          J: Iterator + fmt::Debug,
          J::Item: fmt::Debug,
{
    debug_fmt_fields!(MergeJoinBy, left, right);
}

impl<I, J, F> Iterator for MergeJoinBy<I, J, F>
    where I: Iterator,
          J: Iterator,
          F: FnMut(&I::Item, &J::Item) -> Ordering
{
    type Item = EitherOrBoth<I::Item, J::Item>;

    fn next(&mut self) -> Option<Self::Item> {
        match (self.left.next(), self.right.next()) {
            (None, None) => None,
            (Some(left), None) =>
                Some(EitherOrBoth::Left(left)),
            (None, Some(right)) =>
                Some(EitherOrBoth::Right(right)),
            (Some(left), Some(right)) => {
                match (self.cmp_fn)(&left, &right) {
                    Ordering::Equal =>
                        Some(EitherOrBoth::Both(left, right)),
                    Ordering::Less => {
                        self.right.put_back(right);
                        Some(EitherOrBoth::Left(left))
                    },
                    Ordering::Greater => {
                        self.left.put_back(left);
                        Some(EitherOrBoth::Right(right))
                    }
                }
            }
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let (a_lower, a_upper) = self.left.size_hint();
        let (b_lower, b_upper) = self.right.size_hint();

        let lower = ::std::cmp::max(a_lower, b_lower);

        let upper = match (a_upper, b_upper) {
            (Some(x), Some(y)) => Some(x + y),
            _ => None,
        };

        (lower, upper)
    }

    fn count(mut self) -> usize {
        let mut count = 0;
        loop {
            match (self.left.next(), self.right.next()) {
                (None, None) => break count,
                (Some(_left), None) => break count + 1 + self.left.count(),
                (None, Some(_right)) => break count + 1 + self.right.count(),
                (Some(left), Some(right)) => {
                    count += 1;
                    match (self.cmp_fn)(&left, &right) {
                        Ordering::Equal => {}
                        Ordering::Less => self.right.put_back(right),
                        Ordering::Greater => self.left.put_back(left),
                    }
                }
            }
        }
    }

    fn last(mut self) -> Option<Self::Item> {
        let mut previous_element = None;
        loop {
            match (self.left.next(), self.right.next()) {
                (None, None) => break previous_element,
                (Some(left), None) => {
                    break Some(EitherOrBoth::Left(self.left.last().unwrap_or(left)))
                }
                (None, Some(right)) => {
                    break Some(EitherOrBoth::Right(self.right.last().unwrap_or(right)))
                }
                (Some(left), Some(right)) => {
                    previous_element = match (self.cmp_fn)(&left, &right) {
                        Ordering::Equal => Some(EitherOrBoth::Both(left, right)),
                        Ordering::Less => {
                            self.right.put_back(right);
                            Some(EitherOrBoth::Left(left))
                        }
                        Ordering::Greater => {
                            self.left.put_back(left);
                            Some(EitherOrBoth::Right(right))
                        }
                    }
                }
            }
        }
    }

    fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
        loop {
            if n == 0 {
                break self.next();
            }
            n -= 1;
            match (self.left.next(), self.right.next()) {
                (None, None) => break None,
                (Some(_left), None) => break self.left.nth(n).map(EitherOrBoth::Left),
                (None, Some(_right)) => break self.right.nth(n).map(EitherOrBoth::Right),
                (Some(left), Some(right)) => match (self.cmp_fn)(&left, &right) {
                    Ordering::Equal => {}
                    Ordering::Less => self.right.put_back(right),
                    Ordering::Greater => self.left.put_back(left),
                },
            }
        }
    }
}
<|endoftext|>