<commit_before>use crate::consts::{constant, Constant};
use crate::utils::sugg::Sugg;
use crate::utils::{span_lint, span_lint_and_then};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for incompatible bit masks in comparisons.
    ///
    /// The formula for detecting if an expression of the type `_ <bit_op> m
    /// <cmp_op> c` (where `<bit_op>` is one of {`&`, `|`} and `<cmp_op>` is one of
    /// {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following
    /// table:
    ///
    /// |Comparison  |Bit Op|Example     |is always|Formula               |
    /// |------------|------|------------|---------|----------------------|
    /// |`==` or `!=`| `&`  |`x & 2 == 3`|`false`  |`c & m != c`          |
    /// |`<`  or `>=`| `&`  |`x & 2 < 3` |`true`   |`m < c`               |
    /// |`>`  or `<=`| `&`  |`x & 1 > 1` |`false`  |`m <= c`              |
    /// |`==` or `!=`| `|`  |`x | 1 == 0`|`false`  |`c | m != c`          |
    /// |`<`  or `>=`| `|`  |`x | 1 < 1` |`false`  |`m >= c`              |
    /// |`<=` or `>` | `|`  |`x | 1 > 0` |`true`   |`m > c`               |
    ///
    /// **Why is this bad?** If the bits that the comparison cares about are always
    /// set to zero or one by the bit mask, the comparison is constant `true` or
    /// `false` (depending on mask, compared value, and operators).
    ///
    /// So the code is actively misleading, and the only reason someone would write
    /// this intentionally is to win an underhanded Rust contest or create a
    /// test-case for this lint.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// # let x = 1;
    /// if (x & 1 == 2) { }
    /// ```
    pub BAD_BIT_MASK,
    correctness,
    "expressions of the form `_ & mask == select` that will only ever return `true` or `false`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for bit masks in comparisons which can be removed
    /// without changing the outcome. The basic structure can be seen in the
    /// following table:
    ///
    /// |Comparison| Bit Op  |Example    |equals |
    /// |----------|---------|-----------|-------|
    /// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`|
    /// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`|
    ///
    /// **Why is this bad?** Not equally evil as [`bad_bit_mask`](#bad_bit_mask),
    /// but still a bit misleading, because the bit mask is ineffective.
    ///
    /// **Known problems:** False negatives: This lint will only match instances
    /// where we have figured out the math (which is for a power-of-two compared
    /// value). This means things like `x | 1 >= 7` (which would be better written
    /// as `x >= 6`) will not be reported (but bit masks like this are fairly
    /// uncommon).
    ///
    /// **Example:**
    /// ```rust
    /// # let x = 1;
    /// if (x | 1 > 3) {  }
    /// ```
    pub INEFFECTIVE_BIT_MASK,
    correctness,
    "expressions where a bit mask will be rendered useless by a comparison, e.g., `(x | 1) > 2`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for bit masks that can be replaced by a call
    /// to `trailing_zeros`
    ///
    /// **Why is this bad?** `x.trailing_zeros() > 4` is much clearer than `x & 15
    /// == 0`
    ///
    /// **Known problems:** llvm generates better code for `x & 15 == 0` on x86
    ///
    /// **Example:**
    /// ```rust
    /// # let x = 1;
    /// if x & 0x1111 == 0 { }
    /// ```
    pub VERBOSE_BIT_MASK,
    style,
    "expressions where a bit mask is less readable than the corresponding method call"
}

#[derive(Copy, Clone)]
pub struct BitMask {
    verbose_bit_mask_threshold: u64,
}

impl BitMask {
    #[must_use]
    pub fn new(verbose_bit_mask_threshold: u64) -> Self {
        Self {
            verbose_bit_mask_threshold,
        }
    }
}

impl_lint_pass!(BitMask => [BAD_BIT_MASK, INEFFECTIVE_BIT_MASK, VERBOSE_BIT_MASK]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BitMask {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
        if let ExprKind::Binary(cmp, left, right) = &e.kind {
            if cmp.node.is_comparison() {
                if let Some(cmp_opt) = fetch_int_literal(cx, right) {
                    check_compare(cx, left, cmp.node, cmp_opt, e.span)
                } else if let Some(cmp_val) = fetch_int_literal(cx, left) {
                    check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span)
                }
            }
        }
        if_chain! {
            if let ExprKind::Binary(op, left, right) = &e.kind;
            if BinOpKind::Eq == op.node;
            if let ExprKind::Binary(op1, left1, right1) = &left.kind;
            if BinOpKind::BitAnd == op1.node;
            if let ExprKind::Lit(lit) = &right1.kind;
            if let LitKind::Int(n, _) = lit.node;
            if let ExprKind::Lit(lit1) = &right.kind;
            if let LitKind::Int(0, _) = lit1.node;
            if n.leading_zeros() == n.count_zeros();
            if n > u128::from(self.verbose_bit_mask_threshold);
            then {
                span_lint_and_then(cx,
                                   VERBOSE_BIT_MASK,
                                   e.span,
                                   "bit mask could be simplified with a call to `trailing_zeros`",
                                   |db| {
                    let sugg = Sugg::hir(cx, left1, "...").maybe_par();
                    db.span_suggestion(
                        e.span,
                        "try",
                        format!("{}.trailing_zeros() >= {}", sugg, n.count_ones()),
                        Applicability::MaybeIncorrect,
                    );
                });
            }
        }
    }
}

#[must_use]
fn invert_cmp(cmp: BinOpKind) -> BinOpKind {
    match cmp {
        BinOpKind::Eq => BinOpKind::Eq,
        BinOpKind::Ne => BinOpKind::Ne,
        BinOpKind::Lt => BinOpKind::Gt,
        BinOpKind::Gt => BinOpKind::Lt,
        BinOpKind::Le => BinOpKind::Ge,
        BinOpKind::Ge => BinOpKind::Le,
        _ => BinOpKind::Or, // Dummy
    }
}

fn check_compare(cx: &LateContext<'_, '_>, bit_op: &Expr<'_>, cmp_op: BinOpKind, cmp_value: u128, span: Span) {
    if let ExprKind::Binary(op, left, right) = &bit_op.kind {
        if op.node != BinOpKind::BitAnd && op.node != BinOpKind::BitOr {
            return;
        }
        fetch_int_literal(cx, right)
            .or_else(|| fetch_int_literal(cx, left))
            .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span))
    }
}

#[allow(clippy::too_many_lines)]
fn check_bit_mask(
    cx: &LateContext<'_, '_>,
    bit_op: BinOpKind,
    cmp_op: BinOpKind,
    mask_value: u128,
    cmp_value: u128,
    span: Span,
) {
    match cmp_op {
        BinOpKind::Eq | BinOpKind::Ne => match bit_op {
            BinOpKind::BitAnd => {
                if mask_value & cmp_value != cmp_value {
                    if cmp_value != 0 {
                        span_lint(
                            cx,
                            BAD_BIT_MASK,
                            span,
                            &format!(
                                "incompatible bit mask: `_ & {}` can never be equal to `{}`",
                                mask_value, cmp_value
                            ),
                        );
                    }
                } else if mask_value == 0 {
                    span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
                }
            },
            BinOpKind::BitOr => {
                if mask_value | cmp_value != cmp_value {
                    span_lint(
                        cx,
                        BAD_BIT_MASK,
                        span,
                        &format!(
                            "incompatible bit mask: `_ | {}` can never be equal to `{}`",
                            mask_value, cmp_value
                        ),
                    );
                }
            },
            _ => (),
        },
        BinOpKind::Lt | BinOpKind::Ge => match bit_op {
            BinOpKind::BitAnd => {
                if mask_value < cmp_value {
                    span_lint(
                        cx,
                        BAD_BIT_MASK,
                        span,
                        &format!(
                            "incompatible bit mask: `_ & {}` will always be lower than `{}`",
                            mask_value, cmp_value
                        ),
                    );
                } else if mask_value == 0 {
                    span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
                }
            },
            BinOpKind::BitOr => {
                if mask_value >= cmp_value {
                    span_lint(
                        cx,
                        BAD_BIT_MASK,
                        span,
                        &format!(
                            "incompatible bit mask: `_ | {}` will never be lower than `{}`",
                            mask_value, cmp_value
                        ),
                    );
                } else {
                    check_ineffective_lt(cx, span, mask_value, cmp_value, "|");
                }
            },
            BinOpKind::BitXor => check_ineffective_lt(cx, span, mask_value, cmp_value, "^"),
            _ => (),
        },
        BinOpKind::Le | BinOpKind::Gt => match bit_op {
            BinOpKind::BitAnd => {
                if mask_value <= cmp_value {
                    span_lint(
                        cx,
                        BAD_BIT_MASK,
                        span,
                        &format!(
                            "incompatible bit mask: `_ & {}` will never be higher than `{}`",
                            mask_value, cmp_value
                        ),
                    );
                } else if mask_value == 0 {
                    span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
                }
            },
            BinOpKind::BitOr => {
                if mask_value > cmp_value {
                    span_lint(
                        cx,
                        BAD_BIT_MASK,
                        span,
                        &format!(
                            "incompatible bit mask: `_ | {}` will always be higher than `{}`",
                            mask_value, cmp_value
                        ),
                    );
                } else {
                    check_ineffective_gt(cx, span, mask_value, cmp_value, "|");
                }
            },
            BinOpKind::BitXor => check_ineffective_gt(cx, span, mask_value, cmp_value, "^"),
            _ => (),
        },
        _ => (),
    }
}

