<commit_before>use rustc::lint::*;
use syntax::codemap::Span;
use syntax::parse::token::InternedString;
use syntax::ast::*;
use syntax::attr;
use syntax::visit::{Visitor, walk_block, walk_pat, walk_expr};
use utils::{span_lint_and_then, in_macro, span_lint};

/// **What it does:** This lint warns about names that are very similar and thus confusing
///
/// **Why is this bad?** It's hard to distinguish between names that differ only by a single character
///
/// **Known problems:** None?
///
/// **Example:** `checked_exp` and `checked_expr`
declare_lint! {
    pub SIMILAR_NAMES,
    Allow,
    "similarly named items and bindings"
}

/// **What it does:** This lint warns about having too many variables whose name consists of a single character
///
/// **Why is this bad?** It's hard to memorize what a variable means without a descriptive name.
///
/// **Known problems:** None?
///
/// **Example:** let (a, b, c, d, e, f, g) = (...);
declare_lint! {
    pub MANY_SINGLE_CHAR_NAMES,
    Warn,
    "too many single character bindings"
}

pub struct NonExpressiveNames {
    pub max_single_char_names: u64,
}

impl LintPass for NonExpressiveNames {
    fn get_lints(&self) -> LintArray {
        lint_array!(SIMILAR_NAMES, MANY_SINGLE_CHAR_NAMES)
    }
}

struct ExistingName {
    interned: InternedString,
    span: Span,
    len: usize,
    whitelist: &'static [&'static str],
}

struct SimilarNamesLocalVisitor<'a, 'b: 'a> {
    names: Vec<ExistingName>,
    cx: &'a EarlyContext<'b>,
    lint: &'a NonExpressiveNames,
    single_char_names: Vec<char>,
}

// this list contains lists of names that are allowed to be similar
// the assumption is that no name is ever contained in multiple lists.
#[cfg_attr(rustfmt, rustfmt_skip)]
const WHITELIST: &'static [&'static [&'static str]] = &[
    &["parsed", "parser"],
    &["lhs", "rhs"],
    &["tx", "rx"],
    &["set", "get"],
];

struct SimilarNamesNameVisitor<'a, 'b: 'a, 'c: 'b>(&'a mut SimilarNamesLocalVisitor<'b, 'c>);

impl<'a, 'b, 'c> Visitor for SimilarNamesNameVisitor<'a, 'b, 'c> {
    fn visit_pat(&mut self, pat: &Pat) {
        match pat.node {
            PatKind::Ident(_, id, _) => self.check_name(id.span, id.node.name),
            PatKind::Struct(_, ref fields, _) => {
                for field in fields {
                    if !field.node.is_shorthand {
                        self.visit_pat(&field.node.pat);
                    }
                }
            }
            _ => walk_pat(self, pat),
        }
    }
}

fn get_whitelist(interned_name: &str) -> Option<&'static [&'static str]> {
    for &allow in WHITELIST {
        if whitelisted(interned_name, allow) {
            return Some(allow);
        }
    }
    None
}

fn whitelisted(interned_name: &str, list: &[&str]) -> bool {
    if list.iter().any(|&name| interned_name == name) {
        return true;
    }
    for name in list {
        // name_*
        if interned_name.chars().zip(name.chars()).all(|(l, r)| l == r) {
            return true;
        }
        // *_name
        if interned_name.chars().rev().zip(name.chars().rev()).all(|(l, r)| l == r) {
            return true;
        }
    }
    false
}

impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> {
    fn check_short_name(&mut self, c: char, span: Span) {
        // make sure we ignore shadowing
        if self.0.single_char_names.contains(&c) {
            return;
        }
        self.0.single_char_names.push(c);
        if self.0.single_char_names.len() as u64 >= self.0.lint.max_single_char_names {
            span_lint(self.0.cx,
                      MANY_SINGLE_CHAR_NAMES,
                      span,
                      &format!("{}th binding whose name is just one char", self.0.single_char_names.len()));
        }
    }
    fn check_name(&mut self, span: Span, name: Name) {
        if in_macro(self.0.cx, span) {
            return;
        }
        let interned_name = name.as_str();
        if interned_name.chars().any(char::is_uppercase) {
            return;
        }
        let count = interned_name.chars().count();
        if count < 3 {
            if count == 1 {
                let c = interned_name.chars().next().expect("already checked");
                self.check_short_name(c, span);
            }
            return;
        }
        for existing_name in &self.0.names {
            if whitelisted(&interned_name, existing_name.whitelist) {
                continue;
            }
            let mut split_at = None;
            if existing_name.len > count {
                if existing_name.len - count != 1 || levenstein_not_1(&interned_name, &existing_name.interned) {
                    continue;
                }
            } else if existing_name.len < count {
                if count - existing_name.len != 1 || levenstein_not_1(&existing_name.interned, &interned_name) {
                    continue;
                }
            } else {
                let mut interned_chars = interned_name.chars();
                let mut existing_chars = existing_name.interned.chars();
                let first_i = interned_chars.next().expect("we know we have at least one char");
                let first_e = existing_chars.next().expect("we know we have at least one char");
                let eq_or_numeric = |a: char, b: char| a == b || a.is_numeric() && b.is_numeric();

                if eq_or_numeric(first_i, first_e) {
                    let last_i = interned_chars.next_back().expect("we know we have at least two chars");
                    let last_e = existing_chars.next_back().expect("we know we have at least two chars");
                    if eq_or_numeric(last_i, last_e) {
                        if interned_chars.zip(existing_chars).filter(|&(i, e)| !eq_or_numeric(i, e)).count() != 1 {
                            continue;
                        }
                    } else {
                        let second_last_i = interned_chars.next_back().expect("we know we have at least three chars");
                        let second_last_e = existing_chars.next_back().expect("we know we have at least three chars");
                        if !eq_or_numeric(second_last_i, second_last_e) || second_last_i == '_' ||
                           !interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) {
                            // allowed similarity foo_x, foo_y
                            // or too many chars differ (foo_x, boo_y) or (foox, booy)
                            continue;
                        }
                        split_at = interned_name.char_indices().rev().next().map(|(i, _)| i);
                    }
                } else {
                    let second_i = interned_chars.next().expect("we know we have at least two chars");
                    let second_e = existing_chars.next().expect("we know we have at least two chars");
                    if !eq_or_numeric(second_i, second_e) || second_i == '_' ||
                       !interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) {
                        // allowed similarity x_foo, y_foo
                        // or too many chars differ (x_foo, y_boo) or (xfoo, yboo)
                        continue;
                    }
                    split_at = interned_name.chars().next().map(|c| c.len_utf8());
                }
            }
            span_lint_and_then(self.0.cx,
                               SIMILAR_NAMES,
                               span,
                               "binding's name is too similar to existing binding",
                               |diag| {
                diag.span_note(existing_name.span, "existing binding defined here");
                if let Some(split) = split_at {
                    diag.span_help(span,
                                   &format!("separate the discriminating character by an \
                                                                underscore like: `{}_{}`",
                                                               &interned_name[..split],
                                                               &interned_name[split..]));
                }
            });
            return;
        }
        self.0.names.push(ExistingName {
            whitelist: get_whitelist(&interned_name).unwrap_or(&[]),
            interned: interned_name,
            span: span,
            len: count,
        });
    }
}

impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> {
    /// ensure scoping rules work
    fn apply<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) {
        let n = self.names.len();
        let single_char_count = self.single_char_names.len();
        f(self);
        self.names.truncate(n);
        self.single_char_names.truncate(single_char_count);
    }
}

impl<'a, 'b> Visitor for SimilarNamesLocalVisitor<'a, 'b> {
    fn visit_local(&mut self, local: &Local) {
        if let Some(ref init) = local.init {
            self.apply(|this| walk_expr(this, &**init));
        }
        // add the pattern after the expression because the bindings aren't available yet in the init expression
        SimilarNamesNameVisitor(self).visit_pat(&*local.pat);
    }
    fn visit_block(&mut self, blk: &Block) {
        self.apply(|this| walk_block(this, blk));
    }
    fn visit_arm(&mut self, arm: &Arm) {
        self.apply(|this| {
            // just go through the first pattern, as either all patterns bind the same bindings or rustc would have errored much earlier
            SimilarNamesNameVisitor(this).visit_pat(&arm.pats[0]);
            this.apply(|this| walk_expr(this, &arm.body));
        });
    }
    fn visit_item(&mut self, _: &Item) {
        // do not recurse into inner items
    }
}

impl EarlyLintPass for NonExpressiveNames {
    fn check_item(&mut self, cx: &EarlyContext, item: &Item) {
        if let ItemKind::Fn(ref decl, _, _, _, _, ref blk) = item.node {
            if !attr::contains_name(&item.attrs, "test") {
                let mut visitor = SimilarNamesLocalVisitor {
                    names: Vec::new(),
                    cx: cx,
                    lint: self,
                    single_char_names: Vec::new(),
                };
                // initialize with function arguments
                for arg in &decl.inputs {
                    SimilarNamesNameVisitor(&mut visitor).visit_pat(&arg.pat);
                }
                // walk all other bindings
                walk_block(&mut visitor, blk);
            }
        }
    }
}

/// Precondition: `a_name.chars().count() < b_name.chars().count()`.
fn levenstein_not_1(a_name: &str, b_name: &str) -> bool {
    debug_assert!(a_name.chars().count() < b_name.chars().count());
    let mut a_chars = a_name.chars();
    let mut b_chars = b_name.chars();
    while let (Some(a), Some(b)) = (a_chars.next(), b_chars.next()) {
        if a == b {
            continue;
        }
        if let Some(b2) = b_chars.next() {
            // check if there's just one character inserted
            return a != b2 || a_chars.ne(b_chars);
        } else {
            // tuple
            // ntuple
            return true;
        }
    }
    // for item in items
    true
}
<commit_msg>Fix `MANY_SINGLE_CHAR_NAMES`'s docs<commit_after>use rustc::lint::*;
use syntax::codemap::Span;
use syntax::parse::token::InternedString;
use syntax::ast::*;
use syntax::attr;
use syntax::visit::{Visitor, walk_block, walk_pat, walk_expr};
use utils::{span_lint_and_then, in_macro, span_lint};

