<commit_before>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::rustc::hir::def_id::DefId;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::ty;
use crate::rustc_data_structures::fx::FxHashSet;
use crate::syntax::ast::{Lit, LitKind, Name};
use crate::syntax::source_map::{Span, Spanned};
use crate::utils::{get_item_name, in_macro, snippet, span_lint, span_lint_and_sugg, walk_ptrs_ty};

/// **What it does:** Checks for getting the length of something via `.len()`
/// just to compare to zero, and suggests using `.is_empty()` where applicable.
///
/// **Why is this bad?** Some structures can answer `.is_empty()` much faster
/// than calculating their length. Notably, for slices, getting the length
/// requires a subtraction whereas `.is_empty()` is just a comparison. So it is
/// good to get into the habit of using `.is_empty()`, and having it is cheap.
/// Besides, it makes the intent clearer than a manual comparison.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// if x.len() == 0 { .. }
/// if y.len() != 0 { .. }
/// ```
/// instead use
/// ```rust
/// if x.len().is_empty() { .. }
/// if !y.len().is_empty() { .. }
/// ```
declare_clippy_lint! {
    pub LEN_ZERO,
    style,
    "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` \
     could be used instead"
}

/// **What it does:** Checks for items that implement `.len()` but not
/// `.is_empty()`.
///
/// **Why is this bad?** It is good custom to have both methods, because for
/// some data structures, asking about the length will be a costly operation,
/// whereas `.is_empty()` can usually answer in constant time. Also it used to
/// lead to false positives on the [`len_zero`](#len_zero) lint – currently that
/// lint will ignore such entities.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// impl X {
///     pub fn len(&self) -> usize { .. }
/// }
/// ```
declare_clippy_lint! {
    pub LEN_WITHOUT_IS_EMPTY,
    style,
    "traits or impls with a public `len` method but no corresponding `is_empty` method"
}

#[derive(Copy, Clone)]
pub struct LenZero;

impl LintPass for LenZero {
    fn get_lints(&self) -> LintArray {
        lint_array!(LEN_ZERO, LEN_WITHOUT_IS_EMPTY)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LenZero {
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
        if in_macro(item.span) {
            return;
        }

        match item.node {
            ItemKind::Trait(_, _, _, _, ref trait_items) => check_trait_items(cx, item, trait_items),
            ItemKind::Impl(_, _, _, _, None, _, ref impl_items) => check_impl_items(cx, item, impl_items),
            _ => (),
        }
    }

    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if in_macro(expr.span) {
            return;
        }

        if let ExprKind::Binary(Spanned { node: cmp, .. }, ref left, ref right) = expr.node {
            match cmp {
                BinOpKind::Eq => {
                    check_cmp(cx, expr.span, left, right, "", 0); // len == 0
                    check_cmp(cx, expr.span, right, left, "", 0); // 0 == len
                },
                BinOpKind::Ne => {
                    check_cmp(cx, expr.span, left, right, "!", 0); // len != 0
                    check_cmp(cx, expr.span, right, left, "!", 0); // 0 != len
                },
                BinOpKind::Gt => {
                    check_cmp(cx, expr.span, left, right, "!", 0); // len > 0
                    check_cmp(cx, expr.span, right, left, "", 1); // 1 > len
                },
                BinOpKind::Lt => {
                    check_cmp(cx, expr.span, left, right, "", 1); // len < 1
                    check_cmp(cx, expr.span, right, left, "!", 0); // 0 < len
                },
                BinOpKind::Ge => check_cmp(cx, expr.span, left, right, "!", 1), // len <= 1
                BinOpKind::Le => check_cmp(cx, expr.span, right, left, "!", 1), // 1 >= len
                _ => (),
            }
        }
    }
}

fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item, trait_items: &[TraitItemRef]) {
    fn is_named_self(cx: &LateContext<'_, '_>, item: &TraitItemRef, name: &str) -> bool {
        item.ident.name == name && if let AssociatedItemKind::Method { has_self } = item.kind {
            has_self && {
                let did = cx.tcx.hir.local_def_id(item.id.node_id);
                cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
            }
        } else {
            false
        }
    }

    // fill the set with current and super traits
    fn fill_trait_set(traitt: DefId, set: &mut FxHashSet<DefId>, cx: &LateContext<'_, '_>) {
        if set.insert(traitt) {
            for supertrait in crate::rustc::traits::supertrait_def_ids(cx.tcx, traitt) {
                fill_trait_set(supertrait, set, cx);
            }
        }
    }

    if cx.access_levels.is_exported(visited_trait.id) && trait_items.iter().any(|i| is_named_self(cx, i, "len")) {
        let mut current_and_super_traits = FxHashSet::default();
        let visited_trait_def_id = cx.tcx.hir.local_def_id(visited_trait.id);
        fill_trait_set(visited_trait_def_id, &mut current_and_super_traits, cx);

        let is_empty_method_found = current_and_super_traits
            .iter()
            .flat_map(|&i| cx.tcx.associated_items(i))
            .any(|i| {
                i.kind == ty::AssociatedKind::Method && i.method_has_self_argument && i.ident.name == "is_empty"
                    && cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
            });

        if !is_empty_method_found {
            span_lint(
                cx,
                LEN_WITHOUT_IS_EMPTY,
                visited_trait.span,
                &format!(
                    "trait `{}` has a `len` method but no (possibly inherited) `is_empty` method",
                    visited_trait.name
                ),
            );
        }
    }
}

fn check_impl_items(cx: &LateContext<'_, '_>, item: &Item, impl_items: &[ImplItemRef]) {
    fn is_named_self(cx: &LateContext<'_, '_>, item: &ImplItemRef, name: &str) -> bool {
        item.ident.name == name && if let AssociatedItemKind::Method { has_self } = item.kind {
            has_self && {
                let did = cx.tcx.hir.local_def_id(item.id.node_id);
                cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
            }
        } else {
            false
        }
    }

    let is_empty = if let Some(is_empty) = impl_items.iter().find(|i| is_named_self(cx, i, "is_empty")) {
        if cx.access_levels.is_exported(is_empty.id.node_id) {
            return;
        } else {
            "a private"
        }
    } else {
        "no corresponding"
    };

    if let Some(i) = impl_items.iter().find(|i| is_named_self(cx, i, "len")) {
        if cx.access_levels.is_exported(i.id.node_id) {
            let def_id = cx.tcx.hir.local_def_id(item.id);
            let ty = cx.tcx.type_of(def_id);

            span_lint(
                cx,
                LEN_WITHOUT_IS_EMPTY,
                item.span,
                &format!(
                    "item `{}` has a public `len` method but {} `is_empty` method",
                    ty, is_empty
                ),
            );
        }
    }
}

fn check_cmp(cx: &LateContext<'_, '_>, span: Span, method: &Expr, lit: &Expr, op: &str, compare_to: u32) {
    if let (&ExprKind::MethodCall(ref method_path, _, ref args), &ExprKind::Lit(ref lit)) = (&method.node, &lit.node) {
        // check if we are in an is_empty() method
        if let Some(name) = get_item_name(cx, method) {
            if name == "is_empty" {
                return;
            }
        }

        check_len(cx, span, method_path.ident.name, args, lit, op, compare_to)
    }
}

fn check_len(cx: &LateContext<'_, '_>, span: Span, method_name: Name, args: &[Expr], lit: &Lit, op: &str, compare_to: u32) {
    if let Spanned {
        node: LitKind::Int(lit, _),
        ..
    } = *lit
    {
        // check if length is compared to the specified number
        if lit != u128::from(compare_to) {
            return;
        }

        if method_name == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) {
            span_lint_and_sugg(
                cx,
                LEN_ZERO,
                span,
                &format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }),
                "using `is_empty` is more concise",
                format!("{}{}.is_empty()", op, snippet(cx, args[0].span, "_")),
            );
        }
    }
}

/// Check if this type has an `is_empty` method.
fn has_is_empty(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
    /// Get an `AssociatedItem` and return true if it matches `is_empty(self)`.
    fn is_is_empty(cx: &LateContext<'_, '_>, item: &ty::AssociatedItem) -> bool {
        if let ty::AssociatedKind::Method = item.kind {
            if item.ident.name == "is_empty" {
                let sig = cx.tcx.fn_sig(item.def_id);
                let ty = sig.skip_binder();
                ty.inputs().len() == 1
            } else {
                false
            }
        } else {
            false
        }
    }

    /// Check the inherent impl's items for an `is_empty(self)` method.
    fn has_is_empty_impl(cx: &LateContext<'_, '_>, id: DefId) -> bool {
        cx.tcx.inherent_impls(id).iter().any(|imp| {
            cx.tcx
                .associated_items(*imp)
                .any(|item| is_is_empty(cx, &item))
        })
    }

    let ty = &walk_ptrs_ty(cx.tables.expr_ty(expr));
    match ty.sty {
        ty::Dynamic(ref tt, ..) => cx.tcx
            .associated_items(tt.principal().expect("trait impl not found").def_id())
            .any(|item| is_is_empty(cx, &item)),
        ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id),
        ty::Adt(id, _) => has_is_empty_impl(cx, id.did),
        ty::Array(..) | ty::Slice(..) | ty::Str => true,
        _ => false,
    }
}
<commit_msg>fix for rustc master<commit_after>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::rustc::hir::def_id::DefId;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::ty;
use crate::rustc_data_structures::fx::FxHashSet;
use crate::syntax::ast::{Lit, LitKind, Name};
use crate::syntax::source_map::{Span, Spanned};
use crate::utils::{get_item_name, in_macro, snippet, span_lint, span_lint_and_sugg, walk_ptrs_ty};

/// **What it does:** Checks for getting the length of something via `.len()`
/// just to compare to zero, and suggests using `.is_empty()` where applicable.
///
/// **Why is this bad?** Some structures can answer `.is_empty()` much faster
/// than calculating their length. Notably, for slices, getting the length
/// requires a subtraction whereas `.is_empty()` is just a comparison. So it is
/// good to get into the habit of using `.is_empty()`, and having it is cheap.
/// Besides, it makes the intent clearer than a manual comparison.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// if x.len() == 0 { .. }
/// if y.len() != 0 { .. }
/// ```
/// instead use
/// ```rust
/// if x.len().is_empty() { .. }
/// if !y.len().is_empty() { .. }
/// ```
declare_clippy_lint! {
    pub LEN_ZERO,
    style,
    "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` \
     could be used instead"
}

/// **What it does:** Checks for items that implement `.len()` but not
/// `.is_empty()`.
///
/// **Why is this bad?** It is good custom to have both methods, because for
/// some data structures, asking about the length will be a costly operation,
/// whereas `.is_empty()` can usually answer in constant time. Also it used to
/// lead to false positives on the [`len_zero`](#len_zero) lint – currently that
/// lint will ignore such entities.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// impl X {
///     pub fn len(&self) -> usize { .. }
/// }
/// ```
declare_clippy_lint! {
    pub LEN_WITHOUT_IS_EMPTY,
    style,
    "traits or impls with a public `len` method but no corresponding `is_empty` method"
}

#[derive(Copy, Clone)]
pub struct LenZero;