fn check_ineffective_lt(cx: &LateContext<'_, '_>, span: Span, m: u128, c: u128, op: &str) {
    if c.is_power_of_two() && m < c {
        span_lint(
            cx,
            INEFFECTIVE_BIT_MASK,
            span,
            &format!(
                "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
                op, m, c
            ),
        );
    }
}

fn check_ineffective_gt(cx: &LateContext<'_, '_>, span: Span, m: u128, c: u128, op: &str) {
    if (c + 1).is_power_of_two() && m <= c {
        span_lint(
            cx,
            INEFFECTIVE_BIT_MASK,
            span,
            &format!(
                "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
                op, m, c
            ),
        );
    }
}

fn fetch_int_literal(cx: &LateContext<'_, '_>, lit: &Expr<'_>) -> Option<u128> {
    match constant(cx, cx.tables, lit)?.0 {
        Constant::Int(n) => Some(n),
        _ => None,
    }
}
<commit_msg>Auto merge of #5454 - spl:patch-1, r=phansch<commit_after>use crate::consts::{constant, Constant};
use crate::utils::sugg::Sugg;
use crate::utils::{span_lint, span_lint_and_then};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for incompatible bit masks in comparisons.
    ///
    /// The formula for detecting if an expression of the type `_ <bit_op> m
    /// <cmp_op> c` (where `<bit_op>` is one of {`&`, `|`} and `<cmp_op>` is one of
    /// {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following
    /// table:
    ///
    /// |Comparison  |Bit Op|Example     |is always|Formula               |
    /// |------------|------|------------|---------|----------------------|
    /// |`==` or `!=`| `&`  |`x & 2 == 3`|`false`  |`c & m != c`          |
    /// |`<`  or `>=`| `&`  |`x & 2 < 3` |`true`   |`m < c`               |
    /// |`>`  or `<=`| `&`  |`x & 1 > 1` |`false`  |`m <= c`              |
    /// |`==` or `!=`| `|`  |`x | 1 == 0`|`false`  |`c | m != c`          |
    /// |`<`  or `>=`| `|`  |`x | 1 < 1` |`false`  |`m >= c`              |
    /// |`<=` or `>` | `|`  |`x | 1 > 0` |`true`   |`m > c`               |
    ///
    /// **Why is this bad?** If the bits that the comparison cares about are always
    /// set to zero or one by the bit mask, the comparison is constant `true` or
    /// `false` (depending on mask, compared value, and operators).
    ///
    /// So the code is actively misleading, and the only reason someone would write
    /// this intentionally is to win an underhanded Rust contest or create a
    /// test-case for this lint.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// # let x = 1;
    /// if (x & 1 == 2) { }
    /// ```
    pub BAD_BIT_MASK,
    correctness,
    "expressions of the form `_ & mask == select` that will only ever return `true` or `false`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for bit masks in comparisons which can be removed
    /// without changing the outcome. The basic structure can be seen in the
    /// following table:
    ///
    /// |Comparison| Bit Op  |Example    |equals |
    /// |----------|---------|-----------|-------|
    /// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`|
    /// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`|
    ///
    /// **Why is this bad?** Not equally evil as [`bad_bit_mask`](#bad_bit_mask),
    /// but still a bit misleading, because the bit mask is ineffective.
    ///
    /// **Known problems:** False negatives: This lint will only match instances
    /// where we have figured out the math (which is for a power-of-two compared
    /// value). This means things like `x | 1 >= 7` (which would be better written
    /// as `x >= 6`) will not be reported (but bit masks like this are fairly
    /// uncommon).
    ///
    /// **Example:**
    /// ```rust
    /// # let x = 1;
    /// if (x | 1 > 3) {  }
    /// ```
    pub INEFFECTIVE_BIT_MASK,
    correctness,
    "expressions where a bit mask will be rendered useless by a comparison, e.g., `(x | 1) > 2`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for bit masks that can be replaced by a call
    /// to `trailing_zeros`
    ///
    /// **Why is this bad?** `x.trailing_zeros() > 4` is much clearer than `x & 15
    /// == 0`
    ///
    /// **Known problems:** llvm generates better code for `x & 15 == 0` on x86
    ///
    /// **Example:**
    /// ```rust
    /// # let x = 1;
    /// if x & 0b1111 == 0 { }
    /// ```
    pub VERBOSE_BIT_MASK,
    style,
    "expressions where a bit mask is less readable than the corresponding method call"
}

#[derive(Copy, Clone)]
pub struct BitMask {
    verbose_bit_mask_threshold: u64,
}

impl BitMask {
    #[must_use]
    pub fn new(verbose_bit_mask_threshold: u64) -> Self {
        Self {
            verbose_bit_mask_threshold,
        }
    }
}

impl_lint_pass!(BitMask => [BAD_BIT_MASK, INEFFECTIVE_BIT_MASK, VERBOSE_BIT_MASK]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BitMask {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
        if let ExprKind::Binary(cmp, left, right) = &e.kind {
            if cmp.node.is_comparison() {
                if let Some(cmp_opt) = fetch_int_literal(cx, right) {
                    check_compare(cx, left, cmp.node, cmp_opt, e.span)
                } else if let Some(cmp_val) = fetch_int_literal(cx, left) {
                    check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span)
                }
            }
        }
        if_chain! {
            if let ExprKind::Binary(op, left, right) = &e.kind;
            if BinOpKind::Eq == op.node;
            if let ExprKind::Binary(op1, left1, right1) = &left.kind;
            if BinOpKind::BitAnd == op1.node;
            if let ExprKind::Lit(lit) = &right1.kind;
            if let LitKind::Int(n, _) = lit.node;
            if let ExprKind::Lit(lit1) = &right.kind;
            if let LitKind::Int(0, _) = lit1.node;
            if n.leading_zeros() == n.count_zeros();
            if n > u128::from(self.verbose_bit_mask_threshold);
            then {
                span_lint_and_then(cx,
                                   VERBOSE_BIT_MASK,
                                   e.span,
                                   "bit mask could be simplified with a call to `trailing_zeros`",
                                   |db| {
                    let sugg = Sugg::hir(cx, left1, "...").maybe_par();
                    db.span_suggestion(
                        e.span,
                        "try",
                        format!("{}.trailing_zeros() >= {}", sugg, n.count_ones()),
                        Applicability::MaybeIncorrect,
                    );
                });
            }
        }
    }
}

#[must_use]
fn invert_cmp(cmp: BinOpKind) -> BinOpKind {
    match cmp {
        BinOpKind::Eq => BinOpKind::Eq,
        BinOpKind::Ne => BinOpKind::Ne,
        BinOpKind::Lt => BinOpKind::Gt,
        BinOpKind::Gt => BinOpKind::Lt,
        BinOpKind::Le => BinOpKind::Ge,
        BinOpKind::Ge => BinOpKind::Le,
        _ => BinOpKind::Or, // Dummy
    }
}

fn check_compare(cx: &LateContext<'_, '_>, bit_op: &Expr<'_>, cmp_op: BinOpKind, cmp_value: u128, span: Span) {
    if let ExprKind::Binary(op, left, right) = &bit_op.kind {
        if op.node != BinOpKind::BitAnd && op.node != BinOpKind::BitOr {
            return;
        }
        fetch_int_literal(cx, right)
            .or_else(|| fetch_int_literal(cx, left))
            .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span))
    }
}