/// **What it does:** This lint warns about names that are very similar and thus confusing
///
/// **Why is this bad?** It's hard to distinguish between names that differ only by a single character
///
/// **Known problems:** None?
///
/// **Example:** `checked_exp` and `checked_expr`
declare_lint! {
    pub SIMILAR_NAMES,
    Allow,
    "similarly named items and bindings"
}

/// **What it does:** This lint warns about having too many variables whose name consists of a single character
///
/// **Why is this bad?** It's hard to memorize what a variable means without a descriptive name.
///
/// **Known problems:** None?
///
/// **Example:**
///
/// ```rust
/// let (a, b, c, d, e, f, g) = (...);
/// ```
declare_lint! {
    pub MANY_SINGLE_CHAR_NAMES,
    Warn,
    "too many single character bindings"
}

pub struct NonExpressiveNames {
    pub max_single_char_names: u64,
}

impl LintPass for NonExpressiveNames {
    fn get_lints(&self) -> LintArray {
        lint_array!(SIMILAR_NAMES, MANY_SINGLE_CHAR_NAMES)
    }
}

struct ExistingName {
    interned: InternedString,
    span: Span,
    len: usize,
    whitelist: &'static [&'static str],
}

struct SimilarNamesLocalVisitor<'a, 'b: 'a> {
    names: Vec<ExistingName>,
    cx: &'a EarlyContext<'b>,
    lint: &'a NonExpressiveNames,
    single_char_names: Vec<char>,
}

// this list contains lists of names that are allowed to be similar
// the assumption is that no name is ever contained in multiple lists.
#[cfg_attr(rustfmt, rustfmt_skip)]
const WHITELIST: &'static [&'static [&'static str]] = &[
    &["parsed", "parser"],
    &["lhs", "rhs"],
    &["tx", "rx"],
    &["set", "get"],
];

struct SimilarNamesNameVisitor<'a, 'b: 'a, 'c: 'b>(&'a mut SimilarNamesLocalVisitor<'b, 'c>);

impl<'a, 'b, 'c> Visitor for SimilarNamesNameVisitor<'a, 'b, 'c> {
    fn visit_pat(&mut self, pat: &Pat) {
        match pat.node {
            PatKind::Ident(_, id, _) => self.check_name(id.span, id.node.name),
            PatKind::Struct(_, ref fields, _) => {
                for field in fields {
                    if !field.node.is_shorthand {
                        self.visit_pat(&field.node.pat);
                    }
                }
            }
            _ => walk_pat(self, pat),
        }
    }
}

fn get_whitelist(interned_name: &str) -> Option<&'static [&'static str]> {
    for &allow in WHITELIST {
        if whitelisted(interned_name, allow) {
            return Some(allow);
        }
    }
    None
}

fn whitelisted(interned_name: &str, list: &[&str]) -> bool {
    if list.iter().any(|&name| interned_name == name) {
        return true;
    }
    for name in list {
        // name_*
        if interned_name.chars().zip(name.chars()).all(|(l, r)| l == r) {
            return true;
        }
        // *_name
        if interned_name.chars().rev().zip(name.chars().rev()).all(|(l, r)| l == r) {
            return true;
        }
    }
    false
}

impl<'a, 'b, 'c> SimilarNamesNameVisitor<'a, 'b, 'c> {
    fn check_short_name(&mut self, c: char, span: Span) {
        // make sure we ignore shadowing
        if self.0.single_char_names.contains(&c) {
            return;
        }
        self.0.single_char_names.push(c);
        if self.0.single_char_names.len() as u64 >= self.0.lint.max_single_char_names {
            span_lint(self.0.cx,
                      MANY_SINGLE_CHAR_NAMES,
                      span,
                      &format!("{}th binding whose name is just one char", self.0.single_char_names.len()));
        }
    }
    fn check_name(&mut self, span: Span, name: Name) {
        if in_macro(self.0.cx, span) {
            return;
        }
        let interned_name = name.as_str();
        if interned_name.chars().any(char::is_uppercase) {
            return;
        }
        let count = interned_name.chars().count();
        if count < 3 {
            if count == 1 {
                let c = interned_name.chars().next().expect("already checked");
                self.check_short_name(c, span);
            }
            return;
        }
        for existing_name in &self.0.names {
            if whitelisted(&interned_name, existing_name.whitelist) {
                continue;
            }
            let mut split_at = None;
            if existing_name.len > count {
                if existing_name.len - count != 1 || levenstein_not_1(&interned_name, &existing_name.interned) {
                    continue;
                }
            } else if existing_name.len < count {
                if count - existing_name.len != 1 || levenstein_not_1(&existing_name.interned, &interned_name) {
                    continue;
                }
            } else {
                let mut interned_chars = interned_name.chars();
                let mut existing_chars = existing_name.interned.chars();
                let first_i = interned_chars.next().expect("we know we have at least one char");
                let first_e = existing_chars.next().expect("we know we have at least one char");
                let eq_or_numeric = |a: char, b: char| a == b || a.is_numeric() && b.is_numeric();

                if eq_or_numeric(first_i, first_e) {
                    let last_i = interned_chars.next_back().expect("we know we have at least two chars");
                    let last_e = existing_chars.next_back().expect("we know we have at least two chars");
                    if eq_or_numeric(last_i, last_e) {
                        if interned_chars.zip(existing_chars).filter(|&(i, e)| !eq_or_numeric(i, e)).count() != 1 {
                            continue;
                        }
                    } else {
                        let second_last_i = interned_chars.next_back().expect("we know we have at least three chars");
                        let second_last_e = existing_chars.next_back().expect("we know we have at least three chars");
                        if !eq_or_numeric(second_last_i, second_last_e) || second_last_i == '_' ||
                           !interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) {
                            // allowed similarity foo_x, foo_y
                            // or too many chars differ (foo_x, boo_y) or (foox, booy)
                            continue;
                        }
                        split_at = interned_name.char_indices().rev().next().map(|(i, _)| i);
                    }
                } else {
                    let second_i = interned_chars.next().expect("we know we have at least two chars");
                    let second_e = existing_chars.next().expect("we know we have at least two chars");
                    if !eq_or_numeric(second_i, second_e) || second_i == '_' ||
                       !interned_chars.zip(existing_chars).all(|(i, e)| eq_or_numeric(i, e)) {
                        // allowed similarity x_foo, y_foo
                        // or too many chars differ (x_foo, y_boo) or (xfoo, yboo)
                        continue;
                    }
                    split_at = interned_name.chars().next().map(|c| c.len_utf8());
                }
            }
            span_lint_and_then(self.0.cx,
                               SIMILAR_NAMES,
                               span,
                               "binding's name is too similar to existing binding",
                               |diag| {
                diag.span_note(existing_name.span, "existing binding defined here");
                if let Some(split) = split_at {
                    diag.span_help(span,
                                   &format!("separate the discriminating character by an \
                                                                underscore like: `{}_{}`",
                                                               &interned_name[..split],
                                                               &interned_name[split..]));
                }
            });
            return;
        }
        self.0.names.push(ExistingName {
            whitelist: get_whitelist(&interned_name).unwrap_or(&[]),
            interned: interned_name,
            span: span,
            len: count,
        });
    }
}

impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> {
    /// ensure scoping rules work
    fn apply<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) {
        let n = self.names.len();
        let single_char_count = self.single_char_names.len();
        f(self);
        self.names.truncate(n);
        self.single_char_names.truncate(single_char_count);
    }
}

impl<'a, 'b> Visitor for SimilarNamesLocalVisitor<'a, 'b> {
    fn visit_local(&mut self, local: &Local) {
        if let Some(ref init) = local.init {
            self.apply(|this| walk_expr(this, &**init));
        }
        // add the pattern after the expression because the bindings aren't available yet in the init expression
        SimilarNamesNameVisitor(self).visit_pat(&*local.pat);
    }
    fn visit_block(&mut self, blk: &Block) {
        self.apply(|this| walk_block(this, blk));
    }
    fn visit_arm(&mut self, arm: &Arm) {
        self.apply(|this| {
            // just go through the first pattern, as either all patterns bind the same bindings or rustc would have errored much earlier
            SimilarNamesNameVisitor(this).visit_pat(&arm.pats[0]);
            this.apply(|this| walk_expr(this, &arm.body));
        });
    }
    fn visit_item(&mut self, _: &Item) {
        // do not recurse into inner items
    }
}

impl EarlyLintPass for NonExpressiveNames {
    fn check_item(&mut self, cx: &EarlyContext, item: &Item) {
        if let ItemKind::Fn(ref decl, _, _, _, _, ref blk) = item.node {
            if !attr::contains_name(&item.attrs, "test") {
                let mut visitor = SimilarNamesLocalVisitor {
                    names: Vec::new(),
                    cx: cx,
                    lint: self,
                    single_char_names: Vec::new(),
                };
                // initialize with function arguments
                for arg in &decl.inputs {
                    SimilarNamesNameVisitor(&mut visitor).visit_pat(&arg.pat);
                }
                // walk all other bindings
                walk_block(&mut visitor, blk);
            }
        }
    }
}

/// Precondition: `a_name.chars().count() < b_name.chars().count()`.
fn levenstein_not_1(a_name: &str, b_name: &str) -> bool {
    debug_assert!(a_name.chars().count() < b_name.chars().count());
    let mut a_chars = a_name.chars();
    let mut b_chars = b_name.chars();
    while let (Some(a), Some(b)) = (a_chars.next(), b_chars.next()) {
        if a == b {
            continue;
        }
        if let Some(b2) = b_chars.next() {
            // check if there's just one character inserted
            return a != b2 || a_chars.ne(b_chars);
        } else {
            // tuple
            // ntuple
            return true;
        }
    }
    // for item in items
    true
}
<|endoftext|>