impl LintPass for LenZero {
    fn get_lints(&self) -> LintArray {
        lint_array!(LEN_ZERO, LEN_WITHOUT_IS_EMPTY)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LenZero {
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
        if in_macro(item.span) {
            return;
        }

        match item.node {
            ItemKind::Trait(_, _, _, _, ref trait_items) => check_trait_items(cx, item, trait_items),
            ItemKind::Impl(_, _, _, _, None, _, ref impl_items) => check_impl_items(cx, item, impl_items),
            _ => (),
        }
    }

    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if in_macro(expr.span) {
            return;
        }

        if let ExprKind::Binary(Spanned { node: cmp, .. }, ref left, ref right) = expr.node {
            match cmp {
                BinOpKind::Eq => {
                    check_cmp(cx, expr.span, left, right, "", 0); // len == 0
                    check_cmp(cx, expr.span, right, left, "", 0); // 0 == len
                },
                BinOpKind::Ne => {
                    check_cmp(cx, expr.span, left, right, "!", 0); // len != 0
                    check_cmp(cx, expr.span, right, left, "!", 0); // 0 != len
                },
                BinOpKind::Gt => {
                    check_cmp(cx, expr.span, left, right, "!", 0); // len > 0
                    check_cmp(cx, expr.span, right, left, "", 1); // 1 > len
                },
                BinOpKind::Lt => {
                    check_cmp(cx, expr.span, left, right, "", 1); // len < 1
                    check_cmp(cx, expr.span, right, left, "!", 0); // 0 < len
                },
                BinOpKind::Ge => check_cmp(cx, expr.span, left, right, "!", 1), // len <= 1
                BinOpKind::Le => check_cmp(cx, expr.span, right, left, "!", 1), // 1 >= len
                _ => (),
            }
        }
    }
}

fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item, trait_items: &[TraitItemRef]) {
    fn is_named_self(cx: &LateContext<'_, '_>, item: &TraitItemRef, name: &str) -> bool {
        item.ident.name == name && if let AssociatedItemKind::Method { has_self } = item.kind {
            has_self && {
                let did = cx.tcx.hir.local_def_id(item.id.node_id);
                cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
            }
        } else {
            false
        }
    }

    // fill the set with current and super traits
    fn fill_trait_set(traitt: DefId, set: &mut FxHashSet<DefId>, cx: &LateContext<'_, '_>) {
        if set.insert(traitt) {
            for supertrait in crate::rustc::traits::supertrait_def_ids(cx.tcx, traitt) {
                fill_trait_set(supertrait, set, cx);
            }
        }
    }

    if cx.access_levels.is_exported(visited_trait.id) && trait_items.iter().any(|i| is_named_self(cx, i, "len")) {
        let mut current_and_super_traits = FxHashSet::default();
        let visited_trait_def_id = cx.tcx.hir.local_def_id(visited_trait.id);
        fill_trait_set(visited_trait_def_id, &mut current_and_super_traits, cx);

        let is_empty_method_found = current_and_super_traits
            .iter()
            .flat_map(|&i| cx.tcx.associated_items(i))
            .any(|i| {
                i.kind == ty::AssociatedKind::Method && i.method_has_self_argument && i.ident.name == "is_empty"
                    && cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
            });

        if !is_empty_method_found {
            span_lint(
                cx,
                LEN_WITHOUT_IS_EMPTY,
                visited_trait.span,
                &format!(
                    "trait `{}` has a `len` method but no (possibly inherited) `is_empty` method",
                    visited_trait.name
                ),
            );
        }
    }
}

fn check_impl_items(cx: &LateContext<'_, '_>, item: &Item, impl_items: &[ImplItemRef]) {
    fn is_named_self(cx: &LateContext<'_, '_>, item: &ImplItemRef, name: &str) -> bool {
        item.ident.name == name && if let AssociatedItemKind::Method { has_self } = item.kind {
            has_self && {
                let did = cx.tcx.hir.local_def_id(item.id.node_id);
                cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
            }
        } else {
            false
        }
    }

    let is_empty = if let Some(is_empty) = impl_items.iter().find(|i| is_named_self(cx, i, "is_empty")) {
        if cx.access_levels.is_exported(is_empty.id.node_id) {
            return;
        } else {
            "a private"
        }
    } else {
        "no corresponding"
    };

    if let Some(i) = impl_items.iter().find(|i| is_named_self(cx, i, "len")) {
        if cx.access_levels.is_exported(i.id.node_id) {
            let def_id = cx.tcx.hir.local_def_id(item.id);
            let ty = cx.tcx.type_of(def_id);

            span_lint(
                cx,
                LEN_WITHOUT_IS_EMPTY,
                item.span,
                &format!(
                    "item `{}` has a public `len` method but {} `is_empty` method",
                    ty, is_empty
                ),
            );
        }
    }
}

fn check_cmp(cx: &LateContext<'_, '_>, span: Span, method: &Expr, lit: &Expr, op: &str, compare_to: u32) {
    if let (&ExprKind::MethodCall(ref method_path, _, ref args), &ExprKind::Lit(ref lit)) = (&method.node, &lit.node) {
        // check if we are in an is_empty() method
        if let Some(name) = get_item_name(cx, method) {
            if name == "is_empty" {
                return;
            }
        }

        check_len(cx, span, method_path.ident.name, args, lit, op, compare_to)
    }
}

fn check_len(cx: &LateContext<'_, '_>, span: Span, method_name: Name, args: &[Expr], lit: &Lit, op: &str, compare_to: u32) {
    if let Spanned {
        node: LitKind::Int(lit, _),
        ..
    } = *lit
    {
        // check if length is compared to the specified number
        if lit != u128::from(compare_to) {
            return;
        }

        if method_name == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) {
            span_lint_and_sugg(
                cx,
                LEN_ZERO,
                span,
                &format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }),
                "using `is_empty` is more concise",
                format!("{}{}.is_empty()", op, snippet(cx, args[0].span, "_")),
            );
        }
    }
}

/// Check if this type has an `is_empty` method.
fn has_is_empty(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
    /// Get an `AssociatedItem` and return true if it matches `is_empty(self)`.
    fn is_is_empty(cx: &LateContext<'_, '_>, item: &ty::AssociatedItem) -> bool {
        if let ty::AssociatedKind::Method = item.kind {
            if item.ident.name == "is_empty" {
                let sig = cx.tcx.fn_sig(item.def_id);
                let ty = sig.skip_binder();
                ty.inputs().len() == 1
            } else {
                false
            }
        } else {
            false
        }
    }

    /// Check the inherent impl's items for an `is_empty(self)` method.
    fn has_is_empty_impl(cx: &LateContext<'_, '_>, id: DefId) -> bool {
        cx.tcx.inherent_impls(id).iter().any(|imp| {
            cx.tcx
                .associated_items(*imp)
                .any(|item| is_is_empty(cx, &item))
        })
    }

    let ty = &walk_ptrs_ty(cx.tables.expr_ty(expr));
    match ty.sty {
        ty::Dynamic(ref tt, ..) => cx.tcx
            .associated_items(tt.principal().def_id())
            .any(|item| is_is_empty(cx, &item)),
        ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id),
        ty::Adt(id, _) => has_is_empty_impl(cx, id.did),
        ty::Array(..) | ty::Slice(..) | ty::Str => true,
        _ => false,
    }
}
<|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/. */

//! Supports writing a trace file created during each layout scope
//! that can be viewed by an external tool to make layout debugging easier.

use flow::GetBaseFlow;
use flow_ref::FlowRef;
use serde_json::{to_string, to_value, Value};
use std::borrow::ToOwned;
use std::cell::RefCell;
use std::fs::File;
use std::io::Write;
#[cfg(debug_assertions)]
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};

thread_local!(static STATE_KEY: RefCell<Option<State>> = RefCell::new(None));

#[cfg(debug_assertions)]
static DEBUG_ID_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;

pub struct Scope;

#[macro_export]
macro_rules! layout_debug_scope(
    ($($arg:tt)*) => (
        if cfg!(debug_assertions) {
            layout_debug::Scope::new(format!($($arg)*))
        } else {
            layout_debug::Scope
        }
    )
);

#[derive(Serialize)]
struct ScopeData {
    name: String,
    pre: Value,
    post: Value,
    children: Vec<Box<ScopeData>>,
}

impl ScopeData {
    fn new(name: String, pre: Value) -> ScopeData {
        ScopeData {
            name: name,
            pre: pre,
            post: Value::Null,
            children: vec!(),
        }
    }
}

struct State {
    flow_root: FlowRef,
    scope_stack: Vec<Box<ScopeData>>,
}

/// A layout debugging scope. The entire state of the flow tree
/// will be output at the beginning and end of this scope.
impl Scope {
    pub fn new(name: String) -> Scope {
        STATE_KEY.with(|ref r| {
            if let Some(ref mut state) = *r.borrow_mut() {
                let flow_trace = to_value(&state.flow_root.base()).unwrap();
                let data = Box::new(ScopeData::new(name.clone(), flow_trace));
                state.scope_stack.push(data);
            }
        });
        Scope
    }
}

#[cfg(debug_assertions)]
impl Drop for Scope {
    fn drop(&mut self) {
        STATE_KEY.with(|ref r| {
            if let Some(ref mut state) = *r.borrow_mut() {
                let mut current_scope = state.scope_stack.pop().unwrap();
                current_scope.post = to_value(&state.flow_root.base()).unwrap();
                let previous_scope = state.scope_stack.last_mut().unwrap();
                previous_scope.children.push(current_scope);
            }
        });
    }
}

/// Generate a unique ID. This is used for items such as Fragment
/// which are often reallocated but represent essentially the
/// same data.
#[cfg(debug_assertions)]
pub fn generate_unique_debug_id() -> u16 {
    DEBUG_ID_COUNTER.fetch_add(1, Ordering::SeqCst) as u16
}

/// Begin a layout debug trace. If this has not been called,
/// creating debug scopes has no effect.
pub fn begin_trace(flow_root: FlowRef) {
    assert!(STATE_KEY.with(|ref r| r.borrow().is_none()));

    STATE_KEY.with(|ref r| {
        let flow_trace = to_value(&flow_root.base()).unwrap();
        let state = State {
            scope_stack: vec![Box::new(ScopeData::new("root".to_owned(), flow_trace))],
            flow_root: flow_root.clone(),
        };
        *r.borrow_mut() = Some(state);
    });
}

/// End the debug layout trace. This will write the layout
/// trace to disk in the current directory. The output
/// file can then be viewed with an external tool.
pub fn end_trace(generation: u32) {
    let mut thread_state = STATE_KEY.with(|ref r| r.borrow_mut().take().unwrap());
    assert!(thread_state.scope_stack.len() == 1);
    let mut root_scope = thread_state.scope_stack.pop().unwrap();
    root_scope.post = to_value(&thread_state.flow_root.base()).unwrap();

    let result = to_string(&root_scope).unwrap();
    let mut file = File::create(format!("layout_trace-{}.json", generation)).unwrap();
    file.write_all(result.as_bytes()).unwrap();
}
<commit_msg>Use specific assertion for layout layout_debug<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/. */

//! Supports writing a trace file created during each layout scope
//! that can be viewed by an external tool to make layout debugging easier.

use flow::GetBaseFlow;
use flow_ref::FlowRef;
use serde_json::{to_string, to_value, Value};
use std::borrow::ToOwned;
use std::cell::RefCell;
use std::fs::File;
use std::io::Write;
#[cfg(debug_assertions)]
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};

thread_local!(static STATE_KEY: RefCell<Option<State>> = RefCell::new(None));

#[cfg(debug_assertions)]
static DEBUG_ID_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;

pub struct Scope;

#[macro_export]
macro_rules! layout_debug_scope(
    ($($arg:tt)*) => (
        if cfg!(debug_assertions) {
            layout_debug::Scope::new(format!($($arg)*))
        } else {
            layout_debug::Scope
        }
    )
);