#[allow(clippy::too_many_lines)]
fn check_bit_mask(
    cx: &LateContext<'_, '_>,
    bit_op: BinOpKind,
    cmp_op: BinOpKind,
    mask_value: u128,
    cmp_value: u128,
    span: Span,
) {
    match cmp_op {
        BinOpKind::Eq | BinOpKind::Ne => match bit_op {
            BinOpKind::BitAnd => {
                if mask_value & cmp_value != cmp_value {
                    if cmp_value != 0 {
                        span_lint(
                            cx,
                            BAD_BIT_MASK,
                            span,
                            &format!(
                                "incompatible bit mask: `_ & {}` can never be equal to `{}`",
                                mask_value, cmp_value
                            ),
                        );
                    }
                } else if mask_value == 0 {
                    span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
                }
            },
            BinOpKind::BitOr => {
                if mask_value | cmp_value != cmp_value {
                    span_lint(
                        cx,
                        BAD_BIT_MASK,
                        span,
                        &format!(
                            "incompatible bit mask: `_ | {}` can never be equal to `{}`",
                            mask_value, cmp_value
                        ),
                    );
                }
            },
            _ => (),
        },
        BinOpKind::Lt | BinOpKind::Ge => match bit_op {
            BinOpKind::BitAnd => {
                if mask_value < cmp_value {
                    span_lint(
                        cx,
                        BAD_BIT_MASK,
                        span,
                        &format!(
                            "incompatible bit mask: `_ & {}` will always be lower than `{}`",
                            mask_value, cmp_value
                        ),
                    );
                } else if mask_value == 0 {
                    span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
                }
            },
            BinOpKind::BitOr => {
                if mask_value >= cmp_value {
                    span_lint(
                        cx,
                        BAD_BIT_MASK,
                        span,
                        &format!(
                            "incompatible bit mask: `_ | {}` will never be lower than `{}`",
                            mask_value, cmp_value
                        ),
                    );
                } else {
                    check_ineffective_lt(cx, span, mask_value, cmp_value, "|");
                }
            },
            BinOpKind::BitXor => check_ineffective_lt(cx, span, mask_value, cmp_value, "^"),
            _ => (),
        },
        BinOpKind::Le | BinOpKind::Gt => match bit_op {
            BinOpKind::BitAnd => {
                if mask_value <= cmp_value {
                    span_lint(
                        cx,
                        BAD_BIT_MASK,
                        span,
                        &format!(
                            "incompatible bit mask: `_ & {}` will never be higher than `{}`",
                            mask_value, cmp_value
                        ),
                    );
                } else if mask_value == 0 {
                    span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
                }
            },
            BinOpKind::BitOr => {
                if mask_value > cmp_value {
                    span_lint(
                        cx,
                        BAD_BIT_MASK,
                        span,
                        &format!(
                            "incompatible bit mask: `_ | {}` will always be higher than `{}`",
                            mask_value, cmp_value
                        ),
                    );
                } else {
                    check_ineffective_gt(cx, span, mask_value, cmp_value, "|");
                }
            },
            BinOpKind::BitXor => check_ineffective_gt(cx, span, mask_value, cmp_value, "^"),
            _ => (),
        },
        _ => (),
    }
}

fn check_ineffective_lt(cx: &LateContext<'_, '_>, span: Span, m: u128, c: u128, op: &str) {
    if c.is_power_of_two() && m < c {
        span_lint(
            cx,
            INEFFECTIVE_BIT_MASK,
            span,
            &format!(
                "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
                op, m, c
            ),
        );
    }
}

fn check_ineffective_gt(cx: &LateContext<'_, '_>, span: Span, m: u128, c: u128, op: &str) {
    if (c + 1).is_power_of_two() && m <= c {
        span_lint(
            cx,
            INEFFECTIVE_BIT_MASK,
            span,
            &format!(
                "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
                op, m, c
            ),
        );
    }
}

fn fetch_int_literal(cx: &LateContext<'_, '_>, lit: &Expr<'_>) -> Option<u128> {
    match constant(cx, cx.tables, lit)?.0 {
        Constant::Int(n) => Some(n),
        _ => None,
    }
}
<|endoftext|>


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

use crate::ui::{UIWriter,
                UI};
use habitat_api_client as api_client;
use habitat_core as hcore;
use lazy_static::lazy_static;
use std::{collections::HashMap,
          env,
          ffi::OsStr,
          iter::FromIterator};

extern crate json;
#[macro_use]
extern crate log;
#[macro_use]
extern crate lazy_static;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[cfg_attr(test, macro_use)]
extern crate serde_json;
#[cfg(windows)]
extern crate winapi;

pub use self::error::{Error,
                      Result};

pub mod cli;
pub mod command;
pub mod error;
pub mod locked_env_var;
pub mod output;
pub mod package_graph;
pub mod templating;
pub mod types;
pub mod ui;
pub mod util;

lazy_static::lazy_static! {
    pub static ref PROGRAM_NAME: String = {
        match env::current_exe() {
            Ok(path) => path.file_stem().and_then(OsStr::to_str).unwrap().to_string(),
            Err(e) => {
                error!("Error getting path of current_exe: {}", e);
                String::from("hab-?")
            }
        }
    };
}

// TODO (CM): It would be nice to come up with a way to more
// programmatically manage these flags. It's a bit of a pain to define
// the flag, and then define the environment variables
// separately. Nothing statically guarantees that you've specified an
// variable for a flag.

// TODO (CM): It'd be great to have a built-in way to document them,
// too.

// TODO (CM): Part of that documentation might be *when* a flag was
// added. In general, long-lived flags are a code-smell.

// TODO (CM): It may also be useful to break out features by area of
// concern. We can have any number of bitflags-generated structs.

bitflags::bitflags! {
    /// All the feature flags that are recogized by Habitat.
    ///
    /// In general, feature flags are enabled by setting the corresponding
    /// environment variable.
    ///
    /// Your binary should call `FeatureFlag::from_env` to get a set
    /// of flags to use.
    ///
    /// To add a new feature flag, you will need to add the bit mask
    /// constant here, as well as a mapping from the feature to the
    /// environment variable to which it corresponds in the `ENV_VARS`
    /// map below.
    pub struct FeatureFlag: u32 {
        const LIST               = 0b0000_0000_0001;
        const TEST_EXIT          = 0b0000_0000_0010;
        const TEST_BOOT_FAIL     = 0b0000_0000_0100;
        const REDACT_HTTP        = 0b0000_0000_1000;
        const IGNORE_SIGNALS     = 0b0000_0001_0000;
        const OFFLINE_INSTALL    = 0b0000_0100_0000;
        const IGNORE_LOCAL       = 0b0000_1000_0000;
        const EVENT_STREAM       = 0b0001_0000_0000;
        const TRIGGER_ELECTION   = 0b0010_0000_0000;
        const CONFIGURE_SHUTDOWN = 0b0100_0000_0000;
    }
}

lazy_static! {
    static ref ENV_VARS: HashMap<FeatureFlag, &'static str> = {
        let mapping = vec![(FeatureFlag::LIST, "HAB_FEAT_LIST"),
                           (FeatureFlag::TEST_EXIT, "HAB_FEAT_TEST_EXIT"),
                           (FeatureFlag::TEST_BOOT_FAIL, "HAB_FEAT_BOOT_FAIL"),
                           (FeatureFlag::REDACT_HTTP, "HAB_FEAT_REDACT_HTTP"),
                           (FeatureFlag::IGNORE_SIGNALS, "HAB_FEAT_IGNORE_SIGNALS"),
                           (FeatureFlag::OFFLINE_INSTALL, "HAB_FEAT_OFFLINE_INSTALL"),
                           (FeatureFlag::IGNORE_LOCAL, "HAB_FEAT_IGNORE_LOCAL"),
                           (FeatureFlag::EVENT_STREAM, "HAB_FEAT_EVENT_STREAM"),
                           (FeatureFlag::TRIGGER_ELECTION, "HAB_FEAT_TRIGGER_ELECTION"),
                           (FeatureFlag::CONFIGURE_SHUTDOWN, "HAB_FEAT_CONFIGURE_SHUTDOWN")];
        HashMap::from_iter(mapping)
    };
}