<commit_before>use std::cmp;

use crate::utils::{is_copy, is_self_ty, snippet, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_ast::attr;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{BindingAnnotation, Body, FnDecl, HirId, ItemKind, MutTy, Mutability, Node, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, Span};
use rustc_target::abi::LayoutOf;
use rustc_target::spec::abi::Abi;
use rustc_target::spec::Target;

declare_clippy_lint! {
    /// **What it does:** Checks for functions taking arguments by reference, where
    /// the argument type is `Copy` and small enough to be more efficient to always
    /// pass by value.
    ///
    /// **Why is this bad?** In many calling conventions instances of structs will
    /// be passed through registers if they fit into two or less general purpose
    /// registers.
    ///
    /// **Known problems:** This lint is target register size dependent, it is
    /// limited to 32-bit to try and reduce portability problems between 32 and
    /// 64-bit, but if you are compiling for 8 or 16-bit targets then the limit
    /// will be different.
    ///
    /// The configuration option `trivial_copy_size_limit` can be set to override
    /// this limit for a project.
    ///
    /// This lint attempts to allow passing arguments by reference if a reference
    /// to that argument is returned. This is implemented by comparing the lifetime
    /// of the argument and return value for equality. However, this can cause
    /// false positives in cases involving multiple lifetimes that are bounded by
    /// each other.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// // Bad
    /// fn foo(v: &u32) {}
    /// ```
    ///
    /// ```rust
    /// // Better
    /// fn foo(v: u32) {}
    /// ```
    pub TRIVIALLY_COPY_PASS_BY_REF,
    pedantic,
    "functions taking small copyable arguments by reference"
}

declare_clippy_lint! {
    /// **What it does:** Checks for functions taking arguments by value, where
    /// the argument type is `Copy` and large enough to be worth considering
    /// passing by reference. Does not trigger if the function is being exported,
    /// because that might induce API breakage, if the parameter is declared as mutable,
    /// or if the argument is a `self`.
    ///
    /// **Why is this bad?** Arguments passed by value might result in an unnecessary
    /// shallow copy, taking up more space in the stack and requiring a call to
    /// `memcpy`, which which can be expensive.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// #[derive(Clone, Copy)]
    /// struct TooLarge([u8; 2048]);
    ///
    /// // Bad
    /// fn foo(v: TooLarge) {}
    /// ```
    /// ```rust
    /// #[derive(Clone, Copy)]
    /// struct TooLarge([u8; 2048]);
    ///
    /// // Good
    /// fn foo(v: &TooLarge) {}
    /// ```
    pub LARGE_TYPES_PASSED_BY_VALUE,
    pedantic,
    "functions taking large arguments by value"
}

#[derive(Copy, Clone)]
pub struct PassByRefOrValue {
    ref_min_size: u64,
    value_max_size: u64,
}

impl<'tcx> PassByRefOrValue {
    pub fn new(ref_min_size: Option<u64>, value_max_size: u64, target: &Target) -> Self {
        let ref_min_size = ref_min_size.unwrap_or_else(|| {
            let bit_width = u64::from(target.pointer_width);
            // Cap the calculated bit width at 32-bits to reduce
            // portability problems between 32 and 64-bit targets
            let bit_width = cmp::min(bit_width, 32);
            #[allow(clippy::integer_division)]
            let byte_width = bit_width / 8;
            // Use a limit of 2 times the register byte width
            byte_width * 2
        });

        Self {
            ref_min_size,
            value_max_size,
        }
    }

    fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, decl: &FnDecl<'_>, span: Option<Span>) {
        let fn_def_id = cx.tcx.hir().local_def_id(hir_id);

        let fn_sig = cx.tcx.fn_sig(fn_def_id);
        let fn_sig = cx.tcx.erase_late_bound_regions(fn_sig);

        let fn_body = cx.enclosing_body.map(|id| cx.tcx.hir().body(id));

        for (index, (input, &ty)) in decl.inputs.iter().zip(fn_sig.inputs()).enumerate() {
            // All spans generated from a proc-macro invocation are the same...
            match span {
                Some(s) if s == input.span => return,
                _ => (),
            }

            match ty.kind() {
                ty::Ref(input_lt, ty, Mutability::Not) => {
                    // Use lifetimes to determine if we're returning a reference to the
                    // argument. In that case we can't switch to pass-by-value as the
                    // argument will not live long enough.
                    let output_lts = match *fn_sig.output().kind() {
                        ty::Ref(output_lt, _, _) => vec![output_lt],
                        ty::Adt(_, substs) => substs.regions().collect(),
                        _ => vec![],
                    };

                    if_chain! {
                        if !output_lts.contains(&input_lt);
                        if is_copy(cx, ty);
                        if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
                        if size <= self.ref_min_size;
                        if let hir::TyKind::Rptr(_, MutTy { ty: ref decl_ty, .. }) = input.kind;
                        then {
                            let value_type = if is_self_ty(decl_ty) {
                                "self".into()
                            } else {
                                snippet(cx, decl_ty.span, "_").into()
                            };
                            span_lint_and_sugg(
                                cx,
                                TRIVIALLY_COPY_PASS_BY_REF,
                                input.span,
                                &format!("this argument ({} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", size, self.ref_min_size),
                                "consider passing by value instead",
                                value_type,
                                Applicability::Unspecified,
                            );
                        }
                    }
                },

                ty::Adt(_, _) | ty::Array(_, _) | ty::Tuple(_) => {
                    // if function has a body and parameter is annotated with mut, ignore
                    if let Some(param) = fn_body.and_then(|body| body.params.get(index)) {
                        match param.pat.kind {
                            PatKind::Binding(BindingAnnotation::Unannotated, _, _, _) => {},
                            _ => continue,
                        }
                    }

                    if_chain! {
                        if !cx.access_levels.is_exported(hir_id);
                        if is_copy(cx, ty);
                        if !is_self_ty(input);
                        if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
                        if size > self.value_max_size;
                        then {
                            span_lint_and_sugg(
                                cx,
                                LARGE_TYPES_PASSED_BY_VALUE,
                                input.span,
                                &format!("this argument ({} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)", size, self.value_max_size),
                                "consider passing by reference instead",
                                format!("&{}", snippet(cx, input.span, "_")),
                                Applicability::MaybeIncorrect,
                            );
                        }
                    }
                },

                _ => {},
            }
        }
    }
}

impl_lint_pass!(PassByRefOrValue => [TRIVIALLY_COPY_PASS_BY_REF, LARGE_TYPES_PASSED_BY_VALUE]);

impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
        if item.span.from_expansion() {
            return;
        }

        if let hir::TraitItemKind::Fn(method_sig, _) = &item.kind {
            self.check_poly_fn(cx, item.hir_id, &*method_sig.decl, None);
        }
    }

    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        kind: FnKind<'tcx>,
        decl: &'tcx FnDecl<'_>,
        _body: &'tcx Body<'_>,
        span: Span,
        hir_id: HirId,
    ) {
        if span.from_expansion() {
            return;
        }

        match kind {
            FnKind::ItemFn(.., header, _, attrs) => {
                if header.abi != Abi::Rust {
                    return;
                }
                for a in attrs {
                    if let Some(meta_items) = a.meta_item_list() {
                        if a.has_name(sym::proc_macro_derive)
                            || (a.has_name(sym::inline) && attr::list_contains_name(&meta_items, sym::always))
                        {
                            return;
                        }
                    }
                }
            },
            FnKind::Method(..) => (),
            FnKind::Closure(..) => return,
        }

        // Exclude non-inherent impls
        if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
            if matches!(
                item.kind,
                ItemKind::Impl { of_trait: Some(_), .. } | ItemKind::Trait(..)
            ) {
                return;
            }
        }

        self.check_poly_fn(cx, hir_id, decl, Some(span));
    }
}
<commit_msg>Fix typo: `which which can be` -> `which can be`<commit_after>use std::cmp;