#[derive(Serialize)]
struct ScopeData {
    name: String,
    pre: Value,
    post: Value,
    children: Vec<Box<ScopeData>>,
}

impl ScopeData {
    fn new(name: String, pre: Value) -> ScopeData {
        ScopeData {
            name: name,
            pre: pre,
            post: Value::Null,
            children: vec!(),
        }
    }
}

struct State {
    flow_root: FlowRef,
    scope_stack: Vec<Box<ScopeData>>,
}

/// A layout debugging scope. The entire state of the flow tree
/// will be output at the beginning and end of this scope.
impl Scope {
    pub fn new(name: String) -> Scope {
        STATE_KEY.with(|ref r| {
            if let Some(ref mut state) = *r.borrow_mut() {
                let flow_trace = to_value(&state.flow_root.base()).unwrap();
                let data = Box::new(ScopeData::new(name.clone(), flow_trace));
                state.scope_stack.push(data);
            }
        });
        Scope
    }
}

#[cfg(debug_assertions)]
impl Drop for Scope {
    fn drop(&mut self) {
        STATE_KEY.with(|ref r| {
            if let Some(ref mut state) = *r.borrow_mut() {
                let mut current_scope = state.scope_stack.pop().unwrap();
                current_scope.post = to_value(&state.flow_root.base()).unwrap();
                let previous_scope = state.scope_stack.last_mut().unwrap();
                previous_scope.children.push(current_scope);
            }
        });
    }
}

/// Generate a unique ID. This is used for items such as Fragment
/// which are often reallocated but represent essentially the
/// same data.
#[cfg(debug_assertions)]
pub fn generate_unique_debug_id() -> u16 {
    DEBUG_ID_COUNTER.fetch_add(1, Ordering::SeqCst) as u16
}

/// Begin a layout debug trace. If this has not been called,
/// creating debug scopes has no effect.
pub fn begin_trace(flow_root: FlowRef) {
    assert!(STATE_KEY.with(|ref r| r.borrow().is_none()));

    STATE_KEY.with(|ref r| {
        let flow_trace = to_value(&flow_root.base()).unwrap();
        let state = State {
            scope_stack: vec![Box::new(ScopeData::new("root".to_owned(), flow_trace))],
            flow_root: flow_root.clone(),
        };
        *r.borrow_mut() = Some(state);
    });
}

/// End the debug layout trace. This will write the layout
/// trace to disk in the current directory. The output
/// file can then be viewed with an external tool.
pub fn end_trace(generation: u32) {
    let mut thread_state = STATE_KEY.with(|ref r| r.borrow_mut().take().unwrap());
    assert_eq!(thread_state.scope_stack.len(), 1);
    let mut root_scope = thread_state.scope_stack.pop().unwrap();
    root_scope.post = to_value(&thread_state.flow_root.base()).unwrap();

    let result = to_string(&root_scope).unwrap();
    let mut file = File::create(format!("layout_trace-{}.json", generation)).unwrap();
    file.write_all(result.as_bytes()).unwrap();
}
<|endoftext|>


<commit_before>//! Collection of utilities for working with XML

use sxd_document::*;
use std::str;

/// Parses a vector of bytes into a XML document
pub fn parse_bytes(bytes: &[u8]) -> Result<Package, String> {
  let string = str::from_utf8(bytes).map_err(|_| format!("{:?}", bytes))?;
  parser::parse(string).map_err(|e| format!("{:?}", e))
}
<commit_msg>refactor: convert xml_utils to use anyhow::Result<commit_after>//! Collection of utilities for working with XML

use std::str;

use anyhow::anyhow;
use sxd_document::*;

/// Parses a vector of bytes into a XML document
pub fn parse_bytes(bytes: &[u8]) -> anyhow::Result<Package> {
  let string = str::from_utf8(bytes)?;
  match parser::parse(string) {
    Ok(doc) => Ok(doc),
    Err(err) => Err(anyhow!("Failed to parse bytes as XML - {}", err))
  }
}
<|endoftext|>


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

//! The implementation of the DOM.
//!
//! The DOM is comprised of interfaces (defined by specifications using
//! [WebIDL](https://heycam.github.io/webidl/)) that are implemented as Rust
//! structs in submodules of this module. Its implementation is documented
//! below.
//!
//! A DOM object and its reflector
//! ==============================
//!
//! The implementation of an interface `Foo` in Servo's DOM involves two
//! related but distinct objects:
//!
//! * the **DOM object**: an instance of the Rust struct `dom::foo::Foo`
//!   (marked with the `#[dom_struct]` attribute) on the Rust heap;
//! * the **reflector**: a `JSObject` allocated by SpiderMonkey, that owns the
//!   DOM object.
//!
//! Memory management
//! =================
//!
//! Reflectors of DOM objects, and thus the DOM objects themselves, are managed
//! by the SpiderMonkey Garbage Collector. Thus, keeping alive a DOM object
//! is done through its reflector.
//!
//! For more information, see:
//!
//! * rooting pointers on the stack: the [`Root`](bindings/js/struct.Root.html)
//!   and [`JSRef`](bindings/js/struct.JSRef.html) smart pointers;
//! * tracing pointers in member fields: the [`JS`](bindings/js/struct.JS.html),
//!   [`MutNullableJS`](bindings/js/struct.MutNullableJS.html) and
//!   [`MutHeap`](bindings/js/struct.MutHeap.html) smart pointers and
//!   [the tracing implementation](bindings/trace/index.html);
//! * returning pointers from functions: the
//!   [`Temporary`](bindings/js/struct.Temporary.html) smart pointer;
//! * rooting pointers from across task boundaries or in channels: the
//!   [`Trusted`](bindings/refcounted/struct.Trusted.html) smart pointer;
//! * extracting pointers to DOM objects from their reflectors: the
//!   [`Unrooted`](bindings/js/struct.Unrooted.html) smart pointer.
//!
//! Inheritance
//! ===========
//!
//! Rust does not support struct inheritance, as would be used for the
//! object-oriented DOM APIs. To work around this issue, Servo stores an
//! instance of the superclass in the first field of its subclasses. (Note that
//! it is stored by value, rather than in a smart pointer such as `JS<T>`.)
//!
//! This implies that a pointer to an object can safely be cast to a pointer
//! to all its classes.
//!
//! This invariant is enforced by the lint in
//! `plugins::lints::inheritance_integrity`.
//!
//! Construction
//! ============
//!
//! DOM objects of type `T` in Servo have two constructors:
//!
//! * a `T::new_inherited` static method that returns a plain `T`, and
//! * a `T::new` static method that returns `Temporary<T>`.
//!
//! (The result of either method can be wrapped in `Result`, if that is
//! appropriate for the type in question.)
//!
//! The latter calls the former, boxes the result, and creates a reflector
//! corresponding to it by calling `dom::bindings::utils::reflect_dom_object`
//! (which yields ownership of the object to the SpiderMonkey Garbage Collector).
//! This is the API to use when creating a DOM object.
//!
//! The former should only be called by the latter, and by subclasses'
//! `new_inherited` methods.
//!
//! DOM object constructors in JavaScript correspond to a `T::Constructor`
//! static method. This method is always fallible.
//!
//! Destruction
//! ===========
//!
//! When the SpiderMonkey Garbage Collector discovers that the reflector of a
//! DOM object is garbage, it calls the reflector's finalization hook. This
//! function deletes the reflector's DOM object, calling its destructor in the
//! process.
//!
//! Mutability and aliasing
//! =======================
//!
//! Reflectors are JavaScript objects, and as such can be freely aliased. As
//! Rust does not allow mutable aliasing, mutable borrows of DOM objects are
//! not allowed. In particular, any mutable fields use `Cell` or `DOMRefCell`
//! to manage their mutability.
//!
//! `Reflector` and `Reflectable`
//! =============================
//!
//! Every DOM object has a `Reflector` as its first (transitive) member field.
//! This contains a `*mut JSObject` that points to its reflector.
//!
//! The `FooBinding::Wrap` function creates the reflector, stores a pointer to
//! the DOM object in the reflector, and initializes the pointer to the reflector
//! in the `Reflector` field.
//!
//! The `Reflectable` trait provides a `reflector()` method that returns the
//! DOM object's `Reflector`. It is implemented automatically for DOM structs
//! through the `#[dom_struct]` attribute.
//!
//! Implementing methods for a DOM object
//! =====================================
//!
//! In order to ensure that DOM objects are rooted when they are called, we
//! require that all methods are implemented for `JSRef<'a, Foo>`. This means
//! that all methods are defined on traits. Conventionally, those traits are
//! called
//!
//! * `dom::bindings::codegen::Bindings::FooBindings::FooMethods` for methods
//!   defined through IDL;
//! * `FooHelpers` for public methods;
//! * `PrivateFooHelpers` for private methods.
//!
//! Calling methods on a DOM object
//! ===============================
//!
//! To call a method on a DOM object, we require that the object is rooted, by
//! calling `.root()` on a `Temporary` or `JS` pointer. This constructs a
//! `Root` on the stack, which ensures the DOM object stays alive for the
//! duration of its lifetime. A `JSRef` on which to call the method can then be
//! obtained by calling the `r()` method on the `Root`.
//!
//! Accessing fields of a DOM object
//! ================================
//!
//! All fields of DOM objects are private; accessing them from outside their
//! module is done through explicit getter or setter methods.
//!
//! However, `JSRef<T>` dereferences to `&T`, so fields can be accessed on a
//! `JSRef<T>` directly within the module that defines the struct.
//!
//! Inheritance and casting
//! =======================
//!
//! For all DOM interfaces `Foo` in an inheritance chain, a
//! `dom::bindings::codegen::InheritTypes::FooCast` provides methods to cast
//! to other types in the inheritance chain. For example:
//!
//! ```ignore
//! # use script::dom::bindings::js::JSRef;
//! # use script::dom::bindings::codegen::InheritTypes::{NodeCast, HTMLElementCast};
//! # use script::dom::element::Element;
//! # use script::dom::node::Node;
//! # use script::dom::htmlelement::HTMLElement;
//! fn f(element: JSRef<Element>) {
//!     let base: JSRef<Node> = NodeCast::from_ref(element);
//!     let derived: Option<JSRef<HTMLElement>> = HTMLElementCast::to_ref(element);
//! }
//! ```
//!
//! Adding a new DOM interface
//! ==========================
//!
//! Adding a new interface `Foo` requires at least the following:
//!
//! * adding the new IDL file at `components/script/dom/webidls/Foo.webidl`;
//! * creating `components/script/dom/foo.rs`;
//! * listing `foo.rs` in components/script/dom/mod.rs`;
//! * defining the DOM struct `Foo` with a `#[dom_struct]` attribute, a
//!   superclass or `Reflector` member, and other members as appropriate;
//! * implementing the
//!   `dom::bindings::codegen::Bindings::FooBindings::FooMethods` trait for
//!   `JSRef<Foo>`.
//!
//! More information is available in the [bindings module](bindings/index.html).
//!
//! Accessing DOM objects from layout
//! =================================
//!
//! Layout code can access the DOM through the
//! [`LayoutJS`](bindings/js/struct.LayoutJS.html) smart pointer. This does not
//! keep the DOM object alive; we ensure that no DOM code (Garbage Collection
//! in particular) runs while the layout task is accessing the DOM.
//!
//! Methods accessible to layout are implemented on `LayoutJS<Foo>` using
//! `LayoutFooHelpers` traits.

#[macro_use]
pub mod macros;

pub mod bindings;

#[path="bindings/codegen/InterfaceTypes.rs"]
pub mod types;