impl FeatureFlag {
    /// If the environment variable for a flag is set to _anything_ but
    /// the empty string, it is activated.
    pub fn from_env(ui: &mut UI) -> Self {
        let mut flags = FeatureFlag::empty();

        for (feature, env_var) in ENV_VARS.iter() {
            if let Some(val) = env::var_os(env_var) {
                if !val.is_empty() {
                    flags.insert(*feature);
                    ui.warn(&format!("Enabling feature: {:?}", feature))
                      .unwrap();
                }
            }
        }

        // TODO (CM): Once the other TODOs above are done (especially the
        // documentation bits), it would be nice to extract this logic
        // into an actual discoverable CLI subcommand; it's a little weird
        // that you have to know how to enable a feature flag before you
        // can even find out that there *are* feature flags to enable.
        //
        // There's no reason why "list feature flags" should itself be a
        // feature-flag.
        if flags.contains(FeatureFlag::LIST) {
            ui.warn("Listing feature flags environment variables:")
              .unwrap();
            for (feature, env_var) in ENV_VARS.iter() {
                ui.warn(&format!("  * {:?}: {}={:?}",
                                 feature,
                                 env_var,
                                 env::var_os(env_var).unwrap_or_default()))
                  .unwrap();
            }
        }

        flags
    }
}

pub mod sync {
    use std::time::Duration;

    #[cfg(feature = "deadlock_detection")]
    mod deadlock_detection {
        use super::*;
        use parking_lot::deadlock;
        use std::{sync::Once,
                  thread};

        static INIT: Once = Once::new();

        pub fn init() { INIT.call_once(spawn_deadlock_detector_thread); }

        fn spawn_deadlock_detector_thread() {
            thread::spawn(move || {
                loop {
                    thread::sleep(Duration::from_secs(10));
                    let deadlocks = deadlock::check_deadlock();
                    if deadlocks.is_empty() {
                        continue;
                    }

                    println!("{} deadlocks detected", deadlocks.len());
                    for (i, threads) in deadlocks.iter().enumerate() {
                        println!("Deadlock #{}", i);
                        for t in threads {
                            println!("Thread Id {:#?}", t.thread_id());
                            println!("{:#?}", t.backtrace());
                        }
                    }

                    // Unfortunately, we can't do anything to resolve the deadlock and
                    // continue, so we have to abort the whole process
                    std::process::exit(1);
                }
            });
        }
    }

    #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
    type InnerLock<T> = parking_lot::RwLock<T>;
    #[cfg(feature = "lock_as_mutex")]
    type InnerLock<T> = parking_lot::Mutex<T>;

    #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
    pub type ReadGuard<'a, T> = parking_lot::RwLockReadGuard<'a, T>;
    #[cfg(feature = "lock_as_mutex")]
    pub type ReadGuard<'a, T> = parking_lot::MutexGuard<'a, T>;

    #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
    pub type WriteGuard<'a, T> = parking_lot::RwLockWriteGuard<'a, T>;
    #[cfg(feature = "lock_as_mutex")]
    pub type WriteGuard<'a, T> = parking_lot::MutexGuard<'a, T>;

    /// A lock which provides the interface of a read/write lock, but which has the option to
    /// internally use either a RwLock or a Mutex in order to make it easier to expose erroneous
    /// recursive locking in tests while still using an RwLock in production to avoid deadlocking
    /// as much as possible.
    #[derive(Debug)]
    pub struct Lock<T> {
        inner: InnerLock<T>,
    }

    impl<T> Lock<T> {
        pub fn new(val: T) -> Self {
            #[cfg(feature = "lock_as_mutex")]
            println!("Lock::new is using Mutex to help find recursive locking");

            #[cfg(feature = "deadlock_detection")]
            deadlock_detection::init();

            Self { inner: InnerLock::new(val), }
        }

        /// This acquires a read lock and will not deadlock if the same thread tries to acquire
        /// the lock recursively. However, it may result in writer starvation. Once we are confident
        /// that all recursive locking has been eliminated, we may replace this implementation
        /// and try_read_for (or add an additional methods) to provide fair locking for readers
        /// and writers.
        ///
        /// See https://github.com/habitat-sh/habitat/issues/6435
        #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
        pub fn read(&self) -> ReadGuard<T> { self.inner.read_recursive() }

        // maybe try_lock_for and panic if not running with deadlock detection?
        #[cfg(feature = "lock_as_mutex")]
        pub fn read(&self) -> ReadGuard<T> { self.inner.lock() }

        #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
        pub fn try_read_for(&self, timeout: Duration) -> Option<ReadGuard<T>> {
            self.inner.try_read_recursive_for(timeout)
        }

        #[cfg(feature = "lock_as_mutex")]
        pub fn try_read_for(&self, timeout: Duration) -> Option<ReadGuard<T>> {
            self.inner.try_lock_for(timeout)
        }

        #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
        pub fn write(&self) -> WriteGuard<T> { self.inner.write() }

        #[cfg(feature = "lock_as_mutex")]
        pub fn write(&self) -> ReadGuard<T> { self.inner.lock() }
    }
}
<commit_msg>Simplify Lock implementation to reduce duplication<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::ui::{UIWriter,
                UI};
use habitat_api_client as api_client;
use habitat_core as hcore;
use lazy_static::lazy_static;
use std::{collections::HashMap,
          env,
          ffi::OsStr,
          iter::FromIterator};

extern crate json;
#[macro_use]
extern crate log;
#[macro_use]
extern crate lazy_static;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[cfg_attr(test, macro_use)]
extern crate serde_json;
#[cfg(windows)]
extern crate winapi;

pub use self::error::{Error,
                      Result};

pub mod cli;
pub mod command;
pub mod error;
pub mod locked_env_var;
pub mod output;
pub mod package_graph;
pub mod templating;
pub mod types;
pub mod ui;
pub mod util;

lazy_static::lazy_static! {
    pub static ref PROGRAM_NAME: String = {
        match env::current_exe() {
            Ok(path) => path.file_stem().and_then(OsStr::to_str).unwrap().to_string(),
            Err(e) => {
                error!("Error getting path of current_exe: {}", e);
                String::from("hab-?")
            }
        }
    };
}

// TODO (CM): It would be nice to come up with a way to more
// programmatically manage these flags. It's a bit of a pain to define
// the flag, and then define the environment variables
// separately. Nothing statically guarantees that you've specified an
// variable for a flag.

// TODO (CM): It'd be great to have a built-in way to document them,
// too.

// TODO (CM): Part of that documentation might be *when* a flag was
// added. In general, long-lived flags are a code-smell.

// TODO (CM): It may also be useful to break out features by area of
// concern. We can have any number of bitflags-generated structs.

bitflags::bitflags! {
    /// All the feature flags that are recogized by Habitat.
    ///
    /// In general, feature flags are enabled by setting the corresponding
    /// environment variable.
    ///
    /// Your binary should call `FeatureFlag::from_env` to get a set
    /// of flags to use.
    ///
    /// To add a new feature flag, you will need to add the bit mask
    /// constant here, as well as a mapping from the feature to the
    /// environment variable to which it corresponds in the `ENV_VARS`
    /// map below.
    pub struct FeatureFlag: u32 {
        const LIST               = 0b0000_0000_0001;
        const TEST_EXIT          = 0b0000_0000_0010;
        const TEST_BOOT_FAIL     = 0b0000_0000_0100;
        const REDACT_HTTP        = 0b0000_0000_1000;
        const IGNORE_SIGNALS     = 0b0000_0001_0000;
        const OFFLINE_INSTALL    = 0b0000_0100_0000;
        const IGNORE_LOCAL       = 0b0000_1000_0000;
        const EVENT_STREAM       = 0b0001_0000_0000;
        const TRIGGER_ELECTION   = 0b0010_0000_0000;
        const CONFIGURE_SHUTDOWN = 0b0100_0000_0000;
    }
}