use crate::utils::{is_copy, is_self_ty, snippet, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_ast::attr;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{BindingAnnotation, Body, FnDecl, HirId, ItemKind, MutTy, Mutability, Node, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, Span};
use rustc_target::abi::LayoutOf;
use rustc_target::spec::abi::Abi;
use rustc_target::spec::Target;

declare_clippy_lint! {
    /// **What it does:** Checks for functions taking arguments by reference, where
    /// the argument type is `Copy` and small enough to be more efficient to always
    /// pass by value.
    ///
    /// **Why is this bad?** In many calling conventions instances of structs will
    /// be passed through registers if they fit into two or less general purpose
    /// registers.
    ///
    /// **Known problems:** This lint is target register size dependent, it is
    /// limited to 32-bit to try and reduce portability problems between 32 and
    /// 64-bit, but if you are compiling for 8 or 16-bit targets then the limit
    /// will be different.
    ///
    /// The configuration option `trivial_copy_size_limit` can be set to override
    /// this limit for a project.
    ///
    /// This lint attempts to allow passing arguments by reference if a reference
    /// to that argument is returned. This is implemented by comparing the lifetime
    /// of the argument and return value for equality. However, this can cause
    /// false positives in cases involving multiple lifetimes that are bounded by
    /// each other.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// // Bad
    /// fn foo(v: &u32) {}
    /// ```
    ///
    /// ```rust
    /// // Better
    /// fn foo(v: u32) {}
    /// ```
    pub TRIVIALLY_COPY_PASS_BY_REF,
    pedantic,
    "functions taking small copyable arguments by reference"
}

declare_clippy_lint! {
    /// **What it does:** Checks for functions taking arguments by value, where
    /// the argument type is `Copy` and large enough to be worth considering
    /// passing by reference. Does not trigger if the function is being exported,
    /// because that might induce API breakage, if the parameter is declared as mutable,
    /// or if the argument is a `self`.
    ///
    /// **Why is this bad?** Arguments passed by value might result in an unnecessary
    /// shallow copy, taking up more space in the stack and requiring a call to
    /// `memcpy`, which can be expensive.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// #[derive(Clone, Copy)]
    /// struct TooLarge([u8; 2048]);
    ///
    /// // Bad
    /// fn foo(v: TooLarge) {}
    /// ```
    /// ```rust
    /// #[derive(Clone, Copy)]
    /// struct TooLarge([u8; 2048]);
    ///
    /// // Good
    /// fn foo(v: &TooLarge) {}
    /// ```
    pub LARGE_TYPES_PASSED_BY_VALUE,
    pedantic,
    "functions taking large arguments by value"
}

#[derive(Copy, Clone)]
pub struct PassByRefOrValue {
    ref_min_size: u64,
    value_max_size: u64,
}

impl<'tcx> PassByRefOrValue {
    pub fn new(ref_min_size: Option<u64>, value_max_size: u64, target: &Target) -> Self {
        let ref_min_size = ref_min_size.unwrap_or_else(|| {
            let bit_width = u64::from(target.pointer_width);
            // Cap the calculated bit width at 32-bits to reduce
            // portability problems between 32 and 64-bit targets
            let bit_width = cmp::min(bit_width, 32);
            #[allow(clippy::integer_division)]
            let byte_width = bit_width / 8;
            // Use a limit of 2 times the register byte width
            byte_width * 2
        });

        Self {
            ref_min_size,
            value_max_size,
        }
    }

    fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, decl: &FnDecl<'_>, span: Option<Span>) {
        let fn_def_id = cx.tcx.hir().local_def_id(hir_id);

        let fn_sig = cx.tcx.fn_sig(fn_def_id);
        let fn_sig = cx.tcx.erase_late_bound_regions(fn_sig);

        let fn_body = cx.enclosing_body.map(|id| cx.tcx.hir().body(id));

        for (index, (input, &ty)) in decl.inputs.iter().zip(fn_sig.inputs()).enumerate() {
            // All spans generated from a proc-macro invocation are the same...
            match span {
                Some(s) if s == input.span => return,
                _ => (),
            }

            match ty.kind() {
                ty::Ref(input_lt, ty, Mutability::Not) => {
                    // Use lifetimes to determine if we're returning a reference to the
                    // argument. In that case we can't switch to pass-by-value as the
                    // argument will not live long enough.
                    let output_lts = match *fn_sig.output().kind() {
                        ty::Ref(output_lt, _, _) => vec![output_lt],
                        ty::Adt(_, substs) => substs.regions().collect(),
                        _ => vec![],
                    };

                    if_chain! {
                        if !output_lts.contains(&input_lt);
                        if is_copy(cx, ty);
                        if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
                        if size <= self.ref_min_size;
                        if let hir::TyKind::Rptr(_, MutTy { ty: ref decl_ty, .. }) = input.kind;
                        then {
                            let value_type = if is_self_ty(decl_ty) {
                                "self".into()
                            } else {
                                snippet(cx, decl_ty.span, "_").into()
                            };
                            span_lint_and_sugg(
                                cx,
                                TRIVIALLY_COPY_PASS_BY_REF,
                                input.span,
                                &format!("this argument ({} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", size, self.ref_min_size),
                                "consider passing by value instead",
                                value_type,
                                Applicability::Unspecified,
                            );
                        }
                    }
                },

                ty::Adt(_, _) | ty::Array(_, _) | ty::Tuple(_) => {
                    // if function has a body and parameter is annotated with mut, ignore
                    if let Some(param) = fn_body.and_then(|body| body.params.get(index)) {
                        match param.pat.kind {
                            PatKind::Binding(BindingAnnotation::Unannotated, _, _, _) => {},
                            _ => continue,
                        }
                    }

                    if_chain! {
                        if !cx.access_levels.is_exported(hir_id);
                        if is_copy(cx, ty);
                        if !is_self_ty(input);
                        if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
                        if size > self.value_max_size;
                        then {
                            span_lint_and_sugg(
                                cx,
                                LARGE_TYPES_PASSED_BY_VALUE,
                                input.span,
                                &format!("this argument ({} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)", size, self.value_max_size),
                                "consider passing by reference instead",
                                format!("&{}", snippet(cx, input.span, "_")),
                                Applicability::MaybeIncorrect,
                            );
                        }
                    }
                },

                _ => {},
            }
        }
    }
}

impl_lint_pass!(PassByRefOrValue => [TRIVIALLY_COPY_PASS_BY_REF, LARGE_TYPES_PASSED_BY_VALUE]);

impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
        if item.span.from_expansion() {
            return;
        }

        if let hir::TraitItemKind::Fn(method_sig, _) = &item.kind {
            self.check_poly_fn(cx, item.hir_id, &*method_sig.decl, None);
        }
    }

    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        kind: FnKind<'tcx>,
        decl: &'tcx FnDecl<'_>,
        _body: &'tcx Body<'_>,
        span: Span,
        hir_id: HirId,
    ) {
        if span.from_expansion() {
            return;
        }

        match kind {
            FnKind::ItemFn(.., header, _, attrs) => {
                if header.abi != Abi::Rust {
                    return;
                }
                for a in attrs {
                    if let Some(meta_items) = a.meta_item_list() {
                        if a.has_name(sym::proc_macro_derive)
                            || (a.has_name(sym::inline) && attr::list_contains_name(&meta_items, sym::always))
                        {
                            return;
                        }
                    }
                }
            },
            FnKind::Method(..) => (),
            FnKind::Closure(..) => return,
        }

        // Exclude non-inherent impls
        if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
            if matches!(
                item.kind,
                ItemKind::Impl { of_trait: Some(_), .. } | ItemKind::Trait(..)
            ) {
                return;
            }
        }

        self.check_poly_fn(cx, hir_id, decl, Some(span));
    }
}
<|endoftext|>


<commit_before><commit_msg>Simplify the API for LitPool<commit_after><|endoftext|>


<commit_before>/// Problem 54
/// In the card game poker, a hand consists of five cards and are ranked, from
/// lowest to highest, in the following way:
///
/// * High Card: Highest value card.
/// * One Pair: Two cards of the same value.
/// * Two Pairs: Two different pairs.
/// * Three of a Kind: Three cards of the same value.
/// * Straight: All cards are consecutive values.
/// * Flush: All cards of the same suit.
/// * Full House: Three of a kind and a pair.
/// * Four of a Kind: Four cards of the same value.
/// * Straight Flush: All cards are consecutive values of same suit.
/// * Royal Flush: Ten, Jack, Queen, King, Ace, in same suit.
///
/// The cards are valued in the order:
/// 2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King, Ace.
///
/// If two players have the same ranked hands then the rank made up of the
/// highest value wins; for example, a pair of eights beats a pair of fives
/// (see example 1 below). But if two ranks tie, for example, both players have
/// a pair of queens, then highest cards in each hand are compared (see example
/// 4 below); if the highest cards tie then the next highest cards are compared,
/// and so on.
///
/// Consider the following five hands dealt to two players:
///
/// Hand  Player 1           Player 2             Winner
/// ----  --------           --------             ------
/// 1     5H 5C 6S 7S KD     2C 3S 8S 8D TD       Player 2
///       Pair of Fives      Pair of Eights
///
/// 2     5D 8C 9S JS AC     2C 5C 7D 8S QH       Player 1
///       Highest card Ace   Highest card Queen
///
/// 3     2D 9C AS AH AC     3D 6D 7D TD QD       Player 2
///       Three Aces         Flush with Diamonds
///
/// 4     4D 6S 9H QH QC     3D 6D 7H QD QS       Player 1
///       Pair of Queens     Pair of Queens
///       Highest card Nine  Highest card Seven
///
/// 5     2H 2D 4C 4D 4S     3C 3D 3S 9S 9D       Player 1
///       Full House         Full House
///       With Three Fours   with Three Threes
///
/// The file, poker.txt, contains one-thousand random hands dealt to two
/// players. Each line of the file contains ten cards (separated by a single
/// space): the first five are Player 1's cards and the last five are Player 2's
/// cards. You can assume that all hands are valid (no invalid characters or
/// repeated cards), each player's hand is in no specific order, and in each
/// hand there is a clear winner.
///
/// How many hands does Player 1 win?
fn main() {
    let data: String = "\
        5H 5C 6S 6S KD 2C 2S 8S 8D TD\n\
        5H 5C 6S 7S KD 2C 3S 8S 8D TD\n\
        5D 8C 9S JS AC 2C 5C 7D 8S QH\n\
        2D 9C AS AH AC 3D 6D 7D TD QD\n\
        4D 6S 9H QH QC 3D 6D 7H QD QS\n\
        TD JS QH KH AC 3D 6D 7D QD QD\n\
        TD JD QD KD AD 3D 4D 5D 6D 7D\n\
        4D 4S 4H 4H AC 3D 3D 3D QD QD\n\
        2H 2D 4C 4D 4S 3C 3D 3S 9S 9D\n".to_string();

    let mut wins: Vec<u32> = vec![0, 0];

    for row in data.lines() {
        let mut hands: Vec<Vec<(u8,u8)>> = Vec::new();
        hands.push(Vec::new());
        hands.push(Vec::new());
        for cardstr in row.split(' ') {
            let mut card: (u8,u8) = (0,0);
            for (i,s) in cardstr.chars().enumerate() {
                match i {
                    0 => card.0 = match s {
                        '2' => 2,
                        '3' => 3,
                        '4' => 4,
                        '5' => 5,
                        '6' => 6,
                        '7' => 7,
                        '8' => 8,
                        '9' => 9,
                        'T' => 10,
                        'J' => 11,
                        'Q' => 12,
                        'K' => 13,
                        'A' => 14,
                        _ => 0,
                    },
                    1 => card.1 = match s {
                        'D' => 1,
                        'C' => 2,
                        'H' => 3,
                        'S' => 4,
                        _ => 0,
                    },
                    _ => (),
                };
            }
            if hands[0].len() < 5 {
                hands[0].push(card)
            } else {
                hands[1].push(card)
            }
        }
        for hand in &mut hands {
            hand.sort_by_key(|k| k.0);
        }

        println!("P1: {:?} -> {:?} \nP2: {:?} -> {:?}\n",
            hands[0], score(&hands[0]), hands[1], score(&hands[1]));
    }
    println!("Answer: {}", wins[0]);
}