pub mod activation;
pub mod attr;
pub mod blob;
pub mod browsercontext;
pub mod canvasgradient;
pub mod canvaspattern;
pub mod canvasrenderingcontext2d;
pub mod characterdata;
pub mod css;
pub mod cssstyledeclaration;
pub mod domrect;
pub mod domrectlist;
pub mod domstringmap;
pub mod closeevent;
pub mod comment;
pub mod console;
mod create;
pub mod customevent;
pub mod dedicatedworkerglobalscope;
pub mod document;
pub mod documentfragment;
pub mod documenttype;
pub mod domexception;
pub mod domimplementation;
pub mod domparser;
pub mod domtokenlist;
pub mod element;
pub mod errorevent;
pub mod event;
pub mod eventdispatcher;
pub mod eventtarget;
pub mod file;
pub mod formdata;
pub mod htmlanchorelement;
pub mod htmlappletelement;
pub mod htmlareaelement;
pub mod htmlaudioelement;
pub mod htmlbaseelement;
pub mod htmlbodyelement;
pub mod htmlbrelement;
pub mod htmlbuttonelement;
pub mod htmlcanvaselement;
pub mod htmlcollection;
pub mod htmldataelement;
pub mod htmldatalistelement;
pub mod htmldialogelement;
pub mod htmldirectoryelement;
pub mod htmldivelement;
pub mod htmldlistelement;
pub mod htmlelement;
pub mod htmlembedelement;
pub mod htmlfieldsetelement;
pub mod htmlfontelement;
pub mod htmlformelement;
pub mod htmlframeelement;
pub mod htmlframesetelement;
pub mod htmlheadelement;
pub mod htmlheadingelement;
pub mod htmlhrelement;
pub mod htmlhtmlelement;
pub mod htmliframeelement;
pub mod htmlimageelement;
pub mod htmlinputelement;
pub mod htmllabelelement;
pub mod htmllegendelement;
pub mod htmllielement;
pub mod htmllinkelement;
pub mod htmlmapelement;
pub mod htmlmediaelement;
pub mod htmlmetaelement;
pub mod htmlmeterelement;
pub mod htmlmodelement;
pub mod htmlobjectelement;
pub mod htmlolistelement;
pub mod htmloptgroupelement;
pub mod htmloptionelement;
pub mod htmloutputelement;
pub mod htmlparagraphelement;
pub mod htmlparamelement;
pub mod htmlpreelement;
pub mod htmlprogresselement;
pub mod htmlquoteelement;
pub mod htmlscriptelement;
pub mod htmlselectelement;
pub mod htmlspanelement;
pub mod htmlsourceelement;
pub mod htmlstyleelement;
pub mod htmltableelement;
pub mod htmltablecaptionelement;
pub mod htmltablecellelement;
pub mod htmltabledatacellelement;
pub mod htmltableheadercellelement;
pub mod htmltablecolelement;
pub mod htmltablerowelement;
pub mod htmltablesectionelement;
pub mod htmltemplateelement;
pub mod htmltextareaelement;
pub mod htmltimeelement;
pub mod htmltitleelement;
pub mod htmltrackelement;
pub mod htmlulistelement;
pub mod htmlvideoelement;
pub mod htmlunknownelement;
pub mod imagedata;
pub mod keyboardevent;
pub mod location;
pub mod messageevent;
pub mod mouseevent;
pub mod namednodemap;
pub mod navigator;
pub mod navigatorinfo;
pub mod node;
pub mod nodeiterator;
pub mod nodelist;
pub mod processinginstruction;
pub mod performance;
pub mod performancetiming;
pub mod progressevent;
pub mod range;
pub mod screen;
pub mod servohtmlparser;
pub mod storage;
pub mod storageevent;
pub mod text;
pub mod textdecoder;
pub mod textencoder;
pub mod treewalker;
pub mod uievent;
pub mod urlhelper;
pub mod urlsearchparams;
pub mod userscripts;
pub mod validitystate;
pub mod virtualmethods;
pub mod webglobject;
pub mod webglbuffer;
pub mod webglprogram;
pub mod webglrenderingcontext;
pub mod webglshader;
pub mod webgluniformlocation;
pub mod webgltexture;
pub mod webglframebuffer;
pub mod webglrenderbuffer;
pub mod websocket;
pub mod window;
pub mod worker;
pub mod workerglobalscope;
pub mod workerlocation;
pub mod workernavigator;
pub mod xmlhttprequest;
pub mod xmlhttprequesteventtarget;
pub mod xmlhttprequestupload;

pub mod testbinding;
pub mod testbindingproxy;
<commit_msg>Fix a typo in the DOM documentation.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! The implementation of the DOM.
//!
//! The DOM is comprised of interfaces (defined by specifications using
//! [WebIDL](https://heycam.github.io/webidl/)) that are implemented as Rust
//! structs in submodules of this module. Its implementation is documented
//! below.
//!
//! A DOM object and its reflector
//! ==============================
//!
//! The implementation of an interface `Foo` in Servo's DOM involves two
//! related but distinct objects:
//!
//! * the **DOM object**: an instance of the Rust struct `dom::foo::Foo`
//!   (marked with the `#[dom_struct]` attribute) on the Rust heap;
//! * the **reflector**: a `JSObject` allocated by SpiderMonkey, that owns the
//!   DOM object.
//!
//! Memory management
//! =================
//!
//! Reflectors of DOM objects, and thus the DOM objects themselves, are managed
//! by the SpiderMonkey Garbage Collector. Thus, keeping alive a DOM object
//! is done through its reflector.
//!
//! For more information, see:
//!
//! * rooting pointers on the stack: the [`Root`](bindings/js/struct.Root.html)
//!   and [`JSRef`](bindings/js/struct.JSRef.html) smart pointers;
//! * tracing pointers in member fields: the [`JS`](bindings/js/struct.JS.html),
//!   [`MutNullableJS`](bindings/js/struct.MutNullableJS.html) and
//!   [`MutHeap`](bindings/js/struct.MutHeap.html) smart pointers and
//!   [the tracing implementation](bindings/trace/index.html);
//! * returning pointers from functions: the
//!   [`Temporary`](bindings/js/struct.Temporary.html) smart pointer;
//! * rooting pointers from across task boundaries or in channels: the
//!   [`Trusted`](bindings/refcounted/struct.Trusted.html) smart pointer;
//! * extracting pointers to DOM objects from their reflectors: the
//!   [`Unrooted`](bindings/js/struct.Unrooted.html) smart pointer.
//!
//! Inheritance
//! ===========
//!
//! Rust does not support struct inheritance, as would be used for the
//! object-oriented DOM APIs. To work around this issue, Servo stores an
//! instance of the superclass in the first field of its subclasses. (Note that
//! it is stored by value, rather than in a smart pointer such as `JS<T>`.)
//!
//! This implies that a pointer to an object can safely be cast to a pointer
//! to all its classes.
//!
//! This invariant is enforced by the lint in
//! `plugins::lints::inheritance_integrity`.
//!
//! Construction
//! ============
//!
//! DOM objects of type `T` in Servo have two constructors:
//!
//! * a `T::new_inherited` static method that returns a plain `T`, and
//! * a `T::new` static method that returns `Temporary<T>`.
//!
//! (The result of either method can be wrapped in `Result`, if that is
//! appropriate for the type in question.)
//!
//! The latter calls the former, boxes the result, and creates a reflector
//! corresponding to it by calling `dom::bindings::utils::reflect_dom_object`
//! (which yields ownership of the object to the SpiderMonkey Garbage Collector).
//! This is the API to use when creating a DOM object.
//!
//! The former should only be called by the latter, and by subclasses'
//! `new_inherited` methods.
//!
//! DOM object constructors in JavaScript correspond to a `T::Constructor`
//! static method. This method is always fallible.
//!
//! Destruction
//! ===========
//!
//! When the SpiderMonkey Garbage Collector discovers that the reflector of a
//! DOM object is garbage, it calls the reflector's finalization hook. This
//! function deletes the reflector's DOM object, calling its destructor in the
//! process.
//!
//! Mutability and aliasing
//! =======================
//!
//! Reflectors are JavaScript objects, and as such can be freely aliased. As
//! Rust does not allow mutable aliasing, mutable borrows of DOM objects are
//! not allowed. In particular, any mutable fields use `Cell` or `DOMRefCell`
//! to manage their mutability.
//!
//! `Reflector` and `Reflectable`
//! =============================
//!
//! Every DOM object has a `Reflector` as its first (transitive) member field.
//! This contains a `*mut JSObject` that points to its reflector.
//!
//! The `FooBinding::Wrap` function creates the reflector, stores a pointer to
//! the DOM object in the reflector, and initializes the pointer to the reflector
//! in the `Reflector` field.
//!
//! The `Reflectable` trait provides a `reflector()` method that returns the
//! DOM object's `Reflector`. It is implemented automatically for DOM structs
//! through the `#[dom_struct]` attribute.
//!
//! Implementing methods for a DOM object
//! =====================================
//!
//! In order to ensure that DOM objects are rooted when they are called, we
//! require that all methods are implemented for `JSRef<'a, Foo>`. This means
//! that all methods are defined on traits. Conventionally, those traits are
//! called
//!
//! * `dom::bindings::codegen::Bindings::FooBindings::FooMethods` for methods
//!   defined through IDL;
//! * `FooHelpers` for public methods;
//! * `PrivateFooHelpers` for private methods.
//!
//! Calling methods on a DOM object
//! ===============================
//!
//! To call a method on a DOM object, we require that the object is rooted, by
//! calling `.root()` on a `Temporary` or `JS` pointer. This constructs a
//! `Root` on the stack, which ensures the DOM object stays alive for the
//! duration of its lifetime. A `JSRef` on which to call the method can then be
//! obtained by calling the `r()` method on the `Root`.
//!
//! Accessing fields of a DOM object
//! ================================
//!
//! All fields of DOM objects are private; accessing them from outside their
//! module is done through explicit getter or setter methods.
//!
//! However, `JSRef<T>` dereferences to `&T`, so fields can be accessed on a
//! `JSRef<T>` directly within the module that defines the struct.
//!
//! Inheritance and casting
//! =======================
//!
//! For all DOM interfaces `Foo` in an inheritance chain, a
//! `dom::bindings::codegen::InheritTypes::FooCast` provides methods to cast
//! to other types in the inheritance chain. For example:
//!
//! ```ignore
//! # use script::dom::bindings::js::JSRef;
//! # use script::dom::bindings::codegen::InheritTypes::{NodeCast, HTMLElementCast};
//! # use script::dom::element::Element;
//! # use script::dom::node::Node;
//! # use script::dom::htmlelement::HTMLElement;
//! fn f(element: JSRef<Element>) {
//!     let base: JSRef<Node> = NodeCast::from_ref(element);
//!     let derived: Option<JSRef<HTMLElement>> = HTMLElementCast::to_ref(element);
//! }
//! ```
//!
//! Adding a new DOM interface
//! ==========================
//!
//! Adding a new interface `Foo` requires at least the following:
//!
//! * adding the new IDL file at `components/script/dom/webidls/Foo.webidl`;
//! * creating `components/script/dom/foo.rs`;
//! * listing `foo.rs` in `components/script/dom/mod.rs`;
//! * defining the DOM struct `Foo` with a `#[dom_struct]` attribute, a
//!   superclass or `Reflector` member, and other members as appropriate;
//! * implementing the
//!   `dom::bindings::codegen::Bindings::FooBindings::FooMethods` trait for
//!   `JSRef<Foo>`.
//!
//! More information is available in the [bindings module](bindings/index.html).
//!
//! Accessing DOM objects from layout
//! =================================
//!
//! Layout code can access the DOM through the
//! [`LayoutJS`](bindings/js/struct.LayoutJS.html) smart pointer. This does not
//! keep the DOM object alive; we ensure that no DOM code (Garbage Collection
//! in particular) runs while the layout task is accessing the DOM.
//!
//! Methods accessible to layout are implemented on `LayoutJS<Foo>` using
//! `LayoutFooHelpers` traits.