lazy_static! {
    static ref ENV_VARS: HashMap<FeatureFlag, &'static str> = {
        let mapping = vec![(FeatureFlag::LIST, "HAB_FEAT_LIST"),
                           (FeatureFlag::TEST_EXIT, "HAB_FEAT_TEST_EXIT"),
                           (FeatureFlag::TEST_BOOT_FAIL, "HAB_FEAT_BOOT_FAIL"),
                           (FeatureFlag::REDACT_HTTP, "HAB_FEAT_REDACT_HTTP"),
                           (FeatureFlag::IGNORE_SIGNALS, "HAB_FEAT_IGNORE_SIGNALS"),
                           (FeatureFlag::OFFLINE_INSTALL, "HAB_FEAT_OFFLINE_INSTALL"),
                           (FeatureFlag::IGNORE_LOCAL, "HAB_FEAT_IGNORE_LOCAL"),
                           (FeatureFlag::EVENT_STREAM, "HAB_FEAT_EVENT_STREAM"),
                           (FeatureFlag::TRIGGER_ELECTION, "HAB_FEAT_TRIGGER_ELECTION"),
                           (FeatureFlag::CONFIGURE_SHUTDOWN, "HAB_FEAT_CONFIGURE_SHUTDOWN")];
        HashMap::from_iter(mapping)
    };
}

impl FeatureFlag {
    /// If the environment variable for a flag is set to _anything_ but
    /// the empty string, it is activated.
    pub fn from_env(ui: &mut UI) -> Self {
        let mut flags = FeatureFlag::empty();

        for (feature, env_var) in ENV_VARS.iter() {
            if let Some(val) = env::var_os(env_var) {
                if !val.is_empty() {
                    flags.insert(*feature);
                    ui.warn(&format!("Enabling feature: {:?}", feature))
                      .unwrap();
                }
            }
        }

        // TODO (CM): Once the other TODOs above are done (especially the
        // documentation bits), it would be nice to extract this logic
        // into an actual discoverable CLI subcommand; it's a little weird
        // that you have to know how to enable a feature flag before you
        // can even find out that there *are* feature flags to enable.
        //
        // There's no reason why "list feature flags" should itself be a
        // feature-flag.
        if flags.contains(FeatureFlag::LIST) {
            ui.warn("Listing feature flags environment variables:")
              .unwrap();
            for (feature, env_var) in ENV_VARS.iter() {
                ui.warn(&format!("  * {:?}: {}={:?}",
                                 feature,
                                 env_var,
                                 env::var_os(env_var).unwrap_or_default()))
                  .unwrap();
            }
        }

        flags
    }
}

pub mod sync {
    use std::time::Duration;

    #[cfg(feature = "deadlock_detection")]
    mod deadlock_detection {
        use super::*;
        use parking_lot::deadlock;
        use std::{sync::Once,
                  thread};

        static INIT: Once = Once::new();

        pub fn init() { INIT.call_once(spawn_deadlock_detector_thread); }

        fn spawn_deadlock_detector_thread() {
            thread::spawn(move || {
                loop {
                    thread::sleep(Duration::from_secs(10));
                    let deadlocks = deadlock::check_deadlock();
                    if deadlocks.is_empty() {
                        continue;
                    }

                    println!("{} deadlocks detected", deadlocks.len());
                    for (i, threads) in deadlocks.iter().enumerate() {
                        println!("Deadlock #{}", i);
                        for t in threads {
                            println!("Thread Id {:#?}", t.thread_id());
                            println!("{:#?}", t.backtrace());
                        }
                    }

                    // Unfortunately, we can't do anything to resolve the deadlock and
                    // continue, so we have to abort the whole process
                    std::process::exit(1);
                }
            });
        }
    }

    #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
    type InnerLock<T> = parking_lot::RwLock<T>;
    #[cfg(feature = "lock_as_mutex")]
    type InnerLock<T> = parking_lot::Mutex<T>;

    #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
    pub type ReadGuard<'a, T> = parking_lot::RwLockReadGuard<'a, T>;
    #[cfg(feature = "lock_as_mutex")]
    pub type ReadGuard<'a, T> = parking_lot::MutexGuard<'a, T>;

    #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
    pub type WriteGuard<'a, T> = parking_lot::RwLockWriteGuard<'a, T>;
    #[cfg(feature = "lock_as_mutex")]
    pub type WriteGuard<'a, T> = parking_lot::MutexGuard<'a, T>;

    /// A lock which provides the interface of a read/write lock, but which has the option to
    /// internally use either a RwLock or a Mutex in order to make it easier to expose erroneous
    /// recursive locking in tests while still using an RwLock in production to avoid deadlocking
    /// as much as possible.
    #[derive(Debug)]
    pub struct Lock<T> {
        inner: InnerLock<T>,
    }

    impl<T> Lock<T> {
        pub fn new(val: T) -> Self {
            #[cfg(feature = "lock_as_mutex")]
            println!("Lock::new is using Mutex to help find recursive locking");

            #[cfg(feature = "deadlock_detection")]
            deadlock_detection::init();

            Self { inner: InnerLock::new(val), }
        }

        /// This acquires a read lock and will not deadlock if the same thread tries to acquire
        /// the lock recursively. However, it may result in writer starvation. Once we are confident
        /// that all recursive locking has been eliminated, we may replace this implementation
        /// and try_read_for (or add an additional methods) to provide fair locking for readers
        /// and writers.
        ///
        /// See https://github.com/habitat-sh/habitat/issues/6435
        pub fn read(&self) -> ReadGuard<T> {
            #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
            {
                self.inner.read_recursive()
            }
            #[cfg(feature = "lock_as_mutex")]
            {
                self.inner.lock()
            }
        }

        pub fn try_read_for(&self, timeout: Duration) -> Option<ReadGuard<T>> {
            #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
            {
                self.inner.try_read_recursive_for(timeout)
            }
            #[cfg(feature = "lock_as_mutex")]
            {
                self.inner.try_lock_for(timeout)
            }
        }

        pub fn write(&self) -> WriteGuard<T> {
            #[cfg(any(feature = "lock_as_rwlock", not(feature = "lock_as_mutex")))]
            {
                self.inner.write()
            }
            #[cfg(feature = "lock_as_mutex")]
            {
                self.inner.lock()
            }
        }
    }
}
<|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 for
//! 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. This field
//! is initialized by the `FooBinding::Wrap` method, called from
//! `reflect_dom_object`.
//!
//! 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);
//! }
//! ```
//!
//! 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 canvasrenderingcontext2d;
pub mod characterdata;
pub mod cssstyledeclaration;
pub mod domrect;
pub mod domrectlist;
pub mod domstringmap;
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 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 htmlserializer;
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 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 text;
pub mod treewalker;
pub mod uievent;
pub mod urlhelper;
pub mod urlsearchparams;
pub mod validitystate;
pub mod virtualmethods;
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;
<commit_msg>Document the main steps involved in adding a new DOM interface.<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 for
//! 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. This field
//! is initialized by the `FooBinding::Wrap` method, called from
//! `reflect_dom_object`.
//!
//! 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>`.
//!
//! 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 canvasrenderingcontext2d;
pub mod characterdata;
pub mod cssstyledeclaration;
pub mod domrect;
pub mod domrectlist;
pub mod domstringmap;
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 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 htmlserializer;
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 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 text;
pub mod treewalker;
pub mod uievent;
pub mod urlhelper;
pub mod urlsearchparams;
pub mod validitystate;
pub mod virtualmethods;
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;
<|endoftext|>


<commit_before>// https://leetcode.com/problems/nearest-exit-from-entrance-in-maze/
pub fn nearest_exit(maze: Vec<Vec<char>>, entrance: Vec<i32>) -> i32 {
    todo!()
}

fn main() {
    println!(
        "{}",
        nearest_exit(
            vec![
                vec!['+', '+', '.', '+'],
                vec!['.', '.', '.', '+'],
                vec!['+', '+', '+', '.']
            ],
            vec![1, 2]
        )
    ); // 1
    println!(
        "{}",
        nearest_exit(
            vec![
                vec!['+', '+', '+'],
                vec!['.', '.', '.'],
                vec!['+', '+', '+']
            ],
            vec![1, 0]
        )
    ); // 2
    println!("{}", nearest_exit(vec![vec!['.', '+']], vec![0, 0])); // -1
}
<commit_msg>Update problem 1926<commit_after>use std::collections::VecDeque;