struct HandInfo {
    flush: bool,
    straight: bool,
    pairing: Pairing
}

impl HandInfo {
    fn new(hand: &Vec<(u8,u8)>) -> HandInfo {
        HandInfo {
            flush: is_flush(hand),
            straight: is_straight(hand),
            pairing: hand_pairing(hand)
        }
    }
}

enum Pairing {
    Nothing { rank: Vec<u8> },
    Pair { pair: u8, kickers: Vec<u8> },
    TwoPair { high_pair: u8, low_pair: u8, kicker: u8 },
    Three { high: u8, kickers: Vec<u8> },
    FullHouse { triplet: u8, pair: u8 },
    Four { quad: u8, kicker: u8 },
}

fn hand_pairing(hand: &Vec<(u8,u8)>) -> Pairing {
    let mut counts: Vec<u8> = vec![0; 15];
    for card in hand {
        counts[card.0 as usize] += 1;
    }
    println!("{:?}", counts);
    let max: u8 = *counts.iter().max().unwrap();
    let ind_max: u8 = counts.iter().position(|&x| x == max).unwrap() as u8;
    match max {
        4 => {
            Pairing::Four {
                quad: ind_max,
                kicker: counts.iter().position(|&x| x == 1).unwrap() as u8
            }
        },
        3 => {
            // Look for full house or plain three-of-a-kind
            match counts.iter().position(|&x| x == 2) {
                Some(x) => {
                    Pairing::FullHouse {
                        triplet: ind_max,
                        pair: x as u8
                    }
                },
                None => {
                    Pairing::Three {
                        high: ind_max,
                        kickers: vec![0]
                    }
                }
            }
        },
        2 => {
            // Look for two pair
            let num_two: u8 = counts.iter()
                .filter(|&x| *x == 2)
                .fold(0, |a, _| a + 1) as u8;

            match num_two {
                2 => {
                    Pairing::TwoPair { high_pair: 0, low_pair: 0, kicker: 0 }
                },
                1 => {
                    Pairing::Pair { pair: 0, kickers: vec![0] }
                },
                _ => {
                    Pairing::Nothing { rank: vec![0] }
                }
            }

        },
        1 => {
            let mut r: Vec<u8> = Vec::new();
            for card in hand.iter().rev() {
                r.push(card.0);
            }
            Pairing::Nothing { rank: r }
        },
        _ => Pairing::Nothing { rank: vec![0] }
    }
}

/// Compute a score for a hand, in the form of (rank, high card, breaker).
/// The ranks are as follows:
/// 0 High Card: Highest value card.
/// 1 One Pair: Two cards of the same value.
/// 2 Two Pairs: Two different pairs.
/// 3 Three of a Kind: Three cards of the same value.
/// 4 Straight: All cards are consecutive values.
/// 5 Flush: All cards of the same suit.
/// 6 Full House: Three of a kind and a pair.
/// 7 Four of a Kind: Four cards of the same value.
/// 8 Straight Flush: All cards are consecutive values of same suit.
///   Royal Flush: Ten, Jack, Queen, King, Ace, in same suit.
///
/// Comparing hands of the same rank breaks ties on the high card first and then
/// on the breaker. For instance, the high card of a full house is the
/// three-of-a-kind, and the breaker is the pair.
///
/// Suits count as equal rank, and are not used to break ties.
fn score(hand: &Vec<(u8,u8)>) -> Vec<u8> {
    let info = HandInfo::new(hand);
    if info.straight && info.flush {
        vec![8, hand[4].0]
    } else if info.flush {
        let mut ret: Vec<u8> = vec![5];
        for card in hand.iter().rev() {
            ret.push(card.0);
        }
        ret
    } else if info.straight {
        vec![4, hand[4].0]
    } else {
        match info.pairing {
            Pairing::Four { quad: q, kicker: k } => vec![7, q, k],
            Pairing::FullHouse { triplet: t, pair: p } => vec![6, t, p],
            Pairing::Three { high: h, kickers: k } => {
                let mut v: Vec<u8> = vec![3, h];
                v.extend_from_slice(&k);
                v
            },
            Pairing::TwoPair {
                high_pair: h, low_pair: l, kicker: k
            } => vec![2, h, l, k],
            Pairing::Pair { pair: p, kickers: k } => {
                let mut v: Vec<u8> = vec![1, p];
                v.extend_from_slice(&k);
                v
            },
            Pairing::Nothing { rank: r } => {
                let mut v: Vec<u8> = vec![0];
                // let mut k: Vec<u8> = r;
                // k.reverse();
                v.extend_from_slice(&r);
                v
            },
        }
    }
}

fn is_flush(hand: &Vec<(u8,u8)>) -> bool {
    let last: u8 = hand[0].1;
    for card in hand {
        if card.1 != last {
            return false
        }
    }
    true
}

fn is_straight(hand: &Vec<(u8,u8)>) -> bool {
    for i in 1..hand.len() {
        if hand[i].0 != hand[i-1].0+1 {
            return false
        }
    }
    true
}
<commit_msg>Completes Rust Problem 54<commit_after>use std::io;
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;

/// Problem 54
/// In the card game poker, a hand consists of five cards and are ranked, from
/// lowest to highest, in the following way:
///
/// * High Card: Highest value card.
/// * One Pair: Two cards of the same value.
/// * Two Pairs: Two different pairs.
/// * Three of a Kind: Three cards of the same value.
/// * Straight: All cards are consecutive values.
/// * Flush: All cards of the same suit.
/// * Full House: Three of a kind and a pair.
/// * Four of a Kind: Four cards of the same value.
/// * Straight Flush: All cards are consecutive values of same suit.
/// * Royal Flush: Ten, Jack, Queen, King, Ace, in same suit.
///
/// The cards are valued in the order:
/// 2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, King, Ace.
///
/// If two players have the same ranked hands then the rank made up of the
/// highest value wins; for example, a pair of eights beats a pair of fives
/// (see example 1 below). But if two ranks tie, for example, both players have
/// a pair of queens, then highest cards in each hand are compared (see example
/// 4 below); if the highest cards tie then the next highest cards are compared,
/// and so on.
///
/// Consider the following five hands dealt to two players:
///
/// Hand  Player 1           Player 2             Winner
/// ----  --------           --------             ------
/// 1     5H 5C 6S 7S KD     2C 3S 8S 8D TD       Player 2
///       Pair of Fives      Pair of Eights
///
/// 2     5D 8C 9S JS AC     2C 5C 7D 8S QH       Player 1
///       Highest card Ace   Highest card Queen
///
/// 3     2D 9C AS AH AC     3D 6D 7D TD QD       Player 2
///       Three Aces         Flush with Diamonds
///
/// 4     4D 6S 9H QH QC     3D 6D 7H QD QS       Player 1
///       Pair of Queens     Pair of Queens
///       Highest card Nine  Highest card Seven
///
/// 5     2H 2D 4C 4D 4S     3C 3D 3S 9S 9D       Player 1
///       Full House         Full House
///       With Three Fours   with Three Threes
///
/// The file, poker.txt, contains one-thousand random hands dealt to two
/// players. Each line of the file contains ten cards (separated by a single
/// space): the first five are Player 1's cards and the last five are Player 2's
/// cards. You can assume that all hands are valid (no invalid characters or
/// repeated cards), each player's hand is in no specific order, and in each
/// hand there is a clear winner.
///
/// How many hands does Player 1 win?
fn main() {
    let data: String = "\
        5H 5C 6S 6S KD 2C 2S 8S 8D TD\n\
        5H 5C 6S 7S KD 2C 3S 8S 8D TD\n\
        5D 8C 9S JS AC 2C 5C 7D 8S QH\n\
        2D 9C AS AH AC 3D 6D 7D TD QD\n\
        4D 6S 9H QH QC 3D 6D 7H QD QS\n\
        TD JS QH KH AC 3D 6D 7D QD QD\n\
        TD JD QD KD AD 3D 4D 5D 6D 7D\n\
        4D 4S 4H 4H AC 3D 3D 3D QD QD\n\
        2H 2D 4C 4D 4S 3C 3D 3S 9S 9D\n".to_string();

    let mut f = match File::open("../data/p054_poker.txt") {
        Ok(file) => file,
        Err(e) => {
            println!("{}", e);
            panic!("Could not open file.")
        }
    };

    // [player 1, player 2, tie]
    let mut wins: Vec<u32> = vec![0; 3];

    for line in BufReader::new(f).lines() {
        let row = match line {
            Ok(s) => s,
            Err(e) => {
                println!("{}", e);
                panic!()
            }
        };
        let mut hands: Vec<Vec<(u8,u8)>> = Vec::new();
        hands.push(Vec::new());
        hands.push(Vec::new());
        for cardstr in row.split(' ') {
            let mut card: (u8,u8) = (0,0);
            for (i,s) in cardstr.chars().enumerate() {
                match i {
                    0 => card.0 = match s {
                        '2' => 2,
                        '3' => 3,
                        '4' => 4,
                        '5' => 5,
                        '6' => 6,
                        '7' => 7,
                        '8' => 8,
                        '9' => 9,
                        'T' => 10,
                        'J' => 11,
                        'Q' => 12,
                        'K' => 13,
                        'A' => 14,
                        _ => 0,
                    },
                    1 => card.1 = match s {
                        'D' => 1,
                        'C' => 2,
                        'H' => 3,
                        'S' => 4,
                        _ => 0,
                    },
                    _ => (),
                };
            }
            if hands[0].len() < 5 {
                hands[0].push(card)
            } else {
                hands[1].push(card)
            }
        }
        for hand in &mut hands {
            hand.sort_by_key(|k| k.0);
        }

        let a = score(&hands[0]);
        let b = score(&hands[1]);
        let w = winner(&a,&b);
        wins[w as usize] += 1;

        // println!("P1: {:?} -> {:?} \nP2: {:?} -> {:?}\nResult: {}\n",
        //     hands[0], a, hands[1], b, w);
    }
    println!("Wins: {:?}", wins);
    println!("Answer: {}", wins[0]);
}