#[macro_use]
pub mod macros;

pub mod bindings;

#[path="bindings/codegen/InterfaceTypes.rs"]
pub mod types;

pub mod activation;
pub mod attr;
pub mod blob;
pub mod browsercontext;
pub mod canvasgradient;
pub mod canvaspattern;
pub mod canvasrenderingcontext2d;
pub mod characterdata;
pub mod css;
pub mod cssstyledeclaration;
pub mod domrect;
pub mod domrectlist;
pub mod domstringmap;
pub mod closeevent;
pub mod comment;
pub mod console;
mod create;
pub mod customevent;
pub mod dedicatedworkerglobalscope;
pub mod document;
pub mod documentfragment;
pub mod documenttype;
pub mod domexception;
pub mod domimplementation;
pub mod domparser;
pub mod domtokenlist;
pub mod element;
pub mod errorevent;
pub mod event;
pub mod eventdispatcher;
pub mod eventtarget;
pub mod file;
pub mod formdata;
pub mod htmlanchorelement;
pub mod htmlappletelement;
pub mod htmlareaelement;
pub mod htmlaudioelement;
pub mod htmlbaseelement;
pub mod htmlbodyelement;
pub mod htmlbrelement;
pub mod htmlbuttonelement;
pub mod htmlcanvaselement;
pub mod htmlcollection;
pub mod htmldataelement;
pub mod htmldatalistelement;
pub mod htmldialogelement;
pub mod htmldirectoryelement;
pub mod htmldivelement;
pub mod htmldlistelement;
pub mod htmlelement;
pub mod htmlembedelement;
pub mod htmlfieldsetelement;
pub mod htmlfontelement;
pub mod htmlformelement;
pub mod htmlframeelement;
pub mod htmlframesetelement;
pub mod htmlheadelement;
pub mod htmlheadingelement;
pub mod htmlhrelement;
pub mod htmlhtmlelement;
pub mod htmliframeelement;
pub mod htmlimageelement;
pub mod htmlinputelement;
pub mod htmllabelelement;
pub mod htmllegendelement;
pub mod htmllielement;
pub mod htmllinkelement;
pub mod htmlmapelement;
pub mod htmlmediaelement;
pub mod htmlmetaelement;
pub mod htmlmeterelement;
pub mod htmlmodelement;
pub mod htmlobjectelement;
pub mod htmlolistelement;
pub mod htmloptgroupelement;
pub mod htmloptionelement;
pub mod htmloutputelement;
pub mod htmlparagraphelement;
pub mod htmlparamelement;
pub mod htmlpreelement;
pub mod htmlprogresselement;
pub mod htmlquoteelement;
pub mod htmlscriptelement;
pub mod htmlselectelement;
pub mod htmlspanelement;
pub mod htmlsourceelement;
pub mod htmlstyleelement;
pub mod htmltableelement;
pub mod htmltablecaptionelement;
pub mod htmltablecellelement;
pub mod htmltabledatacellelement;
pub mod htmltableheadercellelement;
pub mod htmltablecolelement;
pub mod htmltablerowelement;
pub mod htmltablesectionelement;
pub mod htmltemplateelement;
pub mod htmltextareaelement;
pub mod htmltimeelement;
pub mod htmltitleelement;
pub mod htmltrackelement;
pub mod htmlulistelement;
pub mod htmlvideoelement;
pub mod htmlunknownelement;
pub mod imagedata;
pub mod keyboardevent;
pub mod location;
pub mod messageevent;
pub mod mouseevent;
pub mod namednodemap;
pub mod navigator;
pub mod navigatorinfo;
pub mod node;
pub mod nodeiterator;
pub mod nodelist;
pub mod processinginstruction;
pub mod performance;
pub mod performancetiming;
pub mod progressevent;
pub mod range;
pub mod screen;
pub mod servohtmlparser;
pub mod storage;
pub mod storageevent;
pub mod text;
pub mod textdecoder;
pub mod textencoder;
pub mod treewalker;
pub mod uievent;
pub mod urlhelper;
pub mod urlsearchparams;
pub mod userscripts;
pub mod validitystate;
pub mod virtualmethods;
pub mod webglobject;
pub mod webglbuffer;
pub mod webglprogram;
pub mod webglrenderingcontext;
pub mod webglshader;
pub mod webgluniformlocation;
pub mod webgltexture;
pub mod webglframebuffer;
pub mod webglrenderbuffer;
pub mod websocket;
pub mod window;
pub mod worker;
pub mod workerglobalscope;
pub mod workerlocation;
pub mod workernavigator;
pub mod xmlhttprequest;
pub mod xmlhttprequesteventtarget;
pub mod xmlhttprequestupload;

pub mod testbinding;
pub mod testbindingproxy;
<|endoftext|>


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

use log::{debug, info};

use crate::proto;
use crate::proto::manager::NodeContents_oneof_code_type;
use oak::OakStatus;
use protobuf::{Message, ProtobufEnum};
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::collections::VecDeque;
use std::sync::{Arc, RwLock};

pub struct OakMessage {
    pub data: Vec<u8>,
    pub channels: Vec<ChannelHalf>,
}

#[derive(PartialEq, Copy, Clone, Debug, Eq, Hash)]
pub enum Direction {
    Read,
    Write,
}

/// Unidirectional message-based channel object that also allows fault
/// injection.
struct MockChannel {
    /// If read_status is set, this status value will be returned for any read
    /// operations on the mock channel (and |messages| will be left
    /// undisturbed).
    read_status: Option<u32>,
    /// If write_status is set, this status value will be returned for any write
    /// operations on the mock channel (and |messages| will be left
    /// undisturbed).
    write_status: Option<u32>,
    /// Track extant halves referring to this channel, so that it is possible to
    /// tell when a direction has been orphaned.
    half_count: HashMap<Direction, isize>,
    /// Pending messages on the channel
    messages: VecDeque<OakMessage>,
}

impl MockChannel {
    fn new() -> MockChannel {
        MockChannel {
            read_status: None,
            write_status: None,
            messages: VecDeque::new(),
            half_count: [(Direction::Read, 0), (Direction::Write, 0)]
                .iter()
                .cloned()
                .collect(),
        }
    }
    fn write_message(&mut self, msg: OakMessage) -> u32 {
        if let Some(status) = self.write_status {
            return status;
        }
        if self.half_count[&Direction::Read] == 0 {
            // Channel is orphaned; no-one can ever read this message.
            return OakStatus::ERR_CHANNEL_CLOSED.value() as u32;
        }
        self.messages.push_back(msg);
        OakStatus::OK.value() as u32
    }
    fn read_message(
        &mut self,
        size: usize,
        actual_size: &mut u32,
        handle_count: u32,
        actual_handle_count: &mut u32,
    ) -> Result<OakMessage, u32> {
        if let Some(status) = self.read_status {
            return Err(status);
        }
        match self.messages.pop_front() {
            None => {
                *actual_size = 0;
                *actual_handle_count = 0;
                if self.half_count[&Direction::Write] == 0 {
                    // Channel is empty and there can be no future writers, so
                    // indicate that the channel is closed.
                    Err(OakStatus::ERR_CHANNEL_CLOSED.value() as u32)
                } else {
                    Err(OakStatus::OK.value() as u32)
                }
            }
            Some(msg) => {
                // Check whether the message will fit within caller-specified limits; if
                // not, put it back on the queue (and return the required limits).
                *actual_size = msg.data.len() as u32;
                *actual_handle_count = msg.channels.len() as u32;
                if *actual_size > size as u32 {
                    self.messages.push_front(msg);
                    Err(OakStatus::ERR_BUFFER_TOO_SMALL.value() as u32)
                } else if *actual_handle_count > handle_count {
                    self.messages.push_front(msg);
                    Err(OakStatus::ERR_HANDLE_SPACE_TOO_SMALL.value() as u32)
                } else {
                    Ok(msg)
                }
            }
        }
    }
}

type ChannelRef = Arc<RwLock<MockChannel>>;

// A channel half is a clonable reference to one half of a unidirectional channel.
pub struct ChannelHalf {
    direction: Direction,
    channel: ChannelRef,
}

impl ChannelHalf {
    fn new(direction: Direction, channel: ChannelRef) -> ChannelHalf {
        // Update the referenced channel's counts of extant halves.
        *channel
            .write()
            .expect("internal error: corrupt channel ref")
            .half_count
            .get_mut(&direction)
            .expect("internal error: missing enum value in half_count") += 1;
        ChannelHalf { direction, channel }
    }
}

impl Clone for ChannelHalf {
    fn clone(&self) -> ChannelHalf {
        ChannelHalf::new(self.direction, self.channel.clone())
    }
}

impl Drop for ChannelHalf {
    fn drop(&mut self) {
        // Update the referenced channel's counts of extant halves.
        match self
            .channel
            .write()
            .expect("internal error: corrupt channel ref")
            .half_count
            .entry(self.direction)
        {
            Entry::Occupied(mut e) => {
                if *e.get() <= 0 {
                    panic!("internal error: negative channel ref count");
                }
                *e.get_mut() -= 1;
            }
            Entry::Vacant(_) => panic!("internal error: missing enum value in half_count"),
        };
    }
}

/// Expected type for the main entrypoint of a Node.
pub type NodeMain = fn(u64) -> i32;

pub struct OakRuntime {
    termination_pending: bool,
    // Map name of contents to a test entrypoint function pointer.
    entrypoints: HashMap<String, NodeMain>,
    // Map name of node contents to next index.
    next_index: HashMap<String, u32>,
    // Track a reference to the write half of the channel used for sending
    // gRPC requests in to the Application under test.
    grpc_in_half: Option<ChannelHalf>,
    // Node instances organized by internal Node name.
    nodes: HashMap<String, OakNode>,
}

struct OakNode {
    // Each Node has its own handle numbering space; track the next available
    // handle in this space.
    next_handle: oak::Handle,
    halves: HashMap<oak::Handle, ChannelHalf>,
    // Handle for a thread running the main loop for this node.
    thread_handle: Option<std::thread::JoinHandle<i32>>,
}

// Encapsulate the information needed to start a new per-Node thread.
struct NodeStartInfo {
    entrypoint: NodeMain,
    node_name: String,
    handle: oak::Handle,
}

impl OakRuntime {
    pub fn new(node_name: Option<&str>) -> OakRuntime {
        let mut nodes = HashMap::new();
        if let Some(node_name) = node_name {
            // Set up a single-Node with the given name.
            nodes.insert(node_name.to_string(), OakNode::new());
        }
        OakRuntime {
            termination_pending: false,
            entrypoints: HashMap::new(),
            next_index: HashMap::new(),
            grpc_in_half: None,
            nodes,
        }
    }

    fn entrypoint(&self, contents: &str) -> Option<NodeMain> {
        self.entrypoints.get(contents).copied()
    }

    fn next_node_name(&mut self, contents: &str) -> String {
        let index = self.next_index.entry(contents.to_string()).or_insert(0);
        let name = format!("{}-{}", contents, *index);
        *index += 1;
        name
    }