// https://leetcode.com/problems/nearest-exit-from-entrance-in-maze/
pub fn nearest_exit(maze: Vec<Vec<char>>, entrance: Vec<i32>) -> i32 {
    let mut answer = 0;
    let mut found_exit = false;
    let max_rows = maze.len();
    let max_cols = if max_rows == 0 { 0 } else { maze[0].len() };
    let mut visited: Vec<Vec<bool>> = vec![vec![false; max_cols]; max_rows];
    let mut deque: VecDeque<Vec<i32>> = VecDeque::new();
    deque.push_back(entrance.clone());
    'outer: while !deque.is_empty() {
        let length = deque.len();
        for _ in 0..length {
            let v = deque.pop_front().unwrap();
            visited[v[0] as usize][v[1] as usize] = true;
            for (r, c) in vec![(-1, 0), (0, 1), (1, 0), (0, -1)] {
                let row = v[0] + r;
                let col = v[1] + c;
                if v[0] == entrance[0]
                    && v[1] == entrance[1]
                    && (row < 0 || row == max_rows as i32 || col < 0 || col == max_cols as i32)
                {
                    continue;
                }
                if row < 0 || row == max_rows as i32 || col < 0 || col == max_cols as i32 {
                    found_exit = true;
                    break 'outer;
                }
                if visited[row as usize][col as usize] {
                    continue;
                }
                if maze[row as usize][col as usize] == '+' {
                    continue;
                }
                deque.push_back(vec![v[0] + r, v[1] + c]);
            }
        }
        answer += 1;
    }
    if !found_exit {
        -1
    } else {
        answer
    }
}