struct HandInfo {
    flush: bool,
    straight: bool,
    pairing: Pairing
}

impl HandInfo {
    fn new(hand: &Vec<(u8,u8)>) -> HandInfo {
        HandInfo {
            flush: is_flush(hand),
            straight: is_straight(hand),
            pairing: hand_pairing(hand)
        }
    }
}

enum Pairing {
    Nothing { rank: Vec<u8> },
    Pair { pair: u8, kickers: Vec<u8> },
    TwoPair { high_pair: u8, low_pair: u8, kicker: u8 },
    Three { high: u8, kickers: Vec<u8> },
    FullHouse { triplet: u8, pair: u8 },
    Four { quad: u8, kicker: u8 },
}

fn hand_pairing(hand: &Vec<(u8,u8)>) -> Pairing {
    let mut counts: Vec<u8> = vec![0; 15];
    for card in hand {
        counts[card.0 as usize] += 1;
    }
    let max: u8 = *counts.iter().max().unwrap();
    let ind_max: u8 = counts.iter().position(|&x| x == max).unwrap() as u8;
    match max {
        4 => {
            Pairing::Four {
                quad: ind_max,
                kicker: counts.iter().position(|&x| x == 1).unwrap() as u8
            }
        },
        3 => {
            // Look for full house or plain three-of-a-kind
            match counts.iter().position(|&x| x == 2) {
                Some(x) => {
                    Pairing::FullHouse {
                        triplet: ind_max,
                        pair: x as u8
                    }
                },
                None => {
                    Pairing::Three {
                        high: ind_max,
                        kickers: vec![0]
                    }
                }
            }
        },
        2 => {
            // Look for two pair
            let num_two: u8 = counts.iter()
                .filter(|&x| *x == 2)
                .fold(0, |a, _| a + 1) as u8;

            match num_two {
                2 => {
                    Pairing::TwoPair {
                        high_pair: counts.iter().rposition(|&x| x == 2).unwrap() as u8,
                        low_pair: counts.iter().position(|&x| x == 2).unwrap() as u8,
                        kicker: counts.iter().position(|&x| x == 1).unwrap() as u8
                    }
                },
                1 => {
                    let mut k: Vec<u8> = Vec::new();
                    for (i,&c) in counts.iter().enumerate() {
                        if c == 1u8 {
                            k.push(i as u8);
                        }
                    }
                    k.reverse();
                    Pairing::Pair {
                        pair: counts.iter().position(|&x| x == 2).unwrap() as u8,
                        kickers: k
                    }
                },
                _ => {
                    Pairing::Nothing { rank: vec![0] }
                }
            }

        },
        1 => {
            let mut r: Vec<u8> = Vec::new();
            for card in hand.iter().rev() {
                r.push(card.0);
            }
            Pairing::Nothing { rank: r }
        },
        _ => Pairing::Nothing { rank: vec![0] }
    }
}

/// Compute a score for a hand, in the form of (rank, high card, breaker).
/// The ranks are as follows:
/// 0 High Card: Highest value card.
/// 1 One Pair: Two cards of the same value.
/// 2 Two Pairs: Two different pairs.
/// 3 Three of a Kind: Three cards of the same value.
/// 4 Straight: All cards are consecutive values.
/// 5 Flush: All cards of the same suit.
/// 6 Full House: Three of a kind and a pair.
/// 7 Four of a Kind: Four cards of the same value.
/// 8 Straight Flush: All cards are consecutive values of same suit.
///   Royal Flush: Ten, Jack, Queen, King, Ace, in same suit.
///
/// Comparing hands of the same rank breaks ties on the high card first and then
/// on the breaker. For instance, the high card of a full house is the
/// three-of-a-kind, and the breaker is the pair.
///
/// Suits count as equal rank, and are not used to break ties.
fn score(hand: &Vec<(u8,u8)>) -> Vec<u8> {
    let info = HandInfo::new(hand);
    if info.straight && info.flush {
        vec![8, hand[4].0]
    } else if info.flush {
        let mut ret: Vec<u8> = vec![5];
        for card in hand.iter().rev() {
            ret.push(card.0);
        }
        ret
    } else if info.straight {
        vec![4, hand[4].0]
    } else {
        match info.pairing {
            Pairing::Four { quad: q, kicker: k } => vec![7, q, k],
            Pairing::FullHouse { triplet: t, pair: p } => vec![6, t, p],
            Pairing::Three { high: h, kickers: k } => {
                let mut v: Vec<u8> = vec![3, h];
                v.extend_from_slice(&k);
                v
            },
            Pairing::TwoPair {
                high_pair: h, low_pair: l, kicker: k
            } => vec![2, h, l, k],
            Pairing::Pair { pair: p, kickers: k } => {
                let mut v: Vec<u8> = vec![1, p];
                v.extend_from_slice(&k);
                v
            },
            Pairing::Nothing { rank: r } => {
                let mut v: Vec<u8> = vec![0];
                // let mut k: Vec<u8> = r;
                // k.reverse();
                v.extend_from_slice(&r);
                v
            },
        }
    }
}

fn is_flush(hand: &Vec<(u8,u8)>) -> bool {
    let last: u8 = hand[0].1;
    for card in hand {
        if card.1 != last {
            return false
        }
    }
    true
}

fn is_straight(hand: &Vec<(u8,u8)>) -> bool {
    for i in 1..hand.len() {
        if hand[i].0 != hand[i-1].0+1 {
            return false
        }
    }
    true
}

/// Determine the winner of two hands. Pass the score result for each hand
/// to this function.
///
/// Return values
/// 0 - Hand A wins
/// 1 - Hand B wins
/// 2 - Draw. Hands are of equal rank
fn winner(a: &Vec<u8>, b: &Vec<u8>) -> u8 {
    let l: Vec<usize> = vec![a.len(), b.len()];
    for i in 0..*l.iter().max().unwrap() {
        if a[i] > b[i] {
            return 0
        } else if b[i] > a[i] {
            return 1
        }
    }
    2
}
<|endoftext|>


<commit_before>extern crate turtle;

use turtle::Turtle;

fn main() {
    let mut turtle = Turtle::new();

    turtle.set_speed(10);

    turtle.pen_up();
    turtle.forward(150.0);
    turtle.pen_down();

    gear(&mut turtle);

    turtle.pen_up();
    turtle.forward(45.0);
    turtle.left(90.0);
    turtle.pen_down();

    circle(&mut turtle);

    turtle.hide();
}

fn gear(turtle: &mut Turtle) {
    // These variable names don't actually mean much because this was created by guessing and
    // then checking and the result doesn't exactly abide by the values as they are shown.
    let teeth = 32.0;
    let tooth_size = 20.0;
    let angle = 360.0 / teeth;
    turtle.right(180.0 - angle * 6.0 / 2.0);
    for _ in 0..teeth as u64 {
        turtle.forward(tooth_size);
        turtle.left(180.0 - angle * 7.0);
        turtle.forward(tooth_size);
        turtle.right(180.0 - angle * 6.0);
    }

    turtle.right(angle * 6.0 / 2.0);
}

fn circle(turtle: &mut Turtle) {
    for _ in 0..360 {
        turtle.forward(1.5);
        turtle.right(1.0);
    }
}
<commit_msg>Adding more details to the rust logo<commit_after>extern crate turtle;

use turtle::Turtle;

fn main() {
    let mut turtle = Turtle::new();

    turtle.set_speed(11);

    turtle.pen_up();
    turtle.forward(150.0);
    turtle.pen_down();

    gear(&mut turtle);

    turtle.pen_up();
    turtle.forward(45.0);
    turtle.left(90.0);
    turtle.pen_down();

    inner_gear(&mut turtle);

    turtle.wait_for_click();
    turtle.hide();
}

fn gear(turtle: &mut Turtle) {
    // Much of this code was figured out by guessing and checking
    let teeth = 32.0;
    let tooth_size = 20.0;
    let angle = 360.0 / teeth;
    turtle.right(180.0 - angle * 6.0 / 2.0);
    for _ in 0..teeth as u64 {
        turtle.forward(tooth_size);
        turtle.left(180.0 - angle * 7.0);
        turtle.forward(tooth_size);
        turtle.right(180.0 - angle * 6.0);
    }

    turtle.right(angle * 6.0 / 2.0);
}

fn inner_gear(turtle: &mut Turtle) {
    inner_circle(turtle);
    inner_teeth(turtle);
}

fn inner_circle(turtle: &mut Turtle) {
    for _ in 0..360 {
        turtle.forward(1.5);
        turtle.right(1.0);
    }
}

fn inner_teeth(turtle: &mut Turtle) {
    let tooth_size = 40.0;
    turtle.pen_up();
    turtle.left(90.0);
    turtle.forward(10.0);
    turtle.right(90.0);
    turtle.pen_down();

    for _ in 0..5 {
        turtle.pen_up();
        turtle.forward(tooth_size / 2.0);
        turtle.pen_down();

        turtle.right(120.0);
        turtle.forward(tooth_size);
        turtle.right(120.0);
        turtle.forward(tooth_size);
        turtle.right(120.0);

        turtle.pen_up();
        turtle.forward(tooth_size / 2.0);
        turtle.right(90.0);
        turtle.forward(5.0);
        turtle.left(90.0);
        turtle.pen_down();

        inner_tooth_circle(turtle);

        turtle.pen_up();
        turtle.left(90.0);
        turtle.forward(5.0);
        turtle.right(90.0);
        for _ in 0..360/5/2 {
            turtle.forward(3.41);
            turtle.right(2.0);
        }
        turtle.pen_down();
    }
}