    // Build a runtime that has Node and Channels set up according to the given
    // Application configuration. Returns a (node-name, entrypoint, handle)
    // tuple indicating the initial Node that should be started.
    pub fn configure(
        &mut self,
        config: proto::manager::ApplicationConfiguration,
        entrypoints: HashMap<String, NodeMain>,
    ) -> Option<(String, NodeMain, oak::Handle)> {
        self.termination_pending = false;
        self.nodes.clear();
        self.entrypoints = entrypoints;
        for contents in config.get_contents() {
            match &contents.code_type {
                None => {
                    panic!("contents {} with no type", contents.name);
                }
                Some(NodeContents_oneof_code_type::log_code(_)) => {
                    self.entrypoints
                        .insert(contents.name.clone(), log_node_main);
                }
                Some(NodeContents_oneof_code_type::wasm_code(_)) => {
                    // Check that we have an entrypoint corresponding to this.
                    if !self.entrypoints.contains_key(&contents.name) {
                        panic!("no entrypoint provided for contents {}", contents.name)
                    }
                }
                Some(NodeContents_oneof_code_type::storage_code(_storage_code)) => {
                    // TODO: Implement a storage pseudo-Node
                }
            }
        }
        let entrypoint = self.entrypoint(&config.initial_node)?;

        let node_name = self.next_node_name(&config.initial_node);
        let mut node = OakNode::new();
        debug!(
            "{{{}}}: add Wasm node running content '{}'",
            node_name, config.initial_node
        );

        // Setup the initial channel from gRPC pseudo-Node to Node.
        let channel = self.new_channel();
        self.grpc_in_half = Some(ChannelHalf::new(Direction::Write, channel.clone()));
        let half = ChannelHalf::new(Direction::Read, channel.clone());
        let handle = node.add_half(half);
        self.nodes.insert(node_name.clone(), node);

        Some((node_name, entrypoint, handle))
    }
    // Record that a Node of the given name has been started in a distinct thread.
    fn started(&mut self, node_name: &str, join_handle: std::thread::JoinHandle<i32>) {
        self.nodes
            .get_mut(node_name)
            .unwrap_or_else(|| panic!("node {{{}}} not found", node_name))
            .thread_handle
            .replace(join_handle);
    }
    fn stop_next(&mut self) -> Option<(String, std::thread::JoinHandle<i32>)> {
        for (name, node) in &mut self.nodes {
            if let Some(h) = node.thread_handle.take() {
                return Some((name.to_string(), h));
            }
        }
        None
    }
    pub fn reset(&mut self) {
        for node in self.nodes.values_mut() {
            node.halves.clear();
        }
        self.grpc_in_half = None;
    }
    fn new_channel(&mut self) -> ChannelRef {
        Arc::new(RwLock::new(MockChannel::new()))
    }
    pub fn node_half_for_handle(
        &self,
        node_name: &str,
        handle: oak::Handle,
    ) -> Option<ChannelHalf> {
        let node = self.nodes.get(node_name)?;
        let half = node.halves.get(&handle)?;
        Some(half.clone())
    }
    fn node_half_for_handle_dir(
        &self,
        node_name: &str,
        handle: oak::Handle,
        dir: Direction,
    ) -> Option<ChannelHalf> {
        let half = self.node_half_for_handle(node_name, handle)?;
        if half.direction != dir {
            return None;
        }
        Some(half)
    }
    pub fn node_add_half(&mut self, node_name: &str, half: ChannelHalf) -> oak::Handle {
        self.nodes
            .get_mut(node_name)
            .unwrap_or_else(|| panic!("node {{{}}} not found", node_name))
            .add_half(half)
    }
    pub fn node_channel_create(&mut self, node_name: &str) -> (oak::Handle, oak::Handle) {
        let channel = self.new_channel();
        let write_half = ChannelHalf::new(Direction::Write, channel.clone());
        let read_half = ChannelHalf::new(Direction::Read, channel.clone());
        let node = self
            .nodes
            .get_mut(node_name)
            .unwrap_or_else(|| panic!("node {{{}}} not found", node_name));
        (node.add_half(write_half), node.add_half(read_half))
    }
    pub fn node_channel_write(
        &mut self,
        node_name: &str,
        handle: oak::Handle,
        msg: OakMessage,
    ) -> u32 {
        match self.node_half_for_handle_dir(node_name, handle, Direction::Write) {
            None => oak::OakStatus::ERR_BAD_HANDLE.value() as u32,
            Some(half) => half
                .channel
                .write()
                .expect("internal error: corrupt channel ref")
                .write_message(msg),
        }
    }
    pub fn node_channel_read(
        &mut self,
        node_name: &str,
        handle: oak::Handle,
        size: usize,
        actual_size: &mut u32,
        handle_count: u32,
        actual_handle_count: &mut u32,
    ) -> Result<OakMessage, u32> {
        match self.node_half_for_handle_dir(node_name, handle, Direction::Read) {
            None => Err(oak::OakStatus::ERR_BAD_HANDLE.value() as u32),
            Some(half) => half
                .channel
                .write()
                .expect("internal error: corrupt channel ref")
                .read_message(size, actual_size, handle_count, actual_handle_count),
        }
    }
    pub fn channel_status_for_node(
        &self,
        node_name: &str,
        handle: oak::Handle,
    ) -> oak::ChannelReadStatus {
        match self.node_half_for_handle_dir(node_name, handle, Direction::Read) {
            None => oak::ChannelReadStatus::INVALID_CHANNEL,
            Some(half) => {
                let channel = half
                    .channel
                    .read()
                    .expect("internal error: corrupt channel ref");
                if !channel.messages.is_empty() {
                    oak::ChannelReadStatus::READ_READY
                } else if channel.half_count[&Direction::Write] == 0 {
                    oak::ChannelReadStatus::ORPHANED
                } else {
                    oak::ChannelReadStatus::NOT_READY
                }
            }
        }
    }
    fn grpc_channel_setup(&mut self, node_name: &str) -> oak::Handle {
        let channel = self.new_channel();
        let half = ChannelHalf::new(Direction::Read, channel.clone());
        let node = self
            .nodes
            .get_mut(node_name)
            .unwrap_or_else(|| panic!("node {{{}}} not found", node_name));
        let read_handle = node.add_half(half);
        debug!(
            "set up gRPC channel to node {} with handle {}",
            node_name, read_handle
        );
        // Remember the write half of the channel to allow future test
        // injection of gRPC requests.
        self.grpc_in_half = Some(ChannelHalf::new(Direction::Write, channel));
        read_handle
    }
    fn grpc_channel(&self) -> Option<ChannelRef> {
        let half = self.grpc_in_half.as_ref()?;
        Some(half.channel.clone())
    }
    fn node_create(
        &mut self,
        node_name: String,
        contents: &str,
        handle: oak::Handle,
    ) -> Result<NodeStartInfo, OakStatus> {
        // First, find the code referred to by the contents name.
        let entrypoint = match self.entrypoint(&contents) {
            Some(e) => e,
            None => {
                debug!(
                    "{{{}}}: node_create('{}', {}) -> ERR_INVALID_ARGS",
                    node_name, contents, handle
                );
                return Err(OakStatus::ERR_INVALID_ARGS);
            }
        };

        // Next, convert the creating Node's handle to a channel reference.
        let half = match self.node_half_for_handle_dir(&node_name, handle, Direction::Read) {
            Some(h) => h,
            None => {
                debug!(
                    "{{{}}}: node_create('{}', {}) -> ERR_BAD_HANDLE",
                    node_name, contents, handle
                );
                return Err(OakStatus::ERR_BAD_HANDLE);
            }
        };

        // Create the new Node instance.
        let new_node_name = self.next_node_name(&contents);
        let node = OakNode::new();
        debug!(
            "{{{}}}: add node running content '{}'",
            new_node_name, contents
        );
        self.nodes.insert(new_node_name.to_string(), node);

        // Map the channel into the new Node's handle space.
        let new_handle = self.node_add_half(&new_node_name, half);

        // Return enough information to allow the new Node to be started:
        // entrypoint, name and initial handle value.
        Ok(NodeStartInfo {
            entrypoint,
            node_name: new_node_name,
            handle: new_handle,
        })
    }
}

impl OakNode {
    fn new() -> OakNode {
        OakNode {
            next_handle: 1 as oak::Handle,
            halves: HashMap::new(),
            thread_handle: None,
        }
    }
    fn add_half(&mut self, half: ChannelHalf) -> oak::Handle {
        let handle = self.next_handle;
        self.next_handle += 1;
        self.halves.insert(handle, half);
        handle
    }
    fn close_channel(&mut self, handle: oak::Handle) -> u32 {
        if !self.halves.contains_key(&handle) {
            return OakStatus::ERR_BAD_HANDLE.value() as u32;
        }
        self.halves.remove(&handle);
        OakStatus::OK.value() as u32
    }
}

// Main loop function for a log pseudo-Node.
fn log_node_main(handle: u64) -> i32 {
    if handle == oak_abi::INVALID_HANDLE {
        return OakStatus::ERR_BAD_HANDLE.value();
    }
    let half = oak::ReadHandle { handle };
    loop {
        if let Err(status) = oak::wait_on_channels(&[half]) {
            return status.value();
        }
        let mut buf = Vec::<u8>::with_capacity(1024);
        let mut handles = Vec::with_capacity(8);
        oak::channel_read(half, &mut buf, &mut handles);
        if buf.is_empty() {
            debug!("no pending message; poll again");
            continue;
        }
        let message = String::from_utf8_lossy(&buf);
        info!("LOG: {}", message);
    }
}
<commit_msg>Remove unused `sdk/rust/oak_tests/src/runtime.rs` (#465)<commit_after><|endoftext|>


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

use crate::io::ErrorKind;

pub use self::rand::hashmap_random_keys;
pub use crate::os::vxworks as platform;
pub use libc::strlen;

#[path = "../unix/alloc.rs"]
pub mod alloc;
pub mod args;
pub mod cmath;
#[path = "../unix/condvar.rs"]
pub mod condvar;
pub mod env;
pub mod ext;
pub mod fd;
pub mod fs;
pub mod io;
pub mod memchr;
#[path = "../unix/mutex.rs"]
pub mod mutex;
pub mod net;
pub mod os;
pub mod path;
pub mod pipe;
pub mod process;
pub mod rand;
#[path = "../unix/rwlock.rs"]
pub mod rwlock;
#[path = "../unix/stack_overflow.rs"]
pub mod stack_overflow;
#[path = "../unix/stdio.rs"]
pub mod stdio;
#[path = "../unix/thread.rs"]
pub mod thread;
pub mod thread_local_dtor;
#[path = "../unix/thread_local_key.rs"]
pub mod thread_local_key;
#[path = "../unix/time.rs"]
pub mod time;

pub use crate::sys_common::os_str_bytes as os_str;

#[cfg(not(test))]
pub fn init() {
    // ignore SIGPIPE
    unsafe {
        assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
    }
}

pub use libc::signal;

pub fn decode_error_kind(errno: i32) -> ErrorKind {
    match errno as libc::c_int {
        libc::ECONNREFUSED => ErrorKind::ConnectionRefused,
        libc::ECONNRESET => ErrorKind::ConnectionReset,
        libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied,
        libc::EPIPE => ErrorKind::BrokenPipe,
        libc::ENOTCONN => ErrorKind::NotConnected,
        libc::ECONNABORTED => ErrorKind::ConnectionAborted,
        libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
        libc::EADDRINUSE => ErrorKind::AddrInUse,
        libc::ENOENT => ErrorKind::NotFound,
        libc::EINTR => ErrorKind::Interrupted,
        libc::EINVAL => ErrorKind::InvalidInput,
        libc::ETIMEDOUT => ErrorKind::TimedOut,
        libc::EEXIST => ErrorKind::AlreadyExists,

        // These two constants can have the same value on some systems,
        // but different values on others, so we can't use a match
        // clause
        x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => ErrorKind::WouldBlock,

        _ => ErrorKind::Other,
    }
}

#[doc(hidden)]
pub trait IsMinusOne {
    fn is_minus_one(&self) -> bool;
}

macro_rules! impl_is_minus_one {
    ($($t:ident)*) => ($(impl IsMinusOne for $t {
        fn is_minus_one(&self) -> bool {
            *self == -1
        }
    })*)
}

impl_is_minus_one! { i8 i16 i32 i64 isize }

pub fn cvt<T: IsMinusOne>(t: T) -> crate::io::Result<T> {
    if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) }
}