fn main() {
    println!(
        "{}",
        nearest_exit(
            vec![
                vec!['+', '+', '.', '+'],
                vec!['.', '.', '.', '+'],
                vec!['+', '+', '+', '.']
            ],
            vec![1, 2]
        )
    ); // 1
    println!(
        "{}",
        nearest_exit(
            vec![
                vec!['+', '+', '+'],
                vec!['.', '.', '.'],
                vec!['+', '+', '+']
            ],
            vec![1, 0]
        )
    ); // 2
    println!("{}", nearest_exit(vec![vec!['.', '+']], vec![0, 0])); // -1
    println!(
        "{}",
        nearest_exit(
            vec![
                vec!['+', '.', '+', '+', '+', '+', '+'],
                vec!['+', '.', '+', '.', '.', '.', '+'],
                vec!['+', '.', '+', '.', '+', '.', '+'],
                vec!['+', '.', '.', '.', '+', '.', '+'],
                vec!['+', '+', '+', '+', '+', '+', '.']
            ],
            vec![0, 1]
        )
    ); // -1
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/minimum-number-of-buckets-required-to-collect-rainwater-from-houses/
pub fn minimum_buckets(street: String) -> i32 {
    todo!()
}

fn main() {
    println!("{}", minimum_buckets(String::from("H..H"))); // 2
    println!("{}", minimum_buckets(String::from(".H.H."))); // 1
    println!("{}", minimum_buckets(String::from(".HHH."))); // -1
    println!("{}", minimum_buckets(String::from(".H..H..H."))); // 3
    println!("{}", minimum_buckets(String::from(".H.H..H."))); // 2
    println!("{}", minimum_buckets(String::from(".H.H.H."))); // 2
}
<commit_msg>Update problem 2086<commit_after>// https://leetcode.com/problems/minimum-number-of-buckets-required-to-collect-rainwater-from-houses/
pub fn minimum_buckets(street: String) -> i32 {
    todo!()
}

fn main() {
    println!("{}", minimum_buckets(String::from("H..H"))); // 2
    println!("{}", minimum_buckets(String::from(".H.H."))); // 1
    println!("{}", minimum_buckets(String::from(".HHH."))); // -1
    println!("{}", minimum_buckets(String::from(".H..H..H."))); // 3
    println!("{}", minimum_buckets(String::from(".H.H..H."))); // 2
    println!("{}", minimum_buckets(String::from(".H.H.H."))); // 2
    println!("{}", minimum_buckets(String::from("HH..HH"))); // -1
}
<|endoftext|>


<commit_before>use std::collections::{BTreeSet, HashMap};

// https://leetcode.com/problems/design-a-number-container-system/
struct NumberContainers {
    index_to_number_map: HashMap<i32, i32>,
    number_to_indexes_map: HashMap<i32, BTreeSet<i32>>,
}

impl NumberContainers {
    fn new() -> Self {
        NumberContainers {
            index_to_number_map: HashMap::new(),
            number_to_indexes_map: HashMap::new(),
        }
    }

    fn change(&mut self, index: i32, number: i32) {
        match self.index_to_number_map.get(&index) {
            Some(old_number) => match self.number_to_indexes_map.get_mut(&old_number) {
                Some(indexes) => {
                    indexes.remove(&index);
                }
                None => (),
            },
            None => (),
        }
        self.index_to_number_map.insert(index, number);
        match self.number_to_indexes_map.get_mut(&number) {
            Some(indexes) => {
                indexes.insert(index);
            }
            None => {
                let mut set: BTreeSet<i32> = BTreeSet::new();
                set.insert(index);
                self.number_to_indexes_map.insert(number, set);
            }
        }
    }

    fn find(&self, number: i32) -> i32 {
        match self.number_to_indexes_map.get(&number) {
            Some(set) => *set.iter().next().unwrap_or(&-1),
            None => -1,
        }
    }
}

fn main() {
    let mut nc = NumberContainers::new();
    println!("{}", nc.find(10)); // -1
    nc.change(2, 10);
    nc.change(1, 10);
    nc.change(3, 10);
    nc.change(5, 10);
    println!("{}", nc.find(10)); // 1
    nc.change(1, 20);
    println!("{}", nc.find(10)); // 2
    nc.change(2, 20);
    println!("{}", nc.find(10)); // 3
    println!("{}", nc.find(20)); // 1
}
<commit_msg>Update problem 2349<commit_after>use std::collections::{BTreeSet, HashMap};

// https://leetcode.com/problems/design-a-number-container-system/
struct NumberContainers {
    index_to_number_map: HashMap<i32, i32>,
    number_to_indexes_map: HashMap<i32, BTreeSet<i32>>,
}

impl NumberContainers {
    fn new() -> Self {
        NumberContainers {
            index_to_number_map: HashMap::new(),
            number_to_indexes_map: HashMap::new(),
        }
    }

    fn change(&mut self, index: i32, number: i32) {
        match self.index_to_number_map.get(&index) {
            Some(old_number) => match self.number_to_indexes_map.get_mut(&old_number) {
                Some(indexes) => {
                    indexes.remove(&index);
                }
                None => (),
            },
            None => (),
        }
        self.index_to_number_map.insert(index, number);
        match self.number_to_indexes_map.get_mut(&number) {
            Some(indexes) => {
                indexes.insert(index);
            }
            None => {
                let mut set: BTreeSet<i32> = BTreeSet::new();
                set.insert(index);
                self.number_to_indexes_map.insert(number, set);
            }
        }
    }

    fn find(&self, number: i32) -> i32 {
        self.number_to_indexes_map
            .get(&number)
            .map_or(-1, |set| *set.iter().next().unwrap_or(&-1))
    }
}

fn main() {
    let mut nc = NumberContainers::new();
    println!("{}", nc.find(10)); // -1
    nc.change(2, 10);
    nc.change(1, 10);
    nc.change(3, 10);
    nc.change(5, 10);
    println!("{}", nc.find(10)); // 1
    nc.change(1, 20);
    println!("{}", nc.find(10)); // 2
    nc.change(2, 20);
    println!("{}", nc.find(10)); // 3
    println!("{}", nc.find(20)); // 1
}
<|endoftext|>


<commit_before>
extern crate arrayvec;
#[macro_use] extern crate bencher;

use arrayvec::ArrayVec;

use bencher::Bencher;
use bencher::black_box;

fn extend_with_constant(b: &mut Bencher) {
    let mut v = ArrayVec::<[u8; 512]>::new();
    let cap = v.capacity();
    b.iter(|| {
        v.clear();
        v.extend((0..cap).map(|_| 1));
        v[0]
    });
    b.bytes = v.capacity() as u64;
}

fn extend_with_range(b: &mut Bencher) {
    let mut v = ArrayVec::<[u8; 512]>::new();
    let cap = v.capacity();
    b.iter(|| {
        v.clear();
        v.extend((0..cap).map(|x| x as _));
        v[0]
    });
    b.bytes = v.capacity() as u64;
}

fn extend_with_slice(b: &mut Bencher) {
    let mut v = ArrayVec::<[u8; 512]>::new();
    let data = [1; 512];
    b.iter(|| {
        v.clear();
        v.extend(black_box(data.iter()).cloned());
        v[0]
    });
    b.bytes = v.capacity() as u64;
}

fn extend_with_slice_fn(b: &mut Bencher) {
    let mut v = ArrayVec::<[u8; 512]>::new();
    let data = [1; 512];
    b.iter(|| {
        v.clear();
        black_box(v.try_extend_from_slice(&data));
        v[0]
    });
    b.bytes = v.capacity() as u64;
}

benchmark_group!(benches, extend_with_constant, extend_with_range, extend_with_slice, extend_with_slice_fn);
benchmark_main!(benches);
<commit_msg>FIX: Rename the extend_from_slice bench<commit_after>
extern crate arrayvec;
#[macro_use] extern crate bencher;

use arrayvec::ArrayVec;

use bencher::Bencher;
use bencher::black_box;

fn extend_with_constant(b: &mut Bencher) {
    let mut v = ArrayVec::<[u8; 512]>::new();
    let cap = v.capacity();
    b.iter(|| {
        v.clear();
        v.extend((0..cap).map(|_| 1));
        v[0]
    });
    b.bytes = v.capacity() as u64;
}

fn extend_with_range(b: &mut Bencher) {
    let mut v = ArrayVec::<[u8; 512]>::new();
    let cap = v.capacity();
    b.iter(|| {
        v.clear();
        v.extend((0..cap).map(|x| x as _));
        v[0]
    });
    b.bytes = v.capacity() as u64;
}

fn extend_with_slice(b: &mut Bencher) {
    let mut v = ArrayVec::<[u8; 512]>::new();
    let data = [1; 512];
    b.iter(|| {
        v.clear();
        v.extend(black_box(data.iter()).cloned());
        v[0]
    });
    b.bytes = v.capacity() as u64;
}

fn extend_from_slice(b: &mut Bencher) {
    let mut v = ArrayVec::<[u8; 512]>::new();
    let data = [1; 512];
    b.iter(|| {
        v.clear();
        v.try_extend_from_slice(&data).ok();
        v[511]
    });
    b.bytes = v.capacity() as u64;
}

benchmark_group!(benches, extend_with_constant, extend_with_range, extend_with_slice, extend_from_slice);
benchmark_main!(benches);
<|endoftext|>


<commit_before>extern crate libc;

use std::cell::RefCell;
use std::collections::HashMap;
use indy::api::payments::CreatePaymentAddressCB;
use indy::api::ErrorCode;
use std::os::raw::c_char;
use indy::api::payments::AddRequestFeesCB;
use indy::api::payments::ParseResponseWithFeesCB;
use indy::api::payments::BuildGetUTXORequestCB;

pub struct PaymentCallbacks {
    str_params: RefCell<HashMap<String, *const char>>,
    int_params: RefCell<HashMap<String, i32>>,
    cb_params: RefCell<HashMap<String, Option<extern fn(command_handle: i32,
                                                        err: ErrorCode,
                                                        c_str: *const c_char) -> ErrorCode>>>
}

impl PaymentCallbacks {
    pub fn new() -> PaymentCallbacks {
        PaymentCallbacks {
            str_params: RefCell::new(HashMap::new()),
            int_params: RefCell::new(HashMap::new()),
            cb_params: RefCell::new(HashMap::new())
        }
    }

    pub fn get_create_payment_address_cb(&self) -> (i32, CreatePaymentAddressCB) {
        let cb_handle = ::utils::sequence::SequenceUtils::get_next_id();
        let me = self;

        extern "C" fn _callback(command_handle: i32,
                                config: *const c_char,
                                cb: Option<extern fn(command_handle_: i32,
                                                     err: ErrorCode,
                                                     payment_address: *const c_char) -> ErrorCode>) -> ErrorCode {
            me.put(format!("{}_command_handle", cb_handle), command_handle);
            me.put(format!("{}_config", cb_handle), config);
            me.put(format!("{}_cb", cb_handle), cb);
            ErrorCode::Success
        }

        (cb_handle, _callback)
    }

    pub fn get_add_request_fees_cb(&self) -> (i32, AddRequestFeesCB) {
        let cb_handle = ::utils::sequence::SequenceUtils::get_next_id();
        let me = self;

        extern "C" fn _callback(command_handle: i32,
                                req_json: *const c_char,
                                inputs_json: *const c_char,
                                outputs_json: *const c_char,
                                cb: Option<extern fn(command_handle_: i32,
                                                     err: ErrorCode,
                                                     req_with_fees_json: *const c_char) -> ErrorCode>) -> ErrorCode {
            me.put(format!("{}_command_handle", cb_handle), command_handle);
            me.put(format!("{}_req_json", cb_handle), req_json);
            me.put(format!("{}_inputs_json", cb_handle), inputs_json);
            me.put(format!("{}_outputs_json", cb_handle), outputs_json);
            me.put(format!("{}_cb", cb_handle), cb);
            ErrorCode::Success
        }

        (cb_handle, _callback)
    }

    pub fn get_parse_response_with_fees_cb(&self) -> (i32, ParseResponseWithFeesCB) {
        let cb_handle = ::utils::sequence::SequenceUtils::get_next_id();
        let me = self;

        extern "C" fn _callback(command_handle: i32,
                                resp_json: *const c_char,
                                cb: Option<extern fn(command_handle_: i32,
                                                     err: ErrorCode,
                                                     utxo_json: *const c_char) -> ErrorCode>) -> ErrorCode {
            me.put(format!("{}_command_handle", cb_handle), command_handle);
            me.put(format!("{}_resp_json", cb_handle), resp_json);
            me.put(format!("{}_cb", cb_handle), cb);
            ErrorCode::Success
        }

        (cb_handle, _callback)
    }

    pub fn get_build_get_utxo_request_cb(&self) -> (i32, BuildGetUTXORequestCB) {
        let cb_handle = ::utils::sequence::SequenceUtils::get_next_id();
        let me = self;

        extern "C" fn _callback(command_handle: i32,
                                payment_address: *const c_char,
                                cb: Option<extern fn(command_handle_: i32,
                                                     err: ErrorCode,
                                                     get_utxo_txn_json: *const c_char) -> ErrorCode>) -> ErrorCode {
            me.put(format!("{}_command_handle", cb_handle), command_handle);
            me.put(format!("{}_payment_address", cb_handle), payment_address);
            me.put(format!("{}_cb", cb_handle), cb);
            ErrorCode::Success
        }

        (cb_handle, _callback)
    }

}

impl Capture for PaymentCallbacks {
    type Val = i32;
    type Key = String;
    fn put(self, key: String, value: i32) {
        self.int_params.borrow().insert(key, value);
    }
    fn get(self, key: String) -> Option<i32> {
        self.int_params.borrow().remove(key.as_str())
    }
}

impl Capture for PaymentCallbacks {
    type Val = *const char;
    type Key = String;

    fn put(self, key: String, value: *const char) {
        self.str_params.borrow().insert(key, value);
    }
    fn get(self, key: String) -> Option<*const char>  {
        self.str_params.borrow().remove(key.as_str())
    }
}

impl Capture for PaymentCallbacks {
    type Val = Option<extern fn(command_handle: i32,
                                  err: ErrorCode,
                                  c_str: *const c_char) -> ErrorCode>;

    type Key = String;

    fn put(self, key: String, value: Option<extern fn(command_handle: i32,
                                                      err: ErrorCode,
                                                      c_str: *const c_char) -> ErrorCode>) {
        self.cb_params.borrow().insert(key, value);
    }
    fn get(self, key: String) -> Option<Option<extern fn(command_handle: i32,
                                             err: ErrorCode,
                                             c_str: *const c_char) -> ErrorCode>> {
        self.cb_params.borrow().remove(key.as_str())
    }

}

trait Capture {
    type Val;
    type Key;
    fn put(self, key: Key, value: Val);
    fn get(self, key: Key) -> Val;
}<commit_msg>Add null callback creators for Payments API<commit_after>extern crate libc;

use std::cell::RefCell;
use std::collections::HashMap;
use indy::api::ErrorCode;
use std::os::raw::c_char;
use indy::api::payments::*;
use std::sync::mpsc::Receiver;
use std::sync::mpsc::channel;
use std::sync::atomic::Ordering;

lazy_static! {
    static ref COMMAND_HANDLE_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
}

pub struct PaymentCallbacks {}

type CommonResponseCallback = extern fn(command_handle_: i32,
                                        err: ErrorCode,
                                        res1: *const c_char) -> ErrorCode;

impl PaymentCallbacks {

    pub fn get_create_payment_address_cb() -> (Receiver<(i32, *const c_char, Option<CommonResponseCallback>)>, i32, CreatePaymentAddressCB) {
        PaymentCallbacks::get_str_to_str_cb()
    }

    pub fn parse_response_with_fees_cb() -> (Receiver<(i32, *const c_char, Option<CommonResponseCallback>)>, i32, ParseResponseWithFeesCB) {
        PaymentCallbacks::get_str_to_str_cb()
    }

    pub fn build_get_utxo_request_cb() -> (Receiver<(i32, *const c_char, Option<CommonResponseCallback>)>, i32, BuildGetUTXORequestCB) {
        PaymentCallbacks::get_str_to_str_cb()
    }

    pub fn parse_get_utxo_response_cb() -> (Receiver<(i32, *const c_char, Option<CommonResponseCallback>)>, i32, ParseGetUTXOResponseCB) {
        PaymentCallbacks::get_str_to_str_cb()
    }

    pub fn parse_payment_response_cb() -> (Receiver<(i32, *const c_char, Option<CommonResponseCallback>)>, i32, ParsePaymentResponseCB) {
        PaymentCallbacks::get_str_to_str_cb()
    }

    pub fn build_mint_req() -> (Receiver<(i32, *const c_char, Option<CommonResponseCallback>)>, i32, BuildMintReqCB) {
        PaymentCallbacks::get_str_to_str_cb()
    }

    pub fn build_set_txn_fees_req() -> (Receiver<(i32, *const c_char, Option<CommonResponseCallback>)>, i32, BuildSetTxnFeesReqCB) {
        PaymentCallbacks::get_str_to_str_cb()
    }

    pub fn parse_get_txn_fees_response() -> (Receiver<(i32, *const c_char, Option<CommonResponseCallback>)>, i32, ParseGetTxnFeesResponseCB) {
        PaymentCallbacks::get_str_to_str_cb()
    }

    pub fn add_request_fees() -> (Receiver<(i32, *const c_char, *const c_char, *const c_char, Option<CommonResponseCallback>)>, i32, AddRequestFeesCB) {
        PaymentCallbacks::get_str_str_str_to_str_cb()
    }

    pub fn build_payment_req() -> (Receiver<(i32, *const c_char, *const c_char, Option<CommonResponseCallback>)>, i32, BuildPaymentReqCB) {
        PaymentCallbacks::get_str_str_to_str_cb()
    }

    pub fn build_get_txn_fees_req() -> (Receiver<(i32, Option<CommonResponseCallback>)>, i32, BuildGetTxnFeesReqCB) {
        PaymentCallbacks::get_to_str_cb()
    }

    ///
    /// Callback used by:
    /// create_payment_address
    /// parse_response_with_fees
    /// build_get_utxo_request
    /// parse_get_utxo_response
    /// parse_payment_response
    /// build_mint_req
    /// build_set_txn_fees_req
    /// parse_get_txn_fees_response
    ///
    fn get_str_to_str_cb() -> (Receiver<(i32, *const c_char, F)>, i32, E)
        where
            F: Option<CommonResponseCallback>,
            E: Option(extern fn(command_handle: i32,
                            arg1: *const c_char,
                            cb: F) -> ErrorCode) {
        let (sender, receiver) = channel();

        lazy_static! {
            static ref CALLBACKS: Mutex<HashMap<i32, Box<FnMut(i32, *const c_char, F) + Send>>> = Default::default();
        }

        let closure = Box::new(move |cmd_handle, arg1, cb| {
            sender.send((cmd_handle, arg1, cb)).unwrap();
        });

        extern "C" fn _callback(command_handle: i32,
                                arg1: *const c_char,
                                cb: F) -> ErrorCode {
            let mut callbacks = CALLBACKS.lock().unwrap();
            let mut _cb = callbacks.remove(&command_handle).unwrap();
            _cb(command_handle, arg1, cb);
            ErrorCode::Success
        }

        let mut callbacks = CALLBACKS.lock().unwrap();
        let command_handle = (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32;
        callbacks.insert(command_handle, closure);

        (receiver, cb_handle, Some(_callback))
    }

    ///
    /// Callback used for add_request_fees
    ///
    fn get_str_str_str_to_str_cb() -> (Receiver<(i32, *const c_char, *const c_char, *const c_char, F)>, i32, E)
        where
            F: Option<CommonResponseCallback>,
            E: Option<extern fn(command_handle: i32,
                                arg1: *const c_char,
                                arg2: *const c_char,
                                arg3: *const c_char,
                                cb:E) -> ErrorCode> {
        let (sender, receiver) = channel();

        lazy_static! {
            static ref CALLBACKS: Mutex<HashMap<i32, Box<FnMut(i32, *const c_char, *const c_char, *const c_char, F) + Send>>> = Default::default();
        }

        let closure =
            Box::new(move |cmd_handle, arg1, arg2, arg3, cb| {
                sender.send((cmd_handle, arg1, arg2, arg3, cb)).unwrap();
            });

        extern "C" fn _callback(command_handle: i32,
                                arg1: *const c_char,
                                arg2: *const c_char,
                                arg3: *const c_char,
                                cb: F) -> ErrorCode {
            let mut callbacks = CALLBACKS.lock().unwrap();
            let mut _cb = callbacks.remove(&command_handle).unwrap();
            _cb(command_handle, arg1, arg2, arg3, cb);
            ErrorCode::Success
        }

        let mut callbacks = CALLBACKS.lock().unwrap();
        let command_handle = (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32;
        callbacks.insert(command_handle, closure);

        (receiver, cb_handle, Some(_callback))
    }

    ///
    /// Callback used by build_payment_req
    ///
    fn get_str_str_to_str_cb() -> (Receiver<(i32, *const c_char, *const c_char, F)>, i32, E)
        where
            F: Option<CommonResponseCallback>,
            E: Option<extern fn(command_handle: i32,
                                arg1: *const c_char,
                                arg2: *const c_char,
                                cb: F) -> ErrorCode> {
        let (sender, receiver) = channel();

        lazy_static! {
            static ref CALLBACKS: Mutex<HashMap<i32, Box<FnMut(i32, *const c_char, *const c_char, F) + Send>>> = Default::default();
        }

        let closure =
            Box::new(move |cmd_handle, arg1, arg2, cb| {
                sender.send((cmd_handle, arg1, arg2, cb)).unwrap();
            });

        extern "C" fn _callback(command_handle: i32,
                                arg1: *const c_char,
                                arg2: *const c_char,
                                cb: F) -> ErrorCode {
            let mut callbacks = CALLBACKS.lock().unwrap();
            let mut _cb = callbacks.remove(&command_handle).unwrap();
            _cb(command_handle, arg1, arg2, cb);
            ErrorCode::Success
        }

        let mut callbacks = CALLBACKS.lock().unwrap();
        let command_handle = (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32;
        callbacks.insert(command_handle, closure);

        (receiver, cb_handle, Some(_callback))
    }

    ///
    /// Callback used by build_get_txn_fees_req
    ///
    fn get_to_str_cb() -> (Receiver<(i32, F)>, i32, E)
        where
            F: Option<CommonResponseCallback>,
            E: Option<extern fn(command_handle: i32,
                                cb: F) -> ErrorCode> {
        let (sender, receiver) = channel();

        lazy_static! {
            static ref CALLBACKS: Mutex<HashMap<i32, Box<FnMut(i32, F) + Send>>> = Default::default();
        }

        let closure =
            Box::new(move |cmd_handle, cb| {
                sender.send((cmd_handle, cb)).unwrap();
            });

        extern "C" fn _callback(command_handle: i32,
                                cb: F) -> ErrorCode {
            let mut callbacks = CALLBACKS.lock().unwrap();
            let mut _cb = callbacks.remove(&command_handle).unwrap();
            _cb(command_handle, cb);
            ErrorCode::Success
        }

        let mut callbacks = CALLBACKS.lock().unwrap();
        let command_handle = (COMMAND_HANDLE_COUNTER.fetch_add(1, Ordering::SeqCst) + 1) as i32;
        callbacks.insert(command_handle, closure);

        (receiver, cb_handle, Some(_callback))
    }
}<|endoftext|>