fn inner_tooth_circle(turtle: &mut Turtle) {
    for _ in 0..360/8 {
        turtle.forward(1.0);
        turtle.right(8.0);
    }
}
<|endoftext|>


<commit_before><commit_msg>update to recent av_format<commit_after><|endoftext|>


<commit_before>struct Rectangle {
    width: u32,
    height: u32,
}

fn main() {
    let rect1 = Rectangle {  width: 30, height: 50 };

    println!(
        "The area of the rectangle is {} square pixels.",
        area(&rect1)
    );
}

fn area(rectangle: &Rectangle) -> u32 {
    rectangle.width * rectangle.height
}
<commit_msg>working v2<commit_after>#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

fn main() {
    let rect1 = Rectangle {  width: 30, height: 50 };

    println!(
        "The area of the rectangle is {} square pixels.",
        area(&rect1)
    );
    println!("rect1 is {:?}", rect1);
}

fn area(rectangle: &Rectangle) -> u32 {
    rectangle.width * rectangle.height
}
<|endoftext|>


<commit_before>
use super::*;

//

tests_impls!
{
  fn basic()
  {
    let src = "";
    let req = TheModule::string::isolate_left()
    .src( src )
    .perform();
    let mut exp = ( "", None, "" );
    assert_eq!( req, exp );
  }

  fn isolate_left_or_none()
  {
    /* no entry */
    let src = "abaca";
    let req = TheModule::string::isolate_left()
    .src( src )
    .delimeter( "f" )
    .none( true )
    .perform();
    let mut exp = ( "", None, "abaca" );
    assert_eq!( req, exp );

    /* default */
    let src = "abaca";
    let req = TheModule::string::isolate_left()
    .src( src )
    .delimeter( "a" )
    .none( true )
    .perform();
    let mut exp = ( "", Some( "a" ), "baca" );
    assert_eq!( req, exp );

    /* times - 0 */
    let src = "abaca";
    let req = TheModule::string::isolate_left()
    .src( src )
    .delimeter( "a" )
    .times( 0 )
    .none( true )
    .perform();
    let mut exp = ( "", None, "abaca" );
    assert_eq!( req, exp );

    /* times - 1 */
    let src = "abaca";
    let req = TheModule::string::isolate_left()
    .src( src )
    .delimeter( "a" )
    .times( 1 )
    .none( true )
    .perform();
    let mut exp = ( "", Some( "a" ), "baca" );
    assert_eq!( req, exp );

    /* times - 2 */
    let src = "abaca";
    let req = TheModule::string::isolate_left()
    .src( src )
    .delimeter( "a" )
    .times( 2 )
    .none( true )
    .perform();
    let mut exp = ( "ab", Some( "a" ), "ca" );
    assert_eq!( req, exp );

    /* times - 3 */
    let src = "abaca";
    let req = TheModule::string::isolate_left()
    .src( src )
    .delimeter( "a" )
    .times( 3 )
    .none( true )
    .perform();
    let mut exp = ( "abac", Some( "a" ), "" );
    assert_eq!( req, exp );

    /* times - 4 */
    let src = "abaca";
    let req = TheModule::string::isolate_left()
    .src( src )
    .delimeter( "a" )
    .times( 4 )
    .none( true )
    .perform();
    let mut exp = ( "", None, "abaca" );
    assert_eq!( req, exp );
  }
}

//

tests_index!
{
  basic,
  isolate_left_or_none,
}
<commit_msg>Write test routine `isolate_right_or_none`<commit_after>
use super::*;

//

tests_impls!
{
  fn basic()
  {
    let src = "";
    let req = TheModule::string::isolate_left()
    .src( src )
    .perform();
    let mut exp = ( "", None, "" );
    assert_eq!( req, exp );
  }

  //

  fn isolate_left_or_none()
  {
    /* no entry */
    let src = "abaca";
    let req = TheModule::string::isolate_left()
    .src( src )
    .delimeter( "f" )
    .none( true )
    .perform();
    let mut exp = ( "", None, "abaca" );
    assert_eq!( req, exp );

    /* default */
    let src = "abaca";
    let req = TheModule::string::isolate_left()
    .src( src )
    .delimeter( "a" )
    .none( true )
    .perform();
    let mut exp = ( "", Some( "a" ), "baca" );
    assert_eq!( req, exp );

    /* times - 0 */
    let src = "abaca";
    let req = TheModule::string::isolate_left()
    .src( src )
    .delimeter( "a" )
    .times( 0 )
    .none( true )
    .perform();
    let mut exp = ( "", None, "abaca" );
    assert_eq!( req, exp );

    /* times - 1 */
    let src = "abaca";
    let req = TheModule::string::isolate_left()
    .src( src )
    .delimeter( "a" )
    .times( 1 )
    .none( true )
    .perform();
    let mut exp = ( "", Some( "a" ), "baca" );
    assert_eq!( req, exp );

    /* times - 2 */
    let src = "abaca";
    let req = TheModule::string::isolate_left()
    .src( src )
    .delimeter( "a" )
    .times( 2 )
    .none( true )
    .perform();
    let mut exp = ( "ab", Some( "a" ), "ca" );
    assert_eq!( req, exp );

    /* times - 3 */
    let src = "abaca";
    let req = TheModule::string::isolate_left()
    .src( src )
    .delimeter( "a" )
    .times( 3 )
    .none( true )
    .perform();
    let mut exp = ( "abac", Some( "a" ), "" );
    assert_eq!( req, exp );

    /* times - 4 */
    let src = "abaca";
    let req = TheModule::string::isolate_left()
    .src( src )
    .delimeter( "a" )
    .times( 4 )
    .none( true )
    .perform();
    let mut exp = ( "", None, "abaca" );
    assert_eq!( req, exp );
  }

  //

  fn isolate_right_or_none()
  {
    /* no entry */
    let src = "abaca";
    let req = TheModule::string::isolate_right()
    .src( src )
    .delimeter( "f" )
    .none( true )
    .perform();
    let mut exp = ( "abaca", None, "" );
    assert_eq!( req, exp );

    /* default */
    let src = "abaca";
    let req = TheModule::string::isolate_right()
    .src( src )
    .delimeter( "a" )
    .none( true )
    .perform();
    let mut exp = ( "abac", Some( "a" ), "" );
    assert_eq!( req, exp );

    /* times - 0 */
    let src = "abaca";
    let req = TheModule::string::isolate_right()
    .src( src )
    .delimeter( "a" )
    .times( 0 )
    .none( true )
    .perform();
    let mut exp = ( "abaca", None, "" );
    assert_eq!( req, exp );

    /* times - 1 */
    let src = "abaca";
    let req = TheModule::string::isolate_right()
    .src( src )
    .delimeter( "a" )
    .times( 1 )
    .none( true )
    .perform();
    let mut exp = ( "abac", Some( "a" ), "" );
    assert_eq!( req, exp );

    /* times - 2 */
    let src = "abaca";
    let req = TheModule::string::isolate_right()
    .src( src )
    .delimeter( "a" )
    .times( 2 )
    .none( true )
    .perform();
    let mut exp = ( "ab", Some( "a" ), "ca" );
    assert_eq!( req, exp );

    /* times - 3 */
    let src = "abaca";
    let req = TheModule::string::isolate_right()
    .src( src )
    .delimeter( "a" )
    .times( 3 )
    .none( true )
    .perform();
    let mut exp = ( "", Some( "a" ), "baca" );
    assert_eq!( req, exp );

    /* times - 4 */
    let src = "abaca";
    let req = TheModule::string::isolate_right()
    .src( src )
    .delimeter( "a" )
    .times( 4 )
    .none( true )
    .perform();
    let mut exp = ( "abaca", None, "" );
    assert_eq!( req, exp );
  }
}

//

tests_index!
{
  basic,
  isolate_left_or_none,
  isolate_right_or_none,
}
<|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/. */

use dom::attr::Attr;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::HTMLBodyElementBinding::{self, HTMLBodyElementMethods};
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::codegen::InheritTypes::{EventTargetCast};
use dom::bindings::codegen::InheritTypes::{HTMLBodyElementDerived, HTMLElementCast};
use dom::bindings::js::Root;
use dom::bindings::utils::Reflectable;
use dom::document::Document;
use dom::element::{AttributeMutation, ElementTypeId};
use dom::eventtarget::{EventTarget, EventTargetTypeId};
use dom::htmlelement::{HTMLElement, HTMLElementTypeId};
use dom::node::{Node, NodeTypeId, window_from_node, document_from_node};
use dom::virtualmethods::VirtualMethods;
use msg::constellation_msg::ConstellationChan;
use msg::constellation_msg::Msg as ConstellationMsg;

use cssparser::RGBA;
use url::{Url, UrlParser};
use util::str::{self, DOMString};

use std::borrow::ToOwned;
use std::cell::Cell;
use std::rc::Rc;
use time;

/// How long we should wait before performing the initial reflow after `<body>` is parsed, in
/// nanoseconds.
const INITIAL_REFLOW_DELAY: u64 = 200_000_000;

#[dom_struct]
pub struct HTMLBodyElement {
    htmlelement: HTMLElement,
    background_color: Cell<Option<RGBA>>,
    background: DOMRefCell<Option<Url>>
}

impl HTMLBodyElementDerived for EventTarget {
    fn is_htmlbodyelement(&self) -> bool {
        *self.type_id() == EventTargetTypeId::Node(NodeTypeId::Element(ElementTypeId::HTMLElement(
                    HTMLElementTypeId::HTMLBodyElement)))
    }
}

impl HTMLBodyElement {
    fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: &Document)
                     -> HTMLBodyElement {
        HTMLBodyElement {
            htmlelement: HTMLElement::new_inherited(HTMLElementTypeId::HTMLBodyElement,
                                                    localName,
                                                    prefix,
                                                    document),
            background_color: Cell::new(None),
            background: DOMRefCell::new(None)
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: DOMString, prefix: Option<DOMString>, document: &Document)
               -> Root<HTMLBodyElement> {
        let element = HTMLBodyElement::new_inherited(localName, prefix, document);
        Node::reflect_node(box element, document, HTMLBodyElementBinding::Wrap)
    }
}