pub fn cvt_r<T, F>(mut f: F) -> crate::io::Result<T>
where
    T: IsMinusOne,
    F: FnMut() -> T,
{
    loop {
        match cvt(f()) {
            Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
            other => return other,
        }
    }
}

// On Unix-like platforms, libc::abort will unregister signal handlers
// including the SIGABRT handler, preventing the abort from being blocked, and
// fclose streams, with the side effect of flushing them so libc buffered
// output will be printed.  Additionally the shell will generally print a more
// understandable error message like "Abort trap" rather than "Illegal
// instruction" that intrinsics::abort would cause, as intrinsics::abort is
// implemented as an illegal instruction.
pub fn abort_internal() -> ! {
    unsafe { libc::abort() }
}
<commit_msg>Add weak macro to vxworks.<commit_after>#![allow(dead_code)]
#![allow(missing_docs, nonstandard_style)]

use crate::io::ErrorKind;

pub use self::rand::hashmap_random_keys;
pub use crate::os::vxworks as platform;
pub use libc::strlen;

#[macro_use]
#[path = "../unix/weak.rs"]
pub mod weak;

#[path = "../unix/alloc.rs"]
pub mod alloc;
pub mod args;
pub mod cmath;
#[path = "../unix/condvar.rs"]
pub mod condvar;
pub mod env;
pub mod ext;
pub mod fd;
pub mod fs;
pub mod io;
pub mod memchr;
#[path = "../unix/mutex.rs"]
pub mod mutex;
pub mod net;
pub mod os;
pub mod path;
pub mod pipe;
pub mod process;
pub mod rand;
#[path = "../unix/rwlock.rs"]
pub mod rwlock;
#[path = "../unix/stack_overflow.rs"]
pub mod stack_overflow;
#[path = "../unix/stdio.rs"]
pub mod stdio;
#[path = "../unix/thread.rs"]
pub mod thread;
pub mod thread_local_dtor;
#[path = "../unix/thread_local_key.rs"]
pub mod thread_local_key;
#[path = "../unix/time.rs"]
pub mod time;

pub use crate::sys_common::os_str_bytes as os_str;

#[cfg(not(test))]
pub fn init() {
    // ignore SIGPIPE
    unsafe {
        assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
    }
}

pub use libc::signal;

pub fn decode_error_kind(errno: i32) -> ErrorKind {
    match errno as libc::c_int {
        libc::ECONNREFUSED => ErrorKind::ConnectionRefused,
        libc::ECONNRESET => ErrorKind::ConnectionReset,
        libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied,
        libc::EPIPE => ErrorKind::BrokenPipe,
        libc::ENOTCONN => ErrorKind::NotConnected,
        libc::ECONNABORTED => ErrorKind::ConnectionAborted,
        libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
        libc::EADDRINUSE => ErrorKind::AddrInUse,
        libc::ENOENT => ErrorKind::NotFound,
        libc::EINTR => ErrorKind::Interrupted,
        libc::EINVAL => ErrorKind::InvalidInput,
        libc::ETIMEDOUT => ErrorKind::TimedOut,
        libc::EEXIST => ErrorKind::AlreadyExists,

        // These two constants can have the same value on some systems,
        // but different values on others, so we can't use a match
        // clause
        x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => ErrorKind::WouldBlock,

        _ => ErrorKind::Other,
    }
}

#[doc(hidden)]
pub trait IsMinusOne {
    fn is_minus_one(&self) -> bool;
}

macro_rules! impl_is_minus_one {
    ($($t:ident)*) => ($(impl IsMinusOne for $t {
        fn is_minus_one(&self) -> bool {
            *self == -1
        }
    })*)
}

impl_is_minus_one! { i8 i16 i32 i64 isize }

pub fn cvt<T: IsMinusOne>(t: T) -> crate::io::Result<T> {
    if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) }
}

pub fn cvt_r<T, F>(mut f: F) -> crate::io::Result<T>
where
    T: IsMinusOne,
    F: FnMut() -> T,
{
    loop {
        match cvt(f()) {
            Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
            other => return other,
        }
    }
}

// On Unix-like platforms, libc::abort will unregister signal handlers
// including the SIGABRT handler, preventing the abort from being blocked, and
// fclose streams, with the side effect of flushing them so libc buffered
// output will be printed.  Additionally the shell will generally print a more
// understandable error message like "Abort trap" rather than "Illegal
// instruction" that intrinsics::abort would cause, as intrinsics::abort is
// implemented as an illegal instruction.
pub fn abort_internal() -> ! {
    unsafe { libc::abort() }
}
<|endoftext|>


<commit_before>use clap::ArgMatches;
use fork_choice::ForkChoiceAlgorithm;
use network::NetworkConfig;
use slog::error;
use std::fs;
use std::net::SocketAddr;
use std::net::{IpAddr, Ipv4Addr};
use std::path::PathBuf;
use types::multiaddr::Protocol;
use types::multiaddr::ToMultiaddr;
use types::Multiaddr;
use types::{ChainSpec, EthSpec, LighthouseTestnetEthSpec};

#[derive(Debug, Clone)]
pub enum DBType {
    Memory,
    Disk,
}

/// Stores the client configuration for this Lighthouse instance.
#[derive(Debug, Clone)]
pub struct ClientConfig {
    pub data_dir: PathBuf,
    pub spec: ChainSpec,
    pub net_conf: network::NetworkConfig,
    pub fork_choice: ForkChoiceAlgorithm,
    pub db_type: DBType,
    pub db_name: PathBuf,
    pub rpc_conf: rpc::RPCConfig,
    //pub ipc_conf:
}

impl Default for ClientConfig {
    /// Build a new lighthouse configuration from defaults.
    fn default() -> Self {
        let data_dir = {
            let home = dirs::home_dir().expect("Unable to determine home dir.");
            home.join(".lighthouse/")
        };
        fs::create_dir_all(&data_dir)
            .unwrap_or_else(|_| panic!("Unable to create {:?}", &data_dir));

        let default_spec = LighthouseTestnetEthSpec::spec();
        let default_net_conf = NetworkConfig::new(default_spec.boot_nodes.clone());

        Self {
            data_dir: data_dir.clone(),
            // default to foundation for chain specs
            spec: default_spec,
            net_conf: default_net_conf,
            // default to bitwise LMD Ghost
            fork_choice: ForkChoiceAlgorithm::BitwiseLMDGhost,
            // default to memory db for now
            db_type: DBType::Memory,
            // default db name for disk-based dbs
            db_name: data_dir.join("chain.db"),
            rpc_conf: rpc::RPCConfig::default(),
        }
    }
}

impl ClientConfig {
    /// Parses the CLI arguments into a `Config` struct.
    pub fn parse_args(args: ArgMatches, log: &slog::Logger) -> Result<Self, &'static str> {
        let mut config = ClientConfig::default();

        /* Network related arguments */

        // Custom p2p listen port
        if let Some(port_str) = args.value_of("port") {
            if let Ok(port) = port_str.parse::<u16>() {
                config.net_conf.listen_port = port;
                // update the listening multiaddrs
                for address in &mut config.net_conf.listen_addresses {
                    address.pop();
                    address.append(Protocol::Tcp(port));
                }
            } else {
                error!(log, "Invalid port"; "port" => port_str);
                return Err("Invalid port");
            }
        }
        // Custom listening address ipv4/ipv6
        // TODO: Handle list of addresses
        if let Some(listen_address_str) = args.value_of("listen-address") {
            if let Ok(listen_address) = listen_address_str.parse::<IpAddr>() {
                let multiaddr = SocketAddr::new(listen_address, config.net_conf.listen_port)
                    .to_multiaddr()
                    .expect("Invalid listen address format");
                config.net_conf.listen_addresses = vec![multiaddr];
            } else {
                error!(log, "Invalid IP Address"; "Address" => listen_address_str);
                return Err("Invalid IP Address");
            }
        }

        // Custom bootnodes
        // TODO: Handle list of addresses
        if let Some(boot_addresses_str) = args.value_of("boot-nodes") {
            if let Ok(boot_address) = boot_addresses_str.parse::<Multiaddr>() {
                config.net_conf.boot_nodes.append(&mut vec![boot_address]);
            } else {
                error!(log, "Invalid Bootnode multiaddress"; "Multiaddr" => boot_addresses_str);
                return Err("Invalid IP Address");
            }
        }

        /* Filesystem related arguments */

        // Custom datadir
        if let Some(dir) = args.value_of("datadir") {
            config.data_dir = PathBuf::from(dir.to_string());
        };

        /* RPC related arguments */

        if args.is_present("rpc") {
            config.rpc_conf.enabled = true;
        }

        if let Some(rpc_address) = args.value_of("rpc-address") {
            if let Ok(listen_address) = rpc_address.parse::<Ipv4Addr>() {
                config.rpc_conf.listen_address = listen_address;
            } else {
                error!(log, "Invalid RPC listen address"; "Address" => rpc_address);
                return Err("Invalid RPC listen address");
            }
        }

        if let Some(rpc_port) = args.value_of("rpc-port") {
            if let Ok(port) = rpc_port.parse::<u16>() {
                config.rpc_conf.port = port;
            } else {
                error!(log, "Invalid RPC port"; "port" => rpc_port);
                return Err("Invalid RPC port");
            }
        }

        match args.value_of("db") {
            Some("disk") => config.db_type = DBType::Disk,
            Some("memory") => config.db_type = DBType::Memory,
            _ => unreachable!(), // clap prevents this.
        };

        Ok(config)
    }
}
<commit_msg>Rename disk db dir<commit_after>use clap::ArgMatches;
use fork_choice::ForkChoiceAlgorithm;
use network::NetworkConfig;
use slog::error;
use std::fs;
use std::net::SocketAddr;
use std::net::{IpAddr, Ipv4Addr};
use std::path::PathBuf;
use types::multiaddr::Protocol;
use types::multiaddr::ToMultiaddr;
use types::Multiaddr;
use types::{ChainSpec, EthSpec, LighthouseTestnetEthSpec};

#[derive(Debug, Clone)]
pub enum DBType {
    Memory,
    Disk,
}

/// Stores the client configuration for this Lighthouse instance.
#[derive(Debug, Clone)]
pub struct ClientConfig {
    pub data_dir: PathBuf,
    pub spec: ChainSpec,
    pub net_conf: network::NetworkConfig,
    pub fork_choice: ForkChoiceAlgorithm,
    pub db_type: DBType,
    pub db_name: PathBuf,
    pub rpc_conf: rpc::RPCConfig,
    //pub ipc_conf:
}

impl Default for ClientConfig {
    /// Build a new lighthouse configuration from defaults.
    fn default() -> Self {
        let data_dir = {
            let home = dirs::home_dir().expect("Unable to determine home dir.");
            home.join(".lighthouse/")
        };
        fs::create_dir_all(&data_dir)
            .unwrap_or_else(|_| panic!("Unable to create {:?}", &data_dir));

        let default_spec = LighthouseTestnetEthSpec::spec();
        let default_net_conf = NetworkConfig::new(default_spec.boot_nodes.clone());

        Self {
            data_dir: data_dir.clone(),
            // default to foundation for chain specs
            spec: default_spec,
            net_conf: default_net_conf,
            // default to bitwise LMD Ghost
            fork_choice: ForkChoiceAlgorithm::BitwiseLMDGhost,
            // default to memory db for now
            db_type: DBType::Memory,
            // default db name for disk-based dbs
            db_name: data_dir.join("chain_db"),
            rpc_conf: rpc::RPCConfig::default(),
        }
    }
}

impl ClientConfig {
    /// Parses the CLI arguments into a `Config` struct.
    pub fn parse_args(args: ArgMatches, log: &slog::Logger) -> Result<Self, &'static str> {
        let mut config = ClientConfig::default();

        /* Network related arguments */

        // Custom p2p listen port
        if let Some(port_str) = args.value_of("port") {
            if let Ok(port) = port_str.parse::<u16>() {
                config.net_conf.listen_port = port;
                // update the listening multiaddrs
                for address in &mut config.net_conf.listen_addresses {
                    address.pop();
                    address.append(Protocol::Tcp(port));
                }
            } else {
                error!(log, "Invalid port"; "port" => port_str);
                return Err("Invalid port");
            }
        }
        // Custom listening address ipv4/ipv6
        // TODO: Handle list of addresses
        if let Some(listen_address_str) = args.value_of("listen-address") {
            if let Ok(listen_address) = listen_address_str.parse::<IpAddr>() {
                let multiaddr = SocketAddr::new(listen_address, config.net_conf.listen_port)
                    .to_multiaddr()
                    .expect("Invalid listen address format");
                config.net_conf.listen_addresses = vec![multiaddr];
            } else {
                error!(log, "Invalid IP Address"; "Address" => listen_address_str);
                return Err("Invalid IP Address");
            }
        }

        // Custom bootnodes
        // TODO: Handle list of addresses
        if let Some(boot_addresses_str) = args.value_of("boot-nodes") {
            if let Ok(boot_address) = boot_addresses_str.parse::<Multiaddr>() {
                config.net_conf.boot_nodes.append(&mut vec![boot_address]);
            } else {
                error!(log, "Invalid Bootnode multiaddress"; "Multiaddr" => boot_addresses_str);
                return Err("Invalid IP Address");
            }
        }

        /* Filesystem related arguments */

        // Custom datadir
        if let Some(dir) = args.value_of("datadir") {
            config.data_dir = PathBuf::from(dir.to_string());
        };

        /* RPC related arguments */

        if args.is_present("rpc") {
            config.rpc_conf.enabled = true;
        }

        if let Some(rpc_address) = args.value_of("rpc-address") {
            if let Ok(listen_address) = rpc_address.parse::<Ipv4Addr>() {
                config.rpc_conf.listen_address = listen_address;
            } else {
                error!(log, "Invalid RPC listen address"; "Address" => rpc_address);
                return Err("Invalid RPC listen address");
            }
        }

        if let Some(rpc_port) = args.value_of("rpc-port") {
            if let Ok(port) = rpc_port.parse::<u16>() {
                config.rpc_conf.port = port;
            } else {
                error!(log, "Invalid RPC port"; "port" => rpc_port);
                return Err("Invalid RPC port");
            }
        }

        match args.value_of("db") {
            Some("disk") => config.db_type = DBType::Disk,
            Some("memory") => config.db_type = DBType::Memory,
            _ => unreachable!(), // clap prevents this.
        };

        Ok(config)
    }
}
<|endoftext|>


<commit_before>extern crate image;
extern crate img_hash;
extern crate postgres;
#[macro_use]
extern crate log;
extern crate log4rs;
extern crate time;
extern crate hyper;
extern crate url;
extern crate png;

use std::env;
use postgres::{Connection, SslMode};
use img_hash::{ImageHash, HashType};
use std::thread;
use std::default::Default;
use time::{Timespec, Duration};
use hyper::Client;
use hyper::header::ContentType;
use image::ImageFormat;
use std::io::Read;
use hyper::status::StatusCode;
use postgres::stmt::Statement;

fn prepare_statement<'a>(conn: &'a Connection, stmt: &str) -> Statement<'a> {
    loop {
        let prep_stmt = conn.prepare_cached(stmt);
        if prep_stmt.is_err() {
            error!("Error in prepare for '{}': {}",
                   stmt,
                   prep_stmt.unwrap_err());
            thread::sleep_ms(4000);
            continue;
        }
        return prep_stmt.unwrap();
    }
}

fn main() {
    log4rs::init_file("log.toml", Default::default()).unwrap();
    let db_url: &str = &env::var("DATABASE_URL").unwrap();
    let conn = Connection::connect(db_url, &SslMode::None).unwrap();

    let query_stmt = prepare_statement(&conn,
                                       "select * from videos_video order by \"lastRetrieved\" \
                                        desc limit 1");
    let update_stmt = prepare_statement(&conn,
                                        "update videos_video set working = true, hash = $1, \
                                         motion = $2, \"lastRetrieved\" = $3 where id = $4");

    loop {
        let res = query_stmt.query(&[]);
        if res.is_err() {
            error!("Error in query: {}", res.unwrap_err());
            thread::sleep_ms(4000);
            continue;
        }

        let items = res.unwrap();
        if items.len() == 0 {
            warn!("No video feeds");
            thread::sleep_ms(4000);
            continue;
        }
        let item = items.get(0);
        let url: String = item.get("url");
        let when: postgres::Result<Timespec> = item.get_opt("lastRetrieved");
        let id: i32 = item.get("id");
        let old_hash_raw: postgres::Result<String> = item.get_opt("hash");
        let old_hash = ImageHash::from_base64(&old_hash_raw.unwrap()).unwrap();

        if when.is_err() {
            debug!("Item: {}, When: never", url);
        } else {
            let now = time::now().to_timespec();
            let diff: Duration = now - when.unwrap();
            debug!("Item: {}, When: {}", url, diff);
            if diff < Duration::minutes(1) {
                debug!("oldest item is young: {}", diff);
                thread::sleep_ms(4000);
                continue;
            }
        }
        info!("Updating {}", url);

        let mut options = vec![];
        options.push(("url".to_string(), &url));
        let data: &str = &url::form_urlencoded::serialize(&options);

        let mut resp = Client::new()
                           .post("http://imager:8000/streams")
                           .header(ContentType::form_url_encoded())
                           .body(data)
                           .send()
                           .unwrap();

        if resp.status != StatusCode::Ok {
            warn!("{:?}", resp.status_raw());
            thread::sleep_ms(4000);
            continue;
        }

        let mut buf = Vec::new();
        resp.read_to_end(&mut buf).unwrap();
        let image = image::load_from_memory_with_format(&buf, ImageFormat::PNG).unwrap();
        let hash = ImageHash::hash(&image, 16, HashType::DoubleGradient);

        debug!("Image hash: {}", hash.to_base64());
        let motion = old_hash.dist_ratio(&hash) as f64;
        debug!("Difference {}", motion);
        let now = time::now().to_timespec();
        match update_stmt.execute(&[&hash.to_base64(), &motion, &now, &id]) {
            Ok(_) => info!("Updated {} with motion {}", url, motion),
            Err(err) => warn!("Error executing update: {:?}", err),
        }
        thread::sleep_ms(4000);
    }
}
<commit_msg>Cope with blank initial hashes<commit_after>extern crate image;
extern crate img_hash;
extern crate postgres;
#[macro_use]
extern crate log;
extern crate log4rs;
extern crate time;
extern crate hyper;
extern crate url;
extern crate png;

use std::env;
use postgres::{Connection, SslMode};
use img_hash::{ImageHash, HashType};
use std::thread;
use std::default::Default;
use time::{Timespec, Duration};
use hyper::Client;
use hyper::header::ContentType;
use image::ImageFormat;
use std::io::Read;
use hyper::status::StatusCode;
use postgres::stmt::Statement;

fn prepare_statement<'a>(conn: &'a Connection, stmt: &str) -> Statement<'a> {
    loop {
        let prep_stmt = conn.prepare_cached(stmt);
        if prep_stmt.is_err() {
            error!("Error in prepare for '{}': {}",
                   stmt,
                   prep_stmt.unwrap_err());
            thread::sleep_ms(4000);
            continue;
        }
        return prep_stmt.unwrap();
    }
}

fn main() {
    log4rs::init_file("log.toml", Default::default()).unwrap();
    let db_url: &str = &env::var("DATABASE_URL").unwrap();
    let conn = Connection::connect(db_url, &SslMode::None).unwrap();

    let query_stmt = prepare_statement(&conn,
                                       "select * from videos_video order by \"lastRetrieved\" \
                                        desc limit 1");
    let update_stmt = prepare_statement(&conn,
                                        "update videos_video set working = true, hash = $1, \
                                         motion = $2, \"lastRetrieved\" = $3 where id = $4");

    loop {
        let res = query_stmt.query(&[]);
        if res.is_err() {
            error!("Error in query: {}", res.unwrap_err());
            thread::sleep_ms(4000);
            continue;
        }

        let items = res.unwrap();
        if items.len() == 0 {
            warn!("No video feeds");
            thread::sleep_ms(4000);
            continue;
        }
        let item = items.get(0);
        let url: String = item.get("url");
        let when: postgres::Result<Timespec> = item.get_opt("lastRetrieved");
        let id: i32 = item.get("id");
        let old_hash_raw: postgres::Result<String> = item.get_opt("hash");
        let old_hash = ImageHash::from_base64(&old_hash_raw.unwrap());

        if when.is_err() {
            debug!("Item: {}, When: never", url);
        } else {
            let now = time::now().to_timespec();
            let diff: Duration = now - when.unwrap();
            debug!("Item: {}, When: {}", url, diff);
            if diff < Duration::minutes(1) {
                debug!("oldest item is young: {}", diff);
                thread::sleep_ms(4000);
                continue;
            }
        }
        info!("Updating {}", url);

        let mut options = vec![];
        options.push(("url".to_string(), &url));
        let data: &str = &url::form_urlencoded::serialize(&options);

        let mut resp = Client::new()
                           .post("http://imager:8000/streams")
                           .header(ContentType::form_url_encoded())
                           .body(data)
                           .send()
                           .unwrap();

        if resp.status != StatusCode::Ok {
            warn!("{:?}", resp.status_raw());
            thread::sleep_ms(4000);
            continue;
        }

        let mut buf = Vec::new();
        resp.read_to_end(&mut buf).unwrap();
        let image = image::load_from_memory_with_format(&buf, ImageFormat::PNG).unwrap();
        let hash = ImageHash::hash(&image, 16, HashType::DoubleGradient);

        debug!("Image hash: {}", hash.to_base64());
        let motion: f64 = match old_hash {
            Ok(val) => val.dist_ratio(&hash) as f64,
            Err(_) => -1 as f64,
        };
        debug!("Difference {}", motion);
        let now = time::now().to_timespec();
        match update_stmt.execute(&[&hash.to_base64(), &motion, &now, &id]) {
            Ok(_) => info!("Updated {} with motion {}", url, motion),
            Err(err) => warn!("Error executing update: {:?}", err),
        }
        thread::sleep_ms(4000);
    }
}
<|endoftext|>