impl HTMLBodyElementMethods for HTMLBodyElement {
    // https://html.spec.whatwg.org/multipage#dom-body-bgcolor
    make_getter!(BgColor, "bgcolor");

    // https://html.spec.whatwg.org/multipage#dom-body-bgcolor
    make_setter!(SetBgColor, "bgcolor");

    // https://html.spec.whatwg.org/multipage/#the-body-element
    fn GetOnunload(&self) -> Option<Rc<EventHandlerNonNull>> {
        let win = window_from_node(self);
        win.r().GetOnunload()
    }

    // https://html.spec.whatwg.org/multipage/#the-body-element
    fn SetOnunload(&self, listener: Option<Rc<EventHandlerNonNull>>) {
        let win = window_from_node(self);
        win.r().SetOnunload(listener)
    }
}

impl HTMLBodyElement {
    pub fn get_background_color(&self) -> Option<RGBA> {
        self.background_color.get()
    }

    #[allow(unsafe_code)]
    pub fn get_background(&self) -> Option<Url> {
        unsafe {
            self.background.borrow_for_layout().clone()
        }
    }
}

impl VirtualMethods for HTMLBodyElement {
    fn super_type<'b>(&'b self) -> Option<&'b VirtualMethods> {
        let element: &HTMLElement = HTMLElementCast::from_ref(self);
        Some(element as &VirtualMethods)
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        if let Some(ref s) = self.super_type() {
            s.bind_to_tree(tree_in_doc);
        }

        if !tree_in_doc {
            return
        }

        let window = window_from_node(self);
        let document = window.r().Document();
        document.r().set_reflow_timeout(time::precise_time_ns() + INITIAL_REFLOW_DELAY);
        let ConstellationChan(ref chan) = window.r().constellation_chan();
        let event = ConstellationMsg::HeadParsed;
        chan.send(event).unwrap();
    }

    fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
        self.super_type().unwrap().attribute_mutated(attr, mutation);
        match (attr.local_name(), mutation) {
            (&atom!(bgcolor), _) => {
                self.background_color.set(mutation.new_value(attr).and_then(|value| {
                    str::parse_legacy_color(&value).ok()
                }));
            },
            (&atom!(background), _) => {
                *self.background.borrow_mut() = mutation.new_value(attr).and_then(|value| {
                    let base = document_from_node(self).url();
                    UrlParser::new().base_url(&base).parse(&value).ok()
                });
            },
            (name, AttributeMutation::Set(_)) if name.starts_with("on") => {
                static FORWARDED_EVENTS: &'static [&'static str] =
                    &["onfocus", "onload", "onscroll", "onafterprint", "onbeforeprint",
                      "onbeforeunload", "onhashchange", "onlanguagechange", "onmessage",
                      "onoffline", "ononline", "onpagehide", "onpageshow", "onpopstate",
                      "onstorage", "onresize", "onunload", "onerror"];
                let window = window_from_node(self);
                let (cx, url, reflector) = (window.get_cx(),
                                            window.get_url(),
                                            window.reflector().get_jsobject());
                let evtarget =
                    if FORWARDED_EVENTS.iter().any(|&event| &**name == event) {
                        EventTargetCast::from_ref(window.r())
                    } else {
                        EventTargetCast::from_ref(self)
                    };
                evtarget.set_event_handler_uncompiled(cx, url, reflector,
                                                      &name[2..],
                                                      (**attr.value()).to_owned());
            },
            _ => {}
        }
    }
}
<commit_msg>Auto merge of #7623 - aidanhs:aphs-atomise-forwarded-events, r=nox<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/. */

use dom::attr::Attr;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::HTMLBodyElementBinding::{self, HTMLBodyElementMethods};
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::codegen::InheritTypes::{EventTargetCast};
use dom::bindings::codegen::InheritTypes::{HTMLBodyElementDerived, HTMLElementCast};
use dom::bindings::js::Root;
use dom::bindings::utils::Reflectable;
use dom::document::Document;
use dom::element::{AttributeMutation, ElementTypeId};
use dom::eventtarget::{EventTarget, EventTargetTypeId};
use dom::htmlelement::{HTMLElement, HTMLElementTypeId};
use dom::node::{Node, NodeTypeId, window_from_node, document_from_node};
use dom::virtualmethods::VirtualMethods;
use msg::constellation_msg::ConstellationChan;
use msg::constellation_msg::Msg as ConstellationMsg;

use cssparser::RGBA;
use url::{Url, UrlParser};
use util::str::{self, DOMString};

use std::borrow::ToOwned;
use std::cell::Cell;
use std::rc::Rc;
use time;

/// How long we should wait before performing the initial reflow after `<body>` is parsed, in
/// nanoseconds.
const INITIAL_REFLOW_DELAY: u64 = 200_000_000;

#[dom_struct]
pub struct HTMLBodyElement {
    htmlelement: HTMLElement,
    background_color: Cell<Option<RGBA>>,
    background: DOMRefCell<Option<Url>>
}

impl HTMLBodyElementDerived for EventTarget {
    fn is_htmlbodyelement(&self) -> bool {
        *self.type_id() == EventTargetTypeId::Node(NodeTypeId::Element(ElementTypeId::HTMLElement(
                    HTMLElementTypeId::HTMLBodyElement)))
    }
}

impl HTMLBodyElement {
    fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: &Document)
                     -> HTMLBodyElement {
        HTMLBodyElement {
            htmlelement: HTMLElement::new_inherited(HTMLElementTypeId::HTMLBodyElement,
                                                    localName,
                                                    prefix,
                                                    document),
            background_color: Cell::new(None),
            background: DOMRefCell::new(None)
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: DOMString, prefix: Option<DOMString>, document: &Document)
               -> Root<HTMLBodyElement> {
        let element = HTMLBodyElement::new_inherited(localName, prefix, document);
        Node::reflect_node(box element, document, HTMLBodyElementBinding::Wrap)
    }
}

impl HTMLBodyElementMethods for HTMLBodyElement {
    // https://html.spec.whatwg.org/multipage#dom-body-bgcolor
    make_getter!(BgColor, "bgcolor");

    // https://html.spec.whatwg.org/multipage#dom-body-bgcolor
    make_setter!(SetBgColor, "bgcolor");

    // https://html.spec.whatwg.org/multipage/#the-body-element
    fn GetOnunload(&self) -> Option<Rc<EventHandlerNonNull>> {
        let win = window_from_node(self);
        win.r().GetOnunload()
    }

    // https://html.spec.whatwg.org/multipage/#the-body-element
    fn SetOnunload(&self, listener: Option<Rc<EventHandlerNonNull>>) {
        let win = window_from_node(self);
        win.r().SetOnunload(listener)
    }
}

impl HTMLBodyElement {
    pub fn get_background_color(&self) -> Option<RGBA> {
        self.background_color.get()
    }

    #[allow(unsafe_code)]
    pub fn get_background(&self) -> Option<Url> {
        unsafe {
            self.background.borrow_for_layout().clone()
        }
    }
}

impl VirtualMethods for HTMLBodyElement {
    fn super_type<'b>(&'b self) -> Option<&'b VirtualMethods> {
        let element: &HTMLElement = HTMLElementCast::from_ref(self);
        Some(element as &VirtualMethods)
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        if let Some(ref s) = self.super_type() {
            s.bind_to_tree(tree_in_doc);
        }

        if !tree_in_doc {
            return
        }

        let window = window_from_node(self);
        let document = window.r().Document();
        document.r().set_reflow_timeout(time::precise_time_ns() + INITIAL_REFLOW_DELAY);
        let ConstellationChan(ref chan) = window.r().constellation_chan();
        let event = ConstellationMsg::HeadParsed;
        chan.send(event).unwrap();
    }

    fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
        self.super_type().unwrap().attribute_mutated(attr, mutation);
        match (attr.local_name(), mutation) {
            (&atom!(bgcolor), _) => {
                self.background_color.set(mutation.new_value(attr).and_then(|value| {
                    str::parse_legacy_color(&value).ok()
                }));
            },
            (&atom!(background), _) => {
                *self.background.borrow_mut() = mutation.new_value(attr).and_then(|value| {
                    let base = document_from_node(self).url();
                    UrlParser::new().base_url(&base).parse(&value).ok()
                });
            },
            (name, AttributeMutation::Set(_)) if name.starts_with("on") => {
                let window = window_from_node(self);
                let (cx, url, reflector) = (window.get_cx(),
                                            window.get_url(),
                                            window.reflector().get_jsobject());
                let evtarget = match name {
                    &atom!(onfocus) | &atom!(onload) | &atom!(onscroll) | &atom!(onafterprint) |
                    &atom!(onbeforeprint) | &atom!(onbeforeunload) | &atom!(onhashchange) |
                    &atom!(onlanguagechange) | &atom!(onmessage) | &atom!(onoffline) | &atom!(ononline) |
                    &atom!(onpagehide) | &atom!(onpageshow) | &atom!(onpopstate) | &atom!(onstorage) |
                    &atom!(onresize) | &atom!(onunload) | &atom!(onerror)
                      => EventTargetCast::from_ref(window.r()), // forwarded event
                    _ => EventTargetCast::from_ref(self),
                };
                evtarget.set_event_handler_uncompiled(cx, url, reflector,
                                                      &name[2..],
                                                      (**attr.value()).to_owned());
            },
            _ => {}
        }
    }
}
<|endoftext|>


<commit_before>#[test]
fn it_works() {
}
<commit_msg>Pull in the modules in lib.rs<commit_after>extern crate toml;

pub mod content;
pub mod entry;
pub mod error;
pub mod header;
pub mod single_use_lock;
pub mod store;

<|endoftext|>