<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 std::local_data;
use cssparser::ast::{SyntaxError, SourceLocation};

pub struct ErrorLoggerIterator<I>(I);

impl<T, I: Iterator<Result<T, SyntaxError>>> Iterator<T> for ErrorLoggerIterator<I> {
    fn next(&mut self) -> Option<T> {
        let ErrorLoggerIterator(ref mut this) = *self;
        loop {
            match this.next() {
                Some(Ok(v)) => return Some(v),
                Some(Err(error)) => log_css_error(error.location, format!("{:?}", error.reason)),
                None => return None,
            }
        }
   }
}

local_data_key!(silence_errors: ())

pub fn log_css_error(location: SourceLocation, message: &str) {
    // TODO eventually this will got into a "web console" or something.
    if local_data::get(silence_errors, |silenced| silenced.is_none()) {
        error!("{:u}:{:u} {:s}", location.line, location.column, message)
    }
}

pub fn with_errors_silenced<T>(f: || -> T) -> T {
    local_data::set(silence_errors, ());
    let result = f();
    local_data::pop(silence_errors);
    result
}
<commit_msg>Fix the silencing of CSS errors in the UA stylesheet.<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 std::local_data;
use cssparser::ast::{SyntaxError, SourceLocation};

pub struct ErrorLoggerIterator<I>(I);

impl<T, I: Iterator<Result<T, SyntaxError>>> Iterator<T> for ErrorLoggerIterator<I> {
    fn next(&mut self) -> Option<T> {
        let ErrorLoggerIterator(ref mut this) = *self;
        loop {
            match this.next() {
                Some(Ok(v)) => return Some(v),
                Some(Err(error)) => log_css_error(error.location, format!("{:?}", error.reason)),
                None => return None,
            }
        }
   }
}

// FIXME: go back to `()` instead of `bool` after upgrading Rust
// past 898669c4e203ae91e2048fb6c0f8591c867bccc6
// Using bool is a work-around for https://github.com/mozilla/rust/issues/13322
local_data_key!(silence_errors: bool)

pub fn log_css_error(location: SourceLocation, message: &str) {
    // TODO eventually this will got into a "web console" or something.
    if local_data::get(silence_errors, |silenced| silenced.is_none()) {
        error!("{:u}:{:u} {:s}", location.line, location.column, message)
    }
}

pub fn with_errors_silenced<T>(f: || -> T) -> T {
    local_data::set(silence_errors, true);
    let result = f();
    local_data::pop(silence_errors);
    result
}
<|endoftext|>


<commit_before>use rustc::lint::*;
use rustc::hir;
use syntax::codemap;
use utils::{snippet, span_lint_and_then};

/// **What it does:** Checks for variable declarations immediately followed by a
/// conditional affectation.
///
/// **Why is this bad?** This is not idiomatic Rust.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust,ignore
/// let foo;
///
/// if bar() {
///     foo = 42;
/// } else {
///     foo = 0;
/// }
///
/// let mut baz = None;
///
/// if bar() {
///     baz = Some(42);
/// }
/// ```
///
/// should be written
///
/// ```rust,ignore
/// let foo = if bar() {
///     42;
/// } else {
///     0;
/// };
///
/// let baz = if bar() {
///     Some(42);
/// } else {
///     None
/// };
/// ```
declare_lint! {
    pub USELESS_LET_IF_SEQ,
    Warn,
    "unidiomatic `let mut` declaration followed by initialization in `if`"
}

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

impl LintPass for LetIfSeq {
    fn get_lints(&self) -> LintArray {
        lint_array!(USELESS_LET_IF_SEQ)
    }
}

impl LateLintPass for LetIfSeq {
    fn check_block(&mut self, cx: &LateContext, block: &hir::Block) {
        let mut it = block.stmts.iter().peekable();
        while let Some(stmt) = it.next() {
            if_let_chain! {[
                let Some(expr) = it.peek(),
                let hir::StmtDecl(ref decl, _) = stmt.node,
                let hir::DeclLocal(ref decl) = decl.node,
                let hir::PatKind::Binding(mode, ref name, None) = decl.pat.node,
                let Some(def) = cx.tcx.def_map.borrow().get(&decl.pat.id),
                let hir::StmtExpr(ref if_, _) = expr.node,
                let hir::ExprIf(ref cond, ref then, ref else_) = if_.node,
                !used_in_expr(cx, def.full_def().def_id(), cond),
                let Some(value) = check_assign(cx, def.full_def().def_id(), then),
                !used_in_expr(cx, def.full_def().def_id(), value),
            ], {
                let span = codemap::mk_sp(stmt.span.lo, if_.span.hi);

                let (default_multi_stmts, default) = if let Some(ref else_) = *else_ {
                    if let hir::ExprBlock(ref else_) = else_.node {
                        if let Some(default) = check_assign(cx, def.full_def().def_id(), else_) {
                            (else_.stmts.len() > 1, default)
                        } else if let Some(ref default) = decl.init {
                            (true, &**default)
                        } else {
                            continue;
                        }
                    } else {
                        continue;
                    }
                } else if let Some(ref default) = decl.init {
                    (false, &**default)
                } else {
                    continue;
                };

                let mutability = match mode {
                    hir::BindByRef(hir::MutMutable) | hir::BindByValue(hir::MutMutable) => "<mut> ",
                    _ => "",
                };

                // FIXME: this should not suggest `mut` if we can detect that the variable is not
                // use mutably after the `if`

                let sug = format!(
                    "let {mut}{name} = if {cond} {{{then} {value} }} else {{{else} {default} }};",
                    mut=mutability,
                    name=name.node,
                    cond=snippet(cx, cond.span, "_"),
                    then=if then.stmts.len() > 1 { " ..;" } else { "" },
                    else=if default_multi_stmts { " ..;" } else { "" },
                    value=snippet(cx, value.span, "<value>"),
                    default=snippet(cx, default.span, "<default>"),
                );
                span_lint_and_then(cx,
                                   USELESS_LET_IF_SEQ,
                                   span,
                                   "`if _ { .. } else { .. }` is an expression",
                                   |db| {
                                       db.span_suggestion(span,
                                                          "it is more idiomatic to write",
                                                          sug);
                                       if !mutability.is_empty() {
                                           db.note("you might not need `mut` at all");
                                       }
                                   });
            }}
        }
    }
}

struct UsedVisitor<'a, 'tcx: 'a> {
    cx: &'a LateContext<'a, 'tcx>,
    id: hir::def_id::DefId,
    used: bool,
}

impl<'a, 'tcx, 'v> hir::intravisit::Visitor<'v> for UsedVisitor<'a, 'tcx> {
    fn visit_expr(&mut self, expr: &'v hir::Expr) {
        if_let_chain! {[
            let hir::ExprPath(None, _) = expr.node,
            let Some(def) = self.cx.tcx.def_map.borrow().get(&expr.id),
            self.id == def.full_def().def_id(),
        ], {
            self.used = true;
            return;
        }}
        hir::intravisit::walk_expr(self, expr);
    }
}

fn check_assign<'e>(cx: &LateContext, decl: hir::def_id::DefId, block: &'e hir::Block) -> Option<&'e hir::Expr> {
    if_let_chain! {[
        block.expr.is_none(),
        let Some(expr) = block.stmts.iter().last(),
        let hir::StmtSemi(ref expr, _) = expr.node,
        let hir::ExprAssign(ref var, ref value) = expr.node,
        let hir::ExprPath(None, _) = var.node,
        let Some(def) = cx.tcx.def_map.borrow().get(&var.id),
        decl == def.full_def().def_id(),
    ], {
        let mut v = UsedVisitor {
            cx: cx,
            id: decl,
            used: false,
        };

        for s in block.stmts.iter().take(block.stmts.len()-1) {
            hir::intravisit::walk_stmt(&mut v, s);

            if v.used {
                return None;
            }
        }

        return Some(value);
    }}

    None
}

fn used_in_expr(cx: &LateContext, id: hir::def_id::DefId, expr: &hir::Expr) -> bool {
    let mut v = UsedVisitor {
        cx: cx,
        id: id,
        used: false,
    };
    hir::intravisit::walk_expr(&mut v, expr);
    v.used
}
<commit_msg>let_if_seq: fix rewrite example<commit_after>use rustc::lint::*;
use rustc::hir;
use syntax::codemap;
use utils::{snippet, span_lint_and_then};

/// **What it does:** Checks for variable declarations immediately followed by a
/// conditional affectation.
///
/// **Why is this bad?** This is not idiomatic Rust.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust,ignore
/// let foo;
///
/// if bar() {
///     foo = 42;
/// } else {
///     foo = 0;
/// }
///
/// let mut baz = None;
///
/// if bar() {
///     baz = Some(42);
/// }
/// ```
///
/// should be written
///
/// ```rust,ignore
/// let foo = if bar() {
///     42
/// } else {
///     0
/// };
///
/// let baz = if bar() {
///     Some(42)
/// } else {
///     None
/// };
/// ```
declare_lint! {
    pub USELESS_LET_IF_SEQ,
    Warn,
    "unidiomatic `let mut` declaration followed by initialization in `if`"
}

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

impl LintPass for LetIfSeq {
    fn get_lints(&self) -> LintArray {
        lint_array!(USELESS_LET_IF_SEQ)
    }
}

impl LateLintPass for LetIfSeq {
    fn check_block(&mut self, cx: &LateContext, block: &hir::Block) {
        let mut it = block.stmts.iter().peekable();
        while let Some(stmt) = it.next() {
            if_let_chain! {[
                let Some(expr) = it.peek(),
                let hir::StmtDecl(ref decl, _) = stmt.node,
                let hir::DeclLocal(ref decl) = decl.node,
                let hir::PatKind::Binding(mode, ref name, None) = decl.pat.node,
                let Some(def) = cx.tcx.def_map.borrow().get(&decl.pat.id),
                let hir::StmtExpr(ref if_, _) = expr.node,
                let hir::ExprIf(ref cond, ref then, ref else_) = if_.node,
                !used_in_expr(cx, def.full_def().def_id(), cond),
                let Some(value) = check_assign(cx, def.full_def().def_id(), then),
                !used_in_expr(cx, def.full_def().def_id(), value),
            ], {
                let span = codemap::mk_sp(stmt.span.lo, if_.span.hi);

                let (default_multi_stmts, default) = if let Some(ref else_) = *else_ {
                    if let hir::ExprBlock(ref else_) = else_.node {
                        if let Some(default) = check_assign(cx, def.full_def().def_id(), else_) {
                            (else_.stmts.len() > 1, default)
                        } else if let Some(ref default) = decl.init {
                            (true, &**default)
                        } else {
                            continue;
                        }
                    } else {
                        continue;
                    }
                } else if let Some(ref default) = decl.init {
                    (false, &**default)
                } else {
                    continue;
                };

                let mutability = match mode {
                    hir::BindByRef(hir::MutMutable) | hir::BindByValue(hir::MutMutable) => "<mut> ",
                    _ => "",
                };

                // FIXME: this should not suggest `mut` if we can detect that the variable is not
                // use mutably after the `if`

                let sug = format!(
                    "let {mut}{name} = if {cond} {{{then} {value} }} else {{{else} {default} }};",
                    mut=mutability,
                    name=name.node,
                    cond=snippet(cx, cond.span, "_"),
                    then=if then.stmts.len() > 1 { " ..;" } else { "" },
                    else=if default_multi_stmts { " ..;" } else { "" },
                    value=snippet(cx, value.span, "<value>"),
                    default=snippet(cx, default.span, "<default>"),
                );
                span_lint_and_then(cx,
                                   USELESS_LET_IF_SEQ,
                                   span,
                                   "`if _ { .. } else { .. }` is an expression",
                                   |db| {
                                       db.span_suggestion(span,
                                                          "it is more idiomatic to write",
                                                          sug);
                                       if !mutability.is_empty() {
                                           db.note("you might not need `mut` at all");
                                       }
                                   });
            }}
        }
    }
}

struct UsedVisitor<'a, 'tcx: 'a> {
    cx: &'a LateContext<'a, 'tcx>,
    id: hir::def_id::DefId,
    used: bool,
}

impl<'a, 'tcx, 'v> hir::intravisit::Visitor<'v> for UsedVisitor<'a, 'tcx> {
    fn visit_expr(&mut self, expr: &'v hir::Expr) {
        if_let_chain! {[
            let hir::ExprPath(None, _) = expr.node,
            let Some(def) = self.cx.tcx.def_map.borrow().get(&expr.id),
            self.id == def.full_def().def_id(),
        ], {
            self.used = true;
            return;
        }}
        hir::intravisit::walk_expr(self, expr);
    }
}

fn check_assign<'e>(cx: &LateContext, decl: hir::def_id::DefId, block: &'e hir::Block) -> Option<&'e hir::Expr> {
    if_let_chain! {[
        block.expr.is_none(),
        let Some(expr) = block.stmts.iter().last(),
        let hir::StmtSemi(ref expr, _) = expr.node,
        let hir::ExprAssign(ref var, ref value) = expr.node,
        let hir::ExprPath(None, _) = var.node,
        let Some(def) = cx.tcx.def_map.borrow().get(&var.id),
        decl == def.full_def().def_id(),
    ], {
        let mut v = UsedVisitor {
            cx: cx,
            id: decl,
            used: false,
        };

        for s in block.stmts.iter().take(block.stmts.len()-1) {
            hir::intravisit::walk_stmt(&mut v, s);

            if v.used {
                return None;
            }
        }

        return Some(value);
    }}

    None
}

fn used_in_expr(cx: &LateContext, id: hir::def_id::DefId, expr: &hir::Expr) -> bool {
    let mut v = UsedVisitor {
        cx: cx,
        id: id,
        used: false,
    };
    hir::intravisit::walk_expr(&mut v, expr);
    v.used
}
<|endoftext|>


<commit_before>use crate::utils::{constants, snippet, snippet_opt, span_help_and_lint, span_lint, span_lint_and_then};
use if_chain::if_chain;
use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Applicability;
use std::char;
use syntax::ast::*;
use syntax::source_map::Span;
use syntax::visit::{walk_expr, FnKind, Visitor};

declare_clippy_lint! {
    /// **What it does:** Checks for structure field patterns bound to wildcards.
    ///
    /// **Why is this bad?** Using `..` instead is shorter and leaves the focus on
    /// the fields that are actually bound.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```ignore
    /// let { a: _, b: ref b, c: _ } = ..
    /// ```
    pub UNNEEDED_FIELD_PATTERN,
    style,
    "struct fields bound to a wildcard instead of using `..`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for function arguments having the similar names
    /// differing by an underscore.
    ///
    /// **Why is this bad?** It affects code readability.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// fn foo(a: i32, _a: i32) {}
    /// ```
    pub DUPLICATE_UNDERSCORE_ARGUMENT,
    style,
    "function arguments having names which only differ by an underscore"
}

declare_clippy_lint! {
    /// **What it does:** Detects closures called in the same expression where they
    /// are defined.
    ///
    /// **Why is this bad?** It is unnecessarily adding to the expression's
    /// complexity.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// (|| 42)()
    /// ```
    pub REDUNDANT_CLOSURE_CALL,
    complexity,
    "throwaway closures called in the expression they are defined"
}

declare_clippy_lint! {
    /// **What it does:** Detects expressions of the form `--x`.
    ///
    /// **Why is this bad?** It can mislead C/C++ programmers to think `x` was
    /// decremented.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// let mut x = 3;
    /// --x;
    /// ```
    pub DOUBLE_NEG,
    style,
    "`--x`, which is a double negation of `x` and not a pre-decrement as in C/C++"
}

declare_clippy_lint! {
    /// **What it does:** Warns on hexadecimal literals with mixed-case letter
    /// digits.
    ///
    /// **Why is this bad?** It looks confusing.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// let y = 0x1a9BAcD;
    /// ```
    pub MIXED_CASE_HEX_LITERALS,
    style,
    "hex literals whose letter digits are not consistently upper- or lowercased"
}

declare_clippy_lint! {
    /// **What it does:** Warns if literal suffixes are not separated by an
    /// underscore.
    ///
    /// **Why is this bad?** It is much less readable.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// let y = 123832i32;
    /// ```
    pub UNSEPARATED_LITERAL_SUFFIX,
    pedantic,
    "literals whose suffix is not separated by an underscore"
}

declare_clippy_lint! {
    /// **What it does:** Warns if an integral constant literal starts with `0`.
    ///
    /// **Why is this bad?** In some languages (including the infamous C language
    /// and most of its
    /// family), this marks an octal constant. In Rust however, this is a decimal
    /// constant. This could
    /// be confusing for both the writer and a reader of the constant.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// In Rust:
    /// ```rust
    /// fn main() {
    ///     let a = 0123;
    ///     println!("{}", a);
    /// }
    /// ```
    ///
    /// prints `123`, while in C:
    ///
    /// ```c
    /// #include <stdio.h>
    ///
    /// int main() {
    ///     int a = 0123;
    ///     printf("%d\n", a);
    /// }
    /// ```
    ///
    /// prints `83` (as `83 == 0o123` while `123 == 0o173`).
    pub ZERO_PREFIXED_LITERAL,
    complexity,
    "integer literals starting with `0`"
}

declare_clippy_lint! {
    /// **What it does:** Warns if a generic shadows a built-in type.
    ///
    /// **Why is this bad?** This gives surprising type errors.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```ignore
    /// impl<u32> Foo<u32> {
    ///     fn impl_func(&self) -> u32 {
    ///         42
    ///     }
    /// }
    /// ```
    pub BUILTIN_TYPE_SHADOW,
    style,
    "shadowing a builtin type"
}

declare_lint_pass!(MiscEarlyLints => [
    UNNEEDED_FIELD_PATTERN,
    DUPLICATE_UNDERSCORE_ARGUMENT,
    REDUNDANT_CLOSURE_CALL,
    DOUBLE_NEG,
    MIXED_CASE_HEX_LITERALS,
    UNSEPARATED_LITERAL_SUFFIX,
    ZERO_PREFIXED_LITERAL,
    BUILTIN_TYPE_SHADOW
]);

// Used to find `return` statements or equivalents e.g., `?`
struct ReturnVisitor {
    found_return: bool,
}

impl ReturnVisitor {
    fn new() -> Self {
        Self { found_return: false }
    }
}

impl<'ast> Visitor<'ast> for ReturnVisitor {
    fn visit_expr(&mut self, ex: &'ast Expr) {
        if let ExprKind::Ret(_) = ex.node {
            self.found_return = true;
        } else if let ExprKind::Try(_) = ex.node {
            self.found_return = true;
        }

        walk_expr(self, ex)
    }
}

impl EarlyLintPass for MiscEarlyLints {
    fn check_generics(&mut self, cx: &EarlyContext<'_>, gen: &Generics) {
        for param in &gen.params {
            if let GenericParamKind::Type { .. } = param.kind {
                let name = param.ident.as_str();
                if constants::BUILTIN_TYPES.contains(&&*name) {
                    span_lint(
                        cx,
                        BUILTIN_TYPE_SHADOW,
                        param.ident.span,
                        &format!("This generic shadows the built-in type `{}`", name),
                    );
                }
            }
        }
    }

    fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat, _: &mut bool) {
        if let PatKind::Struct(ref npat, ref pfields, _) = pat.node {
            let mut wilds = 0;
            let type_name = npat
                .segments
                .last()
                .expect("A path must have at least one segment")
                .ident
                .name;

            for field in pfields {
                if let PatKind::Wild = field.node.pat.node {
                    wilds += 1;
                }
            }
            if !pfields.is_empty() && wilds == pfields.len() {
                span_help_and_lint(
                    cx,
                    UNNEEDED_FIELD_PATTERN,
                    pat.span,
                    "All the struct fields are matched to a wildcard pattern, consider using `..`.",
                    &format!("Try with `{} {{ .. }}` instead", type_name),
                );
                return;
            }
            if wilds > 0 {
                let mut normal = vec![];

                for field in pfields {
                    match field.node.pat.node {
                        PatKind::Wild => {},
                        _ => {
                            if let Ok(n) = cx.sess().source_map().span_to_snippet(field.span) {
                                normal.push(n);
                            }
                        },
                    }
                }
                for field in pfields {
                    if let PatKind::Wild = field.node.pat.node {
                        wilds -= 1;
                        if wilds > 0 {
                            span_lint(
                                cx,
                                UNNEEDED_FIELD_PATTERN,
                                field.span,
                                "You matched a field with a wildcard pattern. Consider using `..` instead",
                            );
                        } else {
                            span_help_and_lint(
                                cx,
                                UNNEEDED_FIELD_PATTERN,
                                field.span,
                                "You matched a field with a wildcard pattern. Consider using `..` \
                                 instead",
                                &format!("Try with `{} {{ {}, .. }}`", type_name, normal[..].join(", ")),
                            );
                        }
                    }
                }
            }
        }
    }

    fn check_fn(&mut self, cx: &EarlyContext<'_>, _: FnKind<'_>, decl: &FnDecl, _: Span, _: NodeId) {
        let mut registered_names: FxHashMap<String, Span> = FxHashMap::default();

        for arg in &decl.inputs {
            if let PatKind::Ident(_, ident, None) = arg.pat.node {
                let arg_name = ident.to_string();

                if arg_name.starts_with('_') {
                    if let Some(correspondence) = registered_names.get(&arg_name[1..]) {
                        span_lint(
                            cx,
                            DUPLICATE_UNDERSCORE_ARGUMENT,
                            *correspondence,
                            &format!(
                                "`{}` already exists, having another argument having almost the same \
                                 name makes code comprehension and documentation more difficult",
                                arg_name[1..].to_owned()
                            ),
                        );;
                    }
                } else {
                    registered_names.insert(arg_name, arg.pat.span);
                }
            }
        }
    }

    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
        if in_external_macro(cx.sess(), expr.span) {
            return;
        }
        match expr.node {
            ExprKind::Call(ref paren, _) => {
                if let ExprKind::Paren(ref closure) = paren.node {
                    if let ExprKind::Closure(_, _, _, ref decl, ref block, _) = closure.node {
                        let mut visitor = ReturnVisitor::new();
                        visitor.visit_expr(block);
                        if !visitor.found_return {
                            span_lint_and_then(
                                cx,
                                REDUNDANT_CLOSURE_CALL,
                                expr.span,
                                "Try not to call a closure in the expression where it is declared.",
                                |db| {
                                    if decl.inputs.is_empty() {
                                        let hint = snippet(cx, block.span, "..").into_owned();
                                        db.span_suggestion(
                                            expr.span,
                                            "Try doing something like: ",
                                            hint,
                                            Applicability::MachineApplicable, // snippet
                                        );
                                    }
                                },
                            );
                        }
                    }
                }
            },
            ExprKind::Unary(UnOp::Neg, ref inner) => {
                if let ExprKind::Unary(UnOp::Neg, _) = inner.node {
                    span_lint(
                        cx,
                        DOUBLE_NEG,
                        expr.span,
                        "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
                    );
                }
            },
            ExprKind::Lit(ref lit) => self.check_lit(cx, lit),
            _ => (),
        }
    }

    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) {
        for w in block.stmts.windows(2) {
            if_chain! {
                if let StmtKind::Local(ref local) = w[0].node;
                if let Option::Some(ref t) = local.init;
                if let ExprKind::Closure(..) = t.node;
                if let PatKind::Ident(_, ident, _) = local.pat.node;
                if let StmtKind::Semi(ref second) = w[1].node;
                if let ExprKind::Assign(_, ref call) = second.node;
                if let ExprKind::Call(ref closure, _) = call.node;
                if let ExprKind::Path(_, ref path) = closure.node;
                then {
                    if ident == path.segments[0].ident {
                        span_lint(
                            cx,
                            REDUNDANT_CLOSURE_CALL,
                            second.span,
                            "Closure called just once immediately after it was declared",
                        );
                    }
                }
            }
        }
    }
}

impl MiscEarlyLints {
    fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
        if_chain! {
            if let LitKind::Int(value, ..) = lit.node;
            if let Some(src) = snippet_opt(cx, lit.span);
            if let Some(firstch) = src.chars().next();
            if char::to_digit(firstch, 10).is_some();
            then {
                let mut prev = '\0';
                for ch in src.chars() {
                    if ch == 'i' || ch == 'u' {
                        if prev != '_' {
                            span_lint(cx, UNSEPARATED_LITERAL_SUFFIX, lit.span,
                                        "integer type suffix should be separated by an underscore");
                        }
                        break;
                    }
                    prev = ch;
                }
                if src.starts_with("0x") {
                    let mut seen = (false, false);
                    for ch in src.chars() {
                        match ch {
                            'a' ..= 'f' => seen.0 = true,
                            'A' ..= 'F' => seen.1 = true,
                            'i' | 'u'   => break,   // start of suffix already
                            _ => ()
                        }
                    }
                    if seen.0 && seen.1 {
                        span_lint(cx, MIXED_CASE_HEX_LITERALS, lit.span,
                                    "inconsistent casing in hexadecimal literal");
                    }
                } else if src.starts_with("0b") || src.starts_with("0o") {
                    /* nothing to do */
                } else if value != 0 && src.starts_with('0') {
                    span_lint_and_then(cx,
                                        ZERO_PREFIXED_LITERAL,
                                        lit.span,
                                        "this is a decimal constant",
                                        |db| {
                        db.span_suggestion(
                            lit.span,
                            "if you mean to use a decimal constant, remove the `0` to remove confusion",
                            src.trim_start_matches(|c| c == '_' || c == '0').to_string(),
                            Applicability::MaybeIncorrect,
                        );
                        db.span_suggestion(
                            lit.span,
                            "if you mean to use an octal constant, use `0o`",
                            format!("0o{}", src.trim_start_matches(|c| c == '_' || c == '0')),
                            Applicability::MaybeIncorrect,
                        );
                    });
                }
            }
        }
        if_chain! {
            if let LitKind::Float(..) = lit.node;
            if let Some(src) = snippet_opt(cx, lit.span);
            if let Some(firstch) = src.chars().next();
            if char::to_digit(firstch, 10).is_some();
            then {
                let mut prev = '\0';
                for ch in src.chars() {
                    if ch == 'f' {
                        if prev != '_' {
                            span_lint(cx, UNSEPARATED_LITERAL_SUFFIX, lit.span,
                                        "float type suffix should be separated by an underscore");
                        }
                        break;
                    }
                    prev = ch;
                }
            }
        }
    }
}
<commit_msg>Auto merge of #4020 - rust-lang:rustup, r=phansch<commit_after>use crate::utils::{constants, snippet, snippet_opt, span_help_and_lint, span_lint, span_lint_and_then};
use if_chain::if_chain;
use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Applicability;
use std::char;
use syntax::ast::*;
use syntax::source_map::Span;
use syntax::visit::{walk_expr, FnKind, Visitor};

declare_clippy_lint! {
    /// **What it does:** Checks for structure field patterns bound to wildcards.
    ///
    /// **Why is this bad?** Using `..` instead is shorter and leaves the focus on
    /// the fields that are actually bound.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```ignore
    /// let { a: _, b: ref b, c: _ } = ..
    /// ```
    pub UNNEEDED_FIELD_PATTERN,
    style,
    "struct fields bound to a wildcard instead of using `..`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for function arguments having the similar names
    /// differing by an underscore.
    ///
    /// **Why is this bad?** It affects code readability.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// fn foo(a: i32, _a: i32) {}
    /// ```
    pub DUPLICATE_UNDERSCORE_ARGUMENT,
    style,
    "function arguments having names which only differ by an underscore"
}

declare_clippy_lint! {
    /// **What it does:** Detects closures called in the same expression where they
    /// are defined.
    ///
    /// **Why is this bad?** It is unnecessarily adding to the expression's
    /// complexity.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// (|| 42)()
    /// ```
    pub REDUNDANT_CLOSURE_CALL,
    complexity,
    "throwaway closures called in the expression they are defined"
}

declare_clippy_lint! {
    /// **What it does:** Detects expressions of the form `--x`.
    ///
    /// **Why is this bad?** It can mislead C/C++ programmers to think `x` was
    /// decremented.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// let mut x = 3;
    /// --x;
    /// ```
    pub DOUBLE_NEG,
    style,
    "`--x`, which is a double negation of `x` and not a pre-decrement as in C/C++"
}

declare_clippy_lint! {
    /// **What it does:** Warns on hexadecimal literals with mixed-case letter
    /// digits.
    ///
    /// **Why is this bad?** It looks confusing.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// let y = 0x1a9BAcD;
    /// ```
    pub MIXED_CASE_HEX_LITERALS,
    style,
    "hex literals whose letter digits are not consistently upper- or lowercased"
}

declare_clippy_lint! {
    /// **What it does:** Warns if literal suffixes are not separated by an
    /// underscore.
    ///
    /// **Why is this bad?** It is much less readable.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// let y = 123832i32;
    /// ```
    pub UNSEPARATED_LITERAL_SUFFIX,
    pedantic,
    "literals whose suffix is not separated by an underscore"
}

declare_clippy_lint! {
    /// **What it does:** Warns if an integral constant literal starts with `0`.
    ///
    /// **Why is this bad?** In some languages (including the infamous C language
    /// and most of its
    /// family), this marks an octal constant. In Rust however, this is a decimal
    /// constant. This could
    /// be confusing for both the writer and a reader of the constant.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// In Rust:
    /// ```rust
    /// fn main() {
    ///     let a = 0123;
    ///     println!("{}", a);
    /// }
    /// ```
    ///
    /// prints `123`, while in C:
    ///
    /// ```c
    /// #include <stdio.h>
    ///
    /// int main() {
    ///     int a = 0123;
    ///     printf("%d\n", a);
    /// }
    /// ```
    ///
    /// prints `83` (as `83 == 0o123` while `123 == 0o173`).
    pub ZERO_PREFIXED_LITERAL,
    complexity,
    "integer literals starting with `0`"
}

declare_clippy_lint! {
    /// **What it does:** Warns if a generic shadows a built-in type.
    ///
    /// **Why is this bad?** This gives surprising type errors.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```ignore
    /// impl<u32> Foo<u32> {
    ///     fn impl_func(&self) -> u32 {
    ///         42
    ///     }
    /// }
    /// ```
    pub BUILTIN_TYPE_SHADOW,
    style,
    "shadowing a builtin type"
}

declare_lint_pass!(MiscEarlyLints => [
    UNNEEDED_FIELD_PATTERN,
    DUPLICATE_UNDERSCORE_ARGUMENT,
    REDUNDANT_CLOSURE_CALL,
    DOUBLE_NEG,
    MIXED_CASE_HEX_LITERALS,
    UNSEPARATED_LITERAL_SUFFIX,
    ZERO_PREFIXED_LITERAL,
    BUILTIN_TYPE_SHADOW
]);

// Used to find `return` statements or equivalents e.g., `?`
struct ReturnVisitor {
    found_return: bool,
}

impl ReturnVisitor {
    fn new() -> Self {
        Self { found_return: false }
    }
}

impl<'ast> Visitor<'ast> for ReturnVisitor {
    fn visit_expr(&mut self, ex: &'ast Expr) {
        if let ExprKind::Ret(_) = ex.node {
            self.found_return = true;
        } else if let ExprKind::Try(_) = ex.node {
            self.found_return = true;
        }

        walk_expr(self, ex)
    }
}

impl EarlyLintPass for MiscEarlyLints {
    fn check_generics(&mut self, cx: &EarlyContext<'_>, gen: &Generics) {
        for param in &gen.params {
            if let GenericParamKind::Type { .. } = param.kind {
                let name = param.ident.as_str();
                if constants::BUILTIN_TYPES.contains(&&*name) {
                    span_lint(
                        cx,
                        BUILTIN_TYPE_SHADOW,
                        param.ident.span,
                        &format!("This generic shadows the built-in type `{}`", name),
                    );
                }
            }
        }
    }

    fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) {
        if let PatKind::Struct(ref npat, ref pfields, _) = pat.node {
            let mut wilds = 0;
            let type_name = npat
                .segments
                .last()
                .expect("A path must have at least one segment")
                .ident
                .name;

            for field in pfields {
                if let PatKind::Wild = field.node.pat.node {
                    wilds += 1;
                }
            }
            if !pfields.is_empty() && wilds == pfields.len() {
                span_help_and_lint(
                    cx,
                    UNNEEDED_FIELD_PATTERN,
                    pat.span,
                    "All the struct fields are matched to a wildcard pattern, consider using `..`.",
                    &format!("Try with `{} {{ .. }}` instead", type_name),
                );
                return;
            }
            if wilds > 0 {
                let mut normal = vec![];

                for field in pfields {
                    match field.node.pat.node {
                        PatKind::Wild => {},
                        _ => {
                            if let Ok(n) = cx.sess().source_map().span_to_snippet(field.span) {
                                normal.push(n);
                            }
                        },
                    }
                }
                for field in pfields {
                    if let PatKind::Wild = field.node.pat.node {
                        wilds -= 1;
                        if wilds > 0 {
                            span_lint(
                                cx,
                                UNNEEDED_FIELD_PATTERN,
                                field.span,
                                "You matched a field with a wildcard pattern. Consider using `..` instead",
                            );
                        } else {
                            span_help_and_lint(
                                cx,
                                UNNEEDED_FIELD_PATTERN,
                                field.span,
                                "You matched a field with a wildcard pattern. Consider using `..` \
                                 instead",
                                &format!("Try with `{} {{ {}, .. }}`", type_name, normal[..].join(", ")),
                            );
                        }
                    }
                }
            }
        }
    }

    fn check_fn(&mut self, cx: &EarlyContext<'_>, _: FnKind<'_>, decl: &FnDecl, _: Span, _: NodeId) {
        let mut registered_names: FxHashMap<String, Span> = FxHashMap::default();

        for arg in &decl.inputs {
            if let PatKind::Ident(_, ident, None) = arg.pat.node {
                let arg_name = ident.to_string();

                if arg_name.starts_with('_') {
                    if let Some(correspondence) = registered_names.get(&arg_name[1..]) {
                        span_lint(
                            cx,
                            DUPLICATE_UNDERSCORE_ARGUMENT,
                            *correspondence,
                            &format!(
                                "`{}` already exists, having another argument having almost the same \
                                 name makes code comprehension and documentation more difficult",
                                arg_name[1..].to_owned()
                            ),
                        );;
                    }
                } else {
                    registered_names.insert(arg_name, arg.pat.span);
                }
            }
        }
    }

    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
        if in_external_macro(cx.sess(), expr.span) {
            return;
        }
        match expr.node {
            ExprKind::Call(ref paren, _) => {
                if let ExprKind::Paren(ref closure) = paren.node {
                    if let ExprKind::Closure(_, _, _, ref decl, ref block, _) = closure.node {
                        let mut visitor = ReturnVisitor::new();
                        visitor.visit_expr(block);
                        if !visitor.found_return {
                            span_lint_and_then(
                                cx,
                                REDUNDANT_CLOSURE_CALL,
                                expr.span,
                                "Try not to call a closure in the expression where it is declared.",
                                |db| {
                                    if decl.inputs.is_empty() {
                                        let hint = snippet(cx, block.span, "..").into_owned();
                                        db.span_suggestion(
                                            expr.span,
                                            "Try doing something like: ",
                                            hint,
                                            Applicability::MachineApplicable, // snippet
                                        );
                                    }
                                },
                            );
                        }
                    }
                }
            },
            ExprKind::Unary(UnOp::Neg, ref inner) => {
                if let ExprKind::Unary(UnOp::Neg, _) = inner.node {
                    span_lint(
                        cx,
                        DOUBLE_NEG,
                        expr.span,
                        "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
                    );
                }
            },
            ExprKind::Lit(ref lit) => self.check_lit(cx, lit),
            _ => (),
        }
    }

    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) {
        for w in block.stmts.windows(2) {
            if_chain! {
                if let StmtKind::Local(ref local) = w[0].node;
                if let Option::Some(ref t) = local.init;
                if let ExprKind::Closure(..) = t.node;
                if let PatKind::Ident(_, ident, _) = local.pat.node;
                if let StmtKind::Semi(ref second) = w[1].node;
                if let ExprKind::Assign(_, ref call) = second.node;
                if let ExprKind::Call(ref closure, _) = call.node;
                if let ExprKind::Path(_, ref path) = closure.node;
                then {
                    if ident == path.segments[0].ident {
                        span_lint(
                            cx,
                            REDUNDANT_CLOSURE_CALL,
                            second.span,
                            "Closure called just once immediately after it was declared",
                        );
                    }
                }
            }
        }
    }
}

impl MiscEarlyLints {
    fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
        if_chain! {
            if let LitKind::Int(value, ..) = lit.node;
            if let Some(src) = snippet_opt(cx, lit.span);
            if let Some(firstch) = src.chars().next();
            if char::to_digit(firstch, 10).is_some();
            then {
                let mut prev = '\0';
                for ch in src.chars() {
                    if ch == 'i' || ch == 'u' {
                        if prev != '_' {
                            span_lint(cx, UNSEPARATED_LITERAL_SUFFIX, lit.span,
                                        "integer type suffix should be separated by an underscore");
                        }
                        break;
                    }
                    prev = ch;
                }
                if src.starts_with("0x") {
                    let mut seen = (false, false);
                    for ch in src.chars() {
                        match ch {
                            'a' ..= 'f' => seen.0 = true,
                            'A' ..= 'F' => seen.1 = true,
                            'i' | 'u'   => break,   // start of suffix already
                            _ => ()
                        }
                    }
                    if seen.0 && seen.1 {
                        span_lint(cx, MIXED_CASE_HEX_LITERALS, lit.span,
                                    "inconsistent casing in hexadecimal literal");
                    }
                } else if src.starts_with("0b") || src.starts_with("0o") {
                    /* nothing to do */
                } else if value != 0 && src.starts_with('0') {
                    span_lint_and_then(cx,
                                        ZERO_PREFIXED_LITERAL,
                                        lit.span,
                                        "this is a decimal constant",
                                        |db| {
                        db.span_suggestion(
                            lit.span,
                            "if you mean to use a decimal constant, remove the `0` to remove confusion",
                            src.trim_start_matches(|c| c == '_' || c == '0').to_string(),
                            Applicability::MaybeIncorrect,
                        );
                        db.span_suggestion(
                            lit.span,
                            "if you mean to use an octal constant, use `0o`",
                            format!("0o{}", src.trim_start_matches(|c| c == '_' || c == '0')),
                            Applicability::MaybeIncorrect,
                        );
                    });
                }
            }
        }
        if_chain! {
            if let LitKind::Float(..) = lit.node;
            if let Some(src) = snippet_opt(cx, lit.span);
            if let Some(firstch) = src.chars().next();
            if char::to_digit(firstch, 10).is_some();
            then {
                let mut prev = '\0';
                for ch in src.chars() {
                    if ch == 'f' {
                        if prev != '_' {
                            span_lint(cx, UNSEPARATED_LITERAL_SUFFIX, lit.span,
                                        "float type suffix should be separated by an underscore");
                        }
                        break;
                    }
                    prev = ch;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#![allow(unused_imports, unused_must_use, unused_variables, dead_code)]

extern crate combine;

use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use std::str;
use combine::{spaces, parser, between, many, many1, digit, char, string, token, Parser, ParserExt, ParseError};
use combine::primitives::{State, Stream, ParseResult};
use combine::combinator::{Between, Token, FnParser};

//my own bencode stuff!
//
pub enum Bencode {
    Number(i64),
    String(Vec<u8>)
}

fn open_file <P: AsRef<Path>>(path: P) -> Vec<u8> {
    let mut fd = File::open(path).unwrap();
    let mut buffer:Vec<u8> = Vec::new();
    fd.read_to_end(&mut buffer);
    buffer
}

enum Expr {
    Integer(i64)
}

fn bencode_integer<I>(input: State<I>) -> ParseResult<i64, I> where I:Stream<Item=char> {
    let (open, close) = (char('i'), char('e'));
    let mut int = between(open, close, many1::<String, _>(digit())).map(|x| {
        x.parse::<i64>().unwrap()
    });
    int.parse_state(input)
}

fn main () {
    let file_contents = open_file("t-test.torrent");

    match str::from_utf8(&file_contents) {
        Ok(v) => println!("file: {}", v),
        Err(e) => panic!("Not a UTF-8 String: {}", e)
    }

    let result = parser(bencode_integer).parse("i5e");

    match result {
        Ok((a, _)) => println!("found {}", a),
        Err(e) => println!("{}", e)
    }
}
<commit_msg>bencode length prefix<commit_after>#![allow(unused_imports, unused_must_use, unused_variables, dead_code)]

extern crate combine;

use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use std::str;
use combine::{spaces, parser, between, many, many1, digit, char, any, string, token, Parser, ParserExt, ParseError};
use combine::primitives::{State, Stream, ParseResult};
use combine::combinator::{Between, Token, FnParser};

//my own bencode stuff!
//
pub enum Bencode {
    Number(i64),
    String(Vec<u8>)
}

fn open_file <P: AsRef<Path>>(path: P) -> Vec<u8> {
    let mut fd = File::open(path).unwrap();
    let mut buffer:Vec<u8> = Vec::new();
    fd.read_to_end(&mut buffer);
    buffer
}

enum Expr {
    Integer(i64)
}

//TODO: this does not handle negatives, yo
fn bencode_integer<I>(input: State<I>) -> ParseResult<i64, I> where I:Stream<Item=char> {
    let (open, close) = (char('i'), char('e'));
    let mut int = between(open, close, many1::<String, _>(digit())).map(|x| {
        x.parse::<i64>().unwrap()
    });
    int.parse_state(input)
}

fn bencode_string<I>(input: State<I>) -> ParseResult<i32, I> where I:Stream<Item=char> {
    bencode_string_length_prefix(input)
}

fn bencode_string_length_prefix<I>(input: State<I>) -> ParseResult<i32, I> where I:Stream<Item=char> {
    let many_digit = many1::<String, _>(digit());
    let mut get_len = (many_digit, char(':')).map(|(length, _)| length.parse::<i32>().unwrap());
    get_len.parse_state(input)
}

fn main () {
    let file_contents = open_file("t-test.torrent");

    match str::from_utf8(&file_contents) {
        Ok(v) => println!("file: {}", v),
        Err(e) => panic!("Not a UTF-8 String: {}", e)
    }

    //let result = parser(bencode_integer).parse("i5e");
    let result = parser(bencode_string).parse("3:sss");

    match result {
        Ok((a, _)) => println!("found {}", a),
        Err(e) => println!("{}", e)
    }
}
<|endoftext|>


<commit_before>use serde_json::{Value, Error};
use std::collections::HashMap;
use crypto::hmac::Hmac;
use crypto::mac::Mac;
use crypto::sha2::Sha256;
use rustc_serialize::hex::ToHex;
use reqwest::header::Headers;

struct Nonce {
    nonce: i64,
}

impl Nonce {
    pub fn new() -> Nonce {
        let sec = time::now().to_timespec().sec;
        let nsec = time::now().to_timespec().nsec;
        Nonce { nonce: sec as i64 * 1_000_000_000 + nsec as i64 }
    }
}

impl Iterator for Nonce {
    type Item = i64;

    fn next(&mut self) -> Option<i64> {
        self.nonce += 1;
        Some(self.nonce)
    }
}

struct Client {
    key: &'static str,
    secret: &'static str,
    public_base: &'static str,
    private_base: &'static str,
    http_client: reqwest::Client,
}

impl Client {
    pub fn new(key: &'static str, secret: &'static str) -> Client {
        Client {
            key: key,
            secret: secret,
            public_base: "https://public.bitbank.cc/",
            private_base: "https://api.bitbank.cc",
            http_client: reqwest::Client::new().unwrap(),
        }
    }

    pub fn get_ticker(&self, pair: &str) -> Result<HashMap<String, Value>, Error> {
        let url = &format!("{}{}/ticker", self.public_base, pair);
        let resp = self.http_client.get(url).send().unwrap();
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    pub fn get_depth(&self, pair: &str) -> Result<HashMap<String, Value>, Error> {
        let url = &format!("{}{}/depth", self.public_base, pair);
        let resp = self.http_client.get(url).send().unwrap();
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    pub fn get_transactions(&self, pair: &str) -> Result<HashMap<String, Value>, Error> {
        let url = &format!("{}{}/transactions", self.public_base, pair);
        let resp = self.http_client.get(url).send().unwrap();
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    pub fn get_transactions_by_date(&self,
                                    pair: &str,
                                    date: &str)
                                    -> Result<HashMap<String, Value>, Error> {
        let url = &format!("{}{}/transactions/{}", self.public_base, pair, date);
        let resp = self.http_client.get(url).send().unwrap();
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    pub fn get_candlestick(&self,
                           pair: &str,
                           candle_type: &str,
                           date: &str)
                           -> Result<HashMap<String, Value>, Error> {
        let url = &format!("{}{}/candlestick/{}/{}",
                self.public_base,
                pair,
                candle_type,
                date);
        let resp = self.http_client.get(url).send().unwrap();
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    pub fn get_assets(&self) -> Result<HashMap<String, Value>, Error> {
        let path = "/v1/user/assets";
        let resp = self.private_get_request(path, "");
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    pub fn get_order(&self, pair: &str, order_id: &str) -> Result<HashMap<String, Value>, Error> {
        let path = "/v1/user/spot/order";
        let query = &format!("?pair={}&order_id={}", pair, order_id);
        let resp = self.private_get_request(path, query);
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    pub fn order(&self,
                 pair: &str,
                 amount: &str,
                 price: &str,
                 order_side: &str,
                 order_type: &str)
                 -> Result<HashMap<String, Value>, Error> {
        let path = "/v1/user/spot/order";
        let mut body = HashMap::new();
        body.insert("pair", pair);
        body.insert("amount", amount);
        body.insert("price", price);
        body.insert("side", order_side);
        body.insert("type", order_type);
        let body = &format!("{:?}", body);

        let resp = self.private_post_request(body, path);
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    pub fn cancel_order(&self,
                        pair: &str,
                        order_id: &str)
                        -> Result<HashMap<String, Value>, Error> {
        let path = "/v1/user/spot/cancel_order";
        let mut body = HashMap::new();
        body.insert("pair", pair);
        body.insert("order_id", order_id);
        let body = &format!("{:?}", body);

        let resp = self.private_post_request(body, path);
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }
    /*
    pub fn cancel_orders(&self,
                         pair: &str,
                         order_ids: Vec<i32>)
                         -> Result<HashMap<String, Value>, Error> {
        let path = "/v1/user/spot/cancel_order";
        let mut body = HashMap::new();
        body.insert("pair", pair);
        //body.insert("order_ids", order_ids);
        let body = &format!("{:?}", body);

        let resp = self.private_post_request(body, path);
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    pub fn get_orders_info(&self,
                           pair: &str,
                           order_ids: Vec<i32>)
                           -> Result<HashMap<String, Value>, Error> {
        let path = "/v1/user/spot/orders_info";
        let mut body = HashMap::new();
        body.insert("pair", pair);
        //body.insert("order_ids", order_ids);
        let body = &format!("{:?}", body);

        let resp = self.private_post_request(body, path);
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }
	*/
    pub fn get_active_orders(&self,
                             pair: &str,
                             count: &str,
                             from_id: &str,
                             end_id: &str,
                             since: &str,
                             end: &str)
                             -> Result<HashMap<String, Value>, Error> {
        let path = "/v1/user/spot/active_orders";
        let query = &format!("?pair={}&count={}&from_id={}&end_id={}&since={}&end={}",
                pair,
                count,
                from_id,
                end_id,
                since,
                end);
        let resp = self.private_get_request(path, query);
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    pub fn get_withdrawal_account(&self, asset: &str) -> Result<HashMap<String, Value>, Error> {
        let path = "/v1/user/withdrawal_account";
        let query = &format!("?asset={}", asset);
        let resp = self.private_get_request(path, query);
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    pub fn request_withdrawal(&self, asset: &str) -> Result<HashMap<String, Value>, Error> {
        let path = "/v1/user/request_withdrawal";
        let mut body = HashMap::new();
        body.insert("asset", asset);
        let body = &format!("{:?}", body);

        let resp = self.private_post_request(body, path);
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    fn private_post_request(&self, body: &str, path: &str) -> reqwest::Response {
        let n = Nonce::new().next().unwrap();
        let message = format!("{}{}", n, body);

        let header = self.create_header(&n.to_string(), &message);

        let url = &format!("{}{}", self.private_base, path);
        let resp = self.http_client.post(url).body(body).headers(header);

        resp.send().unwrap()
    }

    fn private_get_request(&self, path: &str, query: &str) -> reqwest::Response {
        let n = Nonce::new().next().unwrap();
        let message = format!("{}{}{}", n, path, query);
        let header = self.create_header(&n.to_string(), &message);

        let url = &format!("{}{}", self.private_base, path);
        let resp = self.http_client.get(url).headers(header);

        resp.send().unwrap()
    }

    fn create_header(&self, nonce: &str, message: &str) -> Headers {
        let mut header = Headers::new();
        header.set_raw("ACCESS-KEY", vec![self.key.as_bytes().to_vec()]);
        header.set_raw("ACCESS-NONCE", vec![nonce.as_bytes().to_vec()]);
        header.set_raw("ACCESS-SIGNATURE",
                       vec![self.signature(&message).to_string().as_bytes().to_vec()]);

        header
    }

    fn signature(&self, message: &str) -> String {
        let mut mac = Hmac::new(Sha256::new(), self.secret.as_bytes());
        mac.input(message.as_bytes());
        let signature = mac.result().code().to_hex().to_string();

        signature
    }
}
<commit_msg>few change<commit_after>extern crate reqwest;
extern crate serde_json;
extern crate time;
extern crate crypto;
extern crate rustc_serialize;
extern crate url;

use serde_json::{Value, Error};
use std::collections::HashMap;
use crypto::hmac::Hmac;
use crypto::mac::Mac;
use crypto::sha2::Sha256;
use rustc_serialize::hex::ToHex;
use reqwest::header::Headers;

struct Nonce {
    nonce: i64,
}

impl Nonce {
    pub fn new() -> Nonce {
        let sec = time::now().to_timespec().sec;
        let nsec = time::now().to_timespec().nsec;
        Nonce { nonce: sec as i64 * 1_000_000_000 + nsec as i64 }
    }
}

impl Iterator for Nonce {
    type Item = i64;

    fn next(&mut self) -> Option<i64> {
        self.nonce += 1;
        Some(self.nonce)
    }
}

struct Client {
    key: &'static str,
    secret: &'static str,
    public_base: &'static str,
    private_base: &'static str,
    http_client: reqwest::Client,
}

impl Client {
    pub fn new(key: &'static str, secret: &'static str) -> Client {
        Client {
            key: key,
            secret: secret,
            public_base: "https://public.bitbank.cc/",
            private_base: "https://api.bitbank.cc",
            http_client: reqwest::Client::new().unwrap(),
        }
    }

    pub fn get_ticker(&self, pair: &str) -> Result<HashMap<String, Value>, Error> {
        let url = &format!("{}{}/ticker", self.public_base, pair);
        let resp = self.http_client.get(url).send().unwrap();
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    pub fn get_depth(&self, pair: &str) -> Result<HashMap<String, Value>, Error> {
        let url = &format!("{}{}/depth", self.public_base, pair);
        let resp = self.http_client.get(url).send().unwrap();
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    pub fn get_transactions(&self, pair: &str) -> Result<HashMap<String, Value>, Error> {
        let url = &format!("{}{}/transactions", self.public_base, pair);
        let resp = self.http_client.get(url).send().unwrap();
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    pub fn get_transactions_by_date(&self,
                                    pair: &str,
                                    date: &str)
                                    -> Result<HashMap<String, Value>, Error> {
        let url = &format!("{}{}/transactions/{}", self.public_base, pair, date);
        let resp = self.http_client.get(url).send().unwrap();
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    pub fn get_candlestick(&self,
                           pair: &str,
                           candle_type: &str,
                           date: &str)
                           -> Result<HashMap<String, Value>, Error> {
        let url = &format!("{}{}/candlestick/{}/{}",
                self.public_base,
                pair,
                candle_type,
                date);
        let resp = self.http_client.get(url).send().unwrap();
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    pub fn get_assets(&self) -> Result<HashMap<String, Value>, Error> {
        let path = "/v1/user/assets";
        let resp = self.private_get_request(path, "");
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    pub fn get_order(&self, pair: &str, order_id: &str) -> Result<HashMap<String, Value>, Error> {
        let path = "/v1/user/spot/order";
        let query = &format!("?pair={}&order_id={}", pair, order_id);
        let resp = self.private_get_request(path, query);
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    pub fn order(&self,
                 pair: &str,
                 amount: &str,
                 price: &str,
                 order_side: &str,
                 order_type: &str)
                 -> Result<HashMap<String, Value>, Error> {
        let path = "/v1/user/spot/order";
        let mut body = HashMap::new();
        body.insert("pair", pair);
        body.insert("amount", amount);
        body.insert("price", price);
        body.insert("side", order_side);
        body.insert("type", order_type);
        let body = &format!("{:?}", body);

        let resp = self.private_post_request(body, path);
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    pub fn cancel_order(&self,
                        pair: &str,
                        order_id: &str)
                        -> Result<HashMap<String, Value>, Error> {
        let path = "/v1/user/spot/cancel_order";
        let mut body = HashMap::new();
        body.insert("pair", pair);
        body.insert("order_id", order_id);
        let body = &format!("{:?}", body);

        let resp = self.private_post_request(body, path);
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }
    /*
    pub fn cancel_orders(&self,
                         pair: &str,
                         order_ids: Vec<i32>)
                         -> Result<HashMap<String, Value>, Error> {
        let path = "/v1/user/spot/cancel_order";
        let mut body = HashMap::new();
        body.insert("pair", pair);
        //body.insert("order_ids", order_ids);
        let body = &format!("{:?}", body);

        let resp = self.private_post_request(body, path);
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    pub fn get_orders_info(&self,
                           pair: &str,
                           order_ids: Vec<i32>)
                           -> Result<HashMap<String, Value>, Error> {
        let path = "/v1/user/spot/orders_info";
        let mut body = HashMap::new();
        body.insert("pair", pair);
        //body.insert("order_ids", order_ids);
        let body = &format!("{:?}", body);

        let resp = self.private_post_request(body, path);
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }
	*/
    pub fn get_active_orders(&self,
                             pair: &str,
                             count: &str,
                             from_id: &str,
                             end_id: &str,
                             since: &str,
                             end: &str)
                             -> Result<HashMap<String, Value>, Error> {
        let path = "/v1/user/spot/active_orders";
        let query = &format!("?pair={}&count={}&from_id={}&end_id={}&since={}&end={}",
                pair,
                count,
                from_id,
                end_id,
                since,
                end);
        let resp = self.private_get_request(path, query);
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    pub fn get_withdrawal_account(&self, asset: &str) -> Result<HashMap<String, Value>, Error> {
        let path = "/v1/user/withdrawal_account";
        let query = &format!("?asset={}", asset);
        let resp = self.private_get_request(path, query);
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    pub fn request_withdrawal(&self, asset: &str) -> Result<HashMap<String, Value>, Error> {
        let path = "/v1/user/request_withdrawal";
        let mut body = HashMap::new();
        body.insert("asset", asset);
        let body = &format!("{:?}", body);

        let resp = self.private_post_request(body, path);
        let value: HashMap<String, Value> = serde_json::from_reader(resp).unwrap();
        Ok(value)
    }

    fn private_post_request(&self, body: &str, path: &str) -> reqwest::Response {
        let n = Nonce::new().next().unwrap();
        let message = format!("{}{}", n, body);

        let header = self.create_header(&n.to_string(), &message);

        let url = &format!("{}{}", self.private_base, path);
        let resp = self.http_client.post(url).body(body).headers(header);

        resp.send().unwrap()
    }

    fn private_get_request(&self, path: &str, query: &str) -> reqwest::Response {
        let n = Nonce::new().next().unwrap();
        let message = format!("{}{}{}", n, path, query);
        let header = self.create_header(&n.to_string(), &message);

        let url = &format!("{}{}", self.private_base, path);
        let resp = self.http_client.get(url).headers(header);

        resp.send().unwrap()
    }

    fn create_header(&self, nonce: &str, message: &str) -> Headers {
        let mut header = Headers::new();
        header.set_raw("ACCESS-KEY", vec![self.key.as_bytes().to_vec()]);
        header.set_raw("ACCESS-NONCE", vec![nonce.as_bytes().to_vec()]);
        header.set_raw("ACCESS-SIGNATURE",
                       vec![self.signature(&message).to_string().as_bytes().to_vec()]);

        header
    }

    fn signature(&self, message: &str) -> String {
        let mut mac = Hmac::new(Sha256::new(), self.secret.as_bytes());
        mac.input(message.as_bytes());
        let signature = mac.result().code().to_hex().to_string();

        signature
    }
}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   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.
//

//!
//! # Prepare
//!
//! If a pattern needs to be matched against many different things, it can be prepared in order to generate an object that can
//! be used many times without the delay of generating a DFA.
//!
//! ```
//! # use ndfa::*;
//! let match_abcs      = "abc".prepare_to_match();
//! let match_many_abcs = "abc".repeat_forever(1).prepare_to_match();
//!
//! if matches_prepared("abcabc", &match_many_abcs).is_some() { /* ... */ }
//! # assert!(matches_prepared("abc", &match_many_abcs).is_some());
//! ```
//!

use super::countable::*;
use super::symbol_range::*;
use super::state_machine::*;
use super::regular_pattern::*;
use super::symbol_range_dfa::*;
use super::dfa_compiler::*;

///
/// Can be applied to patterns and other objects in order to match them
///
pub trait PrepareToMatch<As> where As: Sized {
    fn prepare_to_match(self) -> As;
}

impl<InputSymbol: Clone+PartialOrd+Countable, OutputSymbol: Ord+Clone> PrepareToMatch<SymbolRangeDfa<InputSymbol, OutputSymbol>>
for Box<StateMachine<SymbolRange<InputSymbol>, OutputSymbol>> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, OutputSymbol> {
        let builder       = SymbolRangeDfaBuilder::new();
        let state_machine = DfaCompiler::build(self, builder);

        state_machine
    }
}

impl<InputSymbol: Clone+PartialOrd+Countable+'static> PrepareToMatch<SymbolRangeDfa<InputSymbol, bool>>
for Pattern<InputSymbol> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, bool> {
        let ndfa = self.to_ndfa(true);

        ndfa.prepare_to_match()
    }
}

impl<'a, InputSymbol: Clone+PartialOrd+Countable+'static> PrepareToMatch<SymbolRangeDfa<InputSymbol, bool>>
for &'a ToPattern<InputSymbol> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, bool> {
        let pattern = self.to_pattern();

        pattern.prepare_to_match()
    }
}

impl<InputSymbol: Clone+PartialOrd+Countable, OutputSymbol> PrepareToMatch<SymbolRangeDfa<InputSymbol, OutputSymbol>> for SymbolRangeDfa<InputSymbol, OutputSymbol> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, OutputSymbol> {
        self
    }
}

impl<'a> PrepareToMatch<SymbolRangeDfa<char, bool>>
for &'a str {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<char, bool> {
        let pattern = self.to_pattern();

        pattern.prepare_to_match()
    }
}
<commit_msg>Hm, test passes if we use two sets of ‘abcs’ here.<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   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.
//

//!
//! # Prepare
//!
//! If a pattern needs to be matched against many different things, it can be prepared in order to generate an object that can
//! be used many times without the delay of generating a DFA.
//!
//! ```
//! # use ndfa::*;
//! let match_abcs      = "abc".prepare_to_match();
//! let match_many_abcs = "abc".repeat_forever(1).prepare_to_match();
//!
//! if matches_prepared("abcabc", &match_many_abcs).is_some() { /* ... */ }
//! # assert!(matches_prepared("abcabc", &match_many_abcs).is_some());
//! ```
//!

use super::countable::*;
use super::symbol_range::*;
use super::state_machine::*;
use super::regular_pattern::*;
use super::symbol_range_dfa::*;
use super::dfa_compiler::*;

///
/// Can be applied to patterns and other objects in order to match them
///
pub trait PrepareToMatch<As> where As: Sized {
    fn prepare_to_match(self) -> As;
}

impl<InputSymbol: Clone+PartialOrd+Countable, OutputSymbol: Ord+Clone> PrepareToMatch<SymbolRangeDfa<InputSymbol, OutputSymbol>>
for Box<StateMachine<SymbolRange<InputSymbol>, OutputSymbol>> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, OutputSymbol> {
        let builder       = SymbolRangeDfaBuilder::new();
        let state_machine = DfaCompiler::build(self, builder);

        state_machine
    }
}

impl<InputSymbol: Clone+PartialOrd+Countable+'static> PrepareToMatch<SymbolRangeDfa<InputSymbol, bool>>
for Pattern<InputSymbol> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, bool> {
        let ndfa = self.to_ndfa(true);

        ndfa.prepare_to_match()
    }
}

impl<'a, InputSymbol: Clone+PartialOrd+Countable+'static> PrepareToMatch<SymbolRangeDfa<InputSymbol, bool>>
for &'a ToPattern<InputSymbol> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, bool> {
        let pattern = self.to_pattern();

        pattern.prepare_to_match()
    }
}

impl<InputSymbol: Clone+PartialOrd+Countable, OutputSymbol> PrepareToMatch<SymbolRangeDfa<InputSymbol, OutputSymbol>> for SymbolRangeDfa<InputSymbol, OutputSymbol> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, OutputSymbol> {
        self
    }
}

impl<'a> PrepareToMatch<SymbolRangeDfa<char, bool>>
for &'a str {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<char, bool> {
        let pattern = self.to_pattern();

        pattern.prepare_to_match()
    }
}
<|endoftext|>


<commit_before>pub use self::parse_mode::ParseMode;
pub use self::chat_action::ChatAction;

mod parse_mode;
mod chat_action;
mod file;

use reqwest::Client;
use serde::de::DeserializeOwned;
use serde_json;
use serde_json::Value;

use bot::chat_action::get_chat_action;
use bot::parse_mode::get_parse_mode;
use error::{Result, check_for_error};
use error::Error::JsonNotFound;
use marker::ReplyMarkup;
use objects::{Update, Message, Contact, InlineKeyboardMarkup, User, UserProfilePhotos, File};

/// A `Bot` which will do all the API calls.
///
/// The `Bot` will be given access to in a `Command` with which you can do all
/// the API interactions in your `Command`s.
#[derive(Debug)]
pub struct Bot {
    pub id: i64,
    pub first_name: String,
    pub last_name: Option<String>,
    pub username: String,
    pub bot_url: String,
    client: Client,
}

impl Bot {
    /// Constructs a new `Bot`.
    pub fn new(bot_url: String) -> Result<Self> {
        debug!("Going to construct a new Bot...");
        let client = Client::new()?;
        let me = Bot::get_me(&client, &bot_url)?;
        let id = me.id;
        let first_name = me.first_name;
        let last_name = me.last_name;
        let username = me.username.expect("Cannot find username of the bot");

        Ok(Bot {
            id: id,
            first_name: first_name,
            last_name: last_name,
            username: username,
            client: client,
            bot_url: bot_url,
        })
    }

    /// API call which gets the information about your bot.
    pub fn get_me(client: &Client, bot_url: &str) -> Result<User> {
        debug!("Calling get_me...");
        let path = ["getMe"];
        let url = ::construct_api_url(bot_url, &path);
        let mut data = client.get(&url)?.send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let user_json = rjson.get("result").ok_or(JsonNotFound)?;
        let user: User = serde_json::from_value(user_json.clone())?;
        Ok(user)
    }

    /// API call which will get called to get the updates for your bot.
    pub fn get_updates(
        &self,
        offset: i32,
        limit: Option<i32>,
        timeout: Option<i32>,
        network_delay: Option<f32>,
    ) -> Result<Option<Vec<Update>>> {
        debug!("Calling get_updates...");
        let limit = limit.unwrap_or(100);
        let timeout = timeout.unwrap_or(0);
        let network_delay = network_delay.unwrap_or(0.0);
        let path = ["getUpdates"];
        let path_url = ::construct_api_url(&self.bot_url, &path);
        let url = format!(
            "{}?offset={}&limit={}&timeout={}&network_delay={}",
            path_url,
            offset,
            limit,
            timeout,
            network_delay
        );
        let mut data = self.client.get(&url)?.send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let updates_json = rjson.get("result");

        if let Some(result) = updates_json {
            let updates: Vec<Update> = serde_json::from_value(result.clone())?;
            Ok(Some(updates))
        } else {
            Ok(None)
        }
    }

    /// API call which will send a message to a chat which your bot participates in.
    pub fn send_message<M: ReplyMarkup>(
        &self,
        chat_id: &i64,
        text: &str,
        parse_mode: Option<&ParseMode>,
        disable_web_page_preview: Option<&bool>,
        disable_notification: Option<&bool>,
        reply_to_message_id: Option<&i64>,
        reply_markup: Option<M>,
    ) -> Result<Message> {
        debug!("Calling send_message...");
        let chat_id: &str = &chat_id.to_string();
        let parse_mode = &get_parse_mode(parse_mode.unwrap_or(&ParseMode::Text));
        let disable_web_page_preview: &str =
            &disable_web_page_preview.unwrap_or(&false).to_string();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let reply_to_message_id: &str = &reply_to_message_id.map(|i| i.to_string()).unwrap_or(
            "None"
                .to_string(),
        );
        let reply_markup = &Box::new(reply_markup)
            .map(|r| serde_json::to_string(&r).unwrap_or("".to_string()))
            .unwrap_or("".to_string());

        let path = ["sendMessage"];
        let params = [
            ("chat_id", chat_id),
            ("text", text),
            ("parse_mode", parse_mode),
            ("disable_web_page_preview", disable_web_page_preview),
            ("disable_notification", disable_notification),
            ("reply_to_message_id", reply_to_message_id),
            ("reply_markup", reply_markup),
        ];
        self.call(&path, &params)
    }

    /// API call which will reply to a message directed to your bot.
    pub fn reply_to_message(&self, update: &Update, text: &str) -> Result<Message> {
        debug!("Calling reply_to_message...");
        let message = update.clone().message.unwrap();
        let message_id = message.message_id;
        let chat_id = message.chat.id;
        self.send_message(
            &chat_id,
            text,
            None,
            None,
            None,
            Some(&message_id),
            ::NO_MARKUP,
        )
    }

    /// API call which will forward a message.
    pub fn forward_message(
        &self,
        update: &Update,
        chat_id: &i64,
        disable_notification: Option<&bool>,
    ) -> Result<Message> {
        debug!("Calling forward_message...");
        let message = update.clone().message.unwrap();
        let chat_id: &str = &chat_id.to_string();
        let from_chat_id: &str = &message.chat.id.to_string();
        let message_id: &str = &message.message_id.to_string();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let path = ["forwardMessage"];
        let params = [
            ("chat_id", chat_id),
            ("from_chat_id", from_chat_id),
            ("disable_notification", disable_notification),
            ("message_id", message_id),
        ];
        self.call(&path, &params)
    }

    /// API call which will show the given chat action to the users.
    pub fn send_chat_action(&self, chat_id: &i64, action: &ChatAction) -> Result<bool> {
        debug!("Calling send_chat_action...");
        let chat_id: &str = &chat_id.to_string();
        let action = &get_chat_action(action);
        let path = ["sendChatAction"];
        let params = [("chat_id", chat_id), ("action", action)];
        self.call(&path, &params)
    }

    /// API call which will send the given contact.
    pub fn send_contact(
        &self,
        chat_id: &i64,
        contact: &Contact,
        disable_notification: Option<&bool>,
        reply_to_message_id: Option<&i64>,
        reply_markup: Option<&InlineKeyboardMarkup>,
    ) -> Result<Message> {
        debug!("Calling send_contact...");
        let chat_id: &str = &chat_id.to_string();
        let phone_number = &contact.phone_number;
        let first_name = &contact.first_name;
        let last_name = &contact.clone().last_name.unwrap();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let reply_to_message_id: &str = &reply_to_message_id.map(|i| i.to_string()).unwrap_or(
            "None"
                .to_string(),
        );
        let reply_markup = &reply_markup
            .and_then(|r| serde_json::to_string(r).ok())
            .unwrap_or("".to_string());
        let path = ["sendContact"];
        let params = [
            ("chat_id", chat_id),
            ("phone_number", phone_number),
            ("first_name", first_name),
            ("last_name", last_name),
            ("disable_notification", disable_notification),
            ("reply_to_message_id", reply_to_message_id),
            ("reply_markup", reply_markup),
        ];
        self.call(&path, &params)
    }

    /// API call which will get a list of profile pictures for a user.
    pub fn get_user_profile_photos(
        &self,
        user_id: &i64,
        offset: Option<&i64>,
        limit: Option<&i64>,
    ) -> Result<UserProfilePhotos> {
        debug!("Calling get_user_profile_photos...");
        let user_id: &str = &user_id.to_string();
        let offset: &str = &offset.map(|i| i.to_string()).unwrap_or("None".to_string());
        let limit: &str = &limit.map(|i| i.to_string()).unwrap_or("None".to_string());
        let path = ["getUserProfilePhotos"];
        let params = [("user_id", user_id), ("offset", offset), ("limit", limit)];
        self.call(&path, &params)
    }

    /// API call which will get basic info about a file and prepare it for donwloading.
    pub fn get_file(&self, file_id: &str) -> Result<File> {
        debug!("Calling get_file...");
        let path = ["getFile"];
        let params = [("file_id", file_id)];
        self.call(&path, &params)
    }

    /// API call which will kick a user from a group, supergroup or a channel. The bot must be
    /// an administrator in the chat for this call to succeed.
    pub fn kick_chat_member(
        &self,
        chat_id: &i64,
        user_id: &i64,
        until_date: Option<i64>,
    ) -> Result<bool> {
        debug!("Calling kick_chat_member...");
        let chat_id: &str = &chat_id.to_string();
        let user_id: &str = &user_id.to_string();
        let until_date: &str = &until_date.map(|i| i.to_string()).unwrap_or(
            "None".to_string(),
        );
        let path = ["kickChatMember"];
        let params = [
            ("chat_id", chat_id),
            ("user_id", user_id),
            ("until_date", until_date),
        ];
        self.call(&path, &params)
    }

    /// API call which will unban previously kicked members in a supergroup or channel. The bot
    /// must be administrator for this to work.
    pub fn unban_chat_member(&self, chat_id: &i64, user_id: &i64) -> Result<bool> {
        debug!("Calling unban_chat_member...");
        let chat_id: &str = &chat_id.to_string();
        let user_id: &str = &user_id.to_string();
        let path = ["unbanChatMember"];
        let params = [("chat_id", chat_id), ("user_id", user_id)];
        self.call(&path, &params)
    }

    /// The actual networking done for making API calls.
    fn call<T: DeserializeOwned>(&self, path: &[&str], params: &[(&str, &str)]) -> Result<T> {
        debug!("Making API call...");
        let url = ::construct_api_url(&self.bot_url, path);
        let mut data = self.client.post(&url)?.form(&params)?.send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let object_json = rjson.get("result").ok_or(JsonNotFound)?;
        let object = serde_json::from_value::<T>(object_json.clone())?;
        Ok(object)
    }
}
<commit_msg>Adding export_chat_invite_link method<commit_after>pub use self::parse_mode::ParseMode;
pub use self::chat_action::ChatAction;

mod parse_mode;
mod chat_action;
mod file;

use reqwest::Client;
use serde::de::DeserializeOwned;
use serde_json;
use serde_json::Value;

use bot::chat_action::get_chat_action;
use bot::parse_mode::get_parse_mode;
use error::{Result, check_for_error};
use error::Error::JsonNotFound;
use marker::ReplyMarkup;
use objects::{Update, Message, Contact, InlineKeyboardMarkup, User, UserProfilePhotos, File};

/// A `Bot` which will do all the API calls.
///
/// The `Bot` will be given access to in a `Command` with which you can do all
/// the API interactions in your `Command`s.
#[derive(Debug)]
pub struct Bot {
    pub id: i64,
    pub first_name: String,
    pub last_name: Option<String>,
    pub username: String,
    pub bot_url: String,
    client: Client,
}

impl Bot {
    /// Constructs a new `Bot`.
    pub fn new(bot_url: String) -> Result<Self> {
        debug!("Going to construct a new Bot...");
        let client = Client::new()?;
        let me = Bot::get_me(&client, &bot_url)?;
        let id = me.id;
        let first_name = me.first_name;
        let last_name = me.last_name;
        let username = me.username.expect("Cannot find username of the bot");

        Ok(Bot {
            id: id,
            first_name: first_name,
            last_name: last_name,
            username: username,
            client: client,
            bot_url: bot_url,
        })
    }

    /// API call which gets the information about your bot.
    pub fn get_me(client: &Client, bot_url: &str) -> Result<User> {
        debug!("Calling get_me...");
        let path = ["getMe"];
        let url = ::construct_api_url(bot_url, &path);
        let mut data = client.get(&url)?.send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let user_json = rjson.get("result").ok_or(JsonNotFound)?;
        let user: User = serde_json::from_value(user_json.clone())?;
        Ok(user)
    }

    /// API call which will get called to get the updates for your bot.
    pub fn get_updates(
        &self,
        offset: i32,
        limit: Option<i32>,
        timeout: Option<i32>,
        network_delay: Option<f32>,
    ) -> Result<Option<Vec<Update>>> {
        debug!("Calling get_updates...");
        let limit = limit.unwrap_or(100);
        let timeout = timeout.unwrap_or(0);
        let network_delay = network_delay.unwrap_or(0.0);
        let path = ["getUpdates"];
        let path_url = ::construct_api_url(&self.bot_url, &path);
        let url = format!(
            "{}?offset={}&limit={}&timeout={}&network_delay={}",
            path_url,
            offset,
            limit,
            timeout,
            network_delay
        );
        let mut data = self.client.get(&url)?.send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let updates_json = rjson.get("result");

        if let Some(result) = updates_json {
            let updates: Vec<Update> = serde_json::from_value(result.clone())?;
            Ok(Some(updates))
        } else {
            Ok(None)
        }
    }

    /// API call which will send a message to a chat which your bot participates in.
    pub fn send_message<M: ReplyMarkup>(
        &self,
        chat_id: &i64,
        text: &str,
        parse_mode: Option<&ParseMode>,
        disable_web_page_preview: Option<&bool>,
        disable_notification: Option<&bool>,
        reply_to_message_id: Option<&i64>,
        reply_markup: Option<M>,
    ) -> Result<Message> {
        debug!("Calling send_message...");
        let chat_id: &str = &chat_id.to_string();
        let parse_mode = &get_parse_mode(parse_mode.unwrap_or(&ParseMode::Text));
        let disable_web_page_preview: &str =
            &disable_web_page_preview.unwrap_or(&false).to_string();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let reply_to_message_id: &str = &reply_to_message_id.map(|i| i.to_string()).unwrap_or(
            "None"
                .to_string(),
        );
        let reply_markup = &Box::new(reply_markup)
            .map(|r| serde_json::to_string(&r).unwrap_or("".to_string()))
            .unwrap_or("".to_string());

        let path = ["sendMessage"];
        let params = [
            ("chat_id", chat_id),
            ("text", text),
            ("parse_mode", parse_mode),
            ("disable_web_page_preview", disable_web_page_preview),
            ("disable_notification", disable_notification),
            ("reply_to_message_id", reply_to_message_id),
            ("reply_markup", reply_markup),
        ];
        self.call(&path, &params)
    }

    /// API call which will reply to a message directed to your bot.
    pub fn reply_to_message(&self, update: &Update, text: &str) -> Result<Message> {
        debug!("Calling reply_to_message...");
        let message = update.clone().message.unwrap();
        let message_id = message.message_id;
        let chat_id = message.chat.id;
        self.send_message(
            &chat_id,
            text,
            None,
            None,
            None,
            Some(&message_id),
            ::NO_MARKUP,
        )
    }

    /// API call which will forward a message.
    pub fn forward_message(
        &self,
        update: &Update,
        chat_id: &i64,
        disable_notification: Option<&bool>,
    ) -> Result<Message> {
        debug!("Calling forward_message...");
        let message = update.clone().message.unwrap();
        let chat_id: &str = &chat_id.to_string();
        let from_chat_id: &str = &message.chat.id.to_string();
        let message_id: &str = &message.message_id.to_string();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let path = ["forwardMessage"];
        let params = [
            ("chat_id", chat_id),
            ("from_chat_id", from_chat_id),
            ("disable_notification", disable_notification),
            ("message_id", message_id),
        ];
        self.call(&path, &params)
    }

    /// API call which will show the given chat action to the users.
    pub fn send_chat_action(&self, chat_id: &i64, action: &ChatAction) -> Result<bool> {
        debug!("Calling send_chat_action...");
        let chat_id: &str = &chat_id.to_string();
        let action = &get_chat_action(action);
        let path = ["sendChatAction"];
        let params = [("chat_id", chat_id), ("action", action)];
        self.call(&path, &params)
    }

    /// API call which will send the given contact.
    pub fn send_contact(
        &self,
        chat_id: &i64,
        contact: &Contact,
        disable_notification: Option<&bool>,
        reply_to_message_id: Option<&i64>,
        reply_markup: Option<&InlineKeyboardMarkup>,
    ) -> Result<Message> {
        debug!("Calling send_contact...");
        let chat_id: &str = &chat_id.to_string();
        let phone_number = &contact.phone_number;
        let first_name = &contact.first_name;
        let last_name = &contact.clone().last_name.unwrap();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let reply_to_message_id: &str = &reply_to_message_id.map(|i| i.to_string()).unwrap_or(
            "None"
                .to_string(),
        );
        let reply_markup = &reply_markup
            .and_then(|r| serde_json::to_string(r).ok())
            .unwrap_or("".to_string());
        let path = ["sendContact"];
        let params = [
            ("chat_id", chat_id),
            ("phone_number", phone_number),
            ("first_name", first_name),
            ("last_name", last_name),
            ("disable_notification", disable_notification),
            ("reply_to_message_id", reply_to_message_id),
            ("reply_markup", reply_markup),
        ];
        self.call(&path, &params)
    }

    /// API call which will get a list of profile pictures for a user.
    pub fn get_user_profile_photos(
        &self,
        user_id: &i64,
        offset: Option<&i64>,
        limit: Option<&i64>,
    ) -> Result<UserProfilePhotos> {
        debug!("Calling get_user_profile_photos...");
        let user_id: &str = &user_id.to_string();
        let offset: &str = &offset.map(|i| i.to_string()).unwrap_or("None".to_string());
        let limit: &str = &limit.map(|i| i.to_string()).unwrap_or("None".to_string());
        let path = ["getUserProfilePhotos"];
        let params = [("user_id", user_id), ("offset", offset), ("limit", limit)];
        self.call(&path, &params)
    }

    /// API call which will get basic info about a file and prepare it for donwloading.
    pub fn get_file(&self, file_id: &str) -> Result<File> {
        debug!("Calling get_file...");
        let path = ["getFile"];
        let params = [("file_id", file_id)];
        self.call(&path, &params)
    }

    /// API call which will kick a user from a group, supergroup or a channel. The bot must be
    /// an administrator in the chat and must have the appropiate rights for this call to succeed.
    pub fn kick_chat_member(
        &self,
        chat_id: &i64,
        user_id: &i64,
        until_date: Option<i64>,
    ) -> Result<bool> {
        debug!("Calling kick_chat_member...");
        let chat_id: &str = &chat_id.to_string();
        let user_id: &str = &user_id.to_string();
        let until_date: &str = &until_date.map(|i| i.to_string()).unwrap_or(
            "None".to_string(),
        );
        let path = ["kickChatMember"];
        let params = [
            ("chat_id", chat_id),
            ("user_id", user_id),
            ("until_date", until_date),
        ];
        self.call(&path, &params)
    }

    /// API call which will unban previously kicked members in a supergroup or channel. The bot
    /// must be an administrator and must have the appropiate rights for this call to succeed.
    pub fn unban_chat_member(&self, chat_id: &i64, user_id: &i64) -> Result<bool> {
        debug!("Calling unban_chat_member...");
        let chat_id: &str = &chat_id.to_string();
        let user_id: &str = &user_id.to_string();
        let path = ["unbanChatMember"];
        let params = [("chat_id", chat_id), ("user_id", user_id)];
        self.call(&path, &params)
    }

    /// API call which will export an invite link to a supergroup or channel. The bot must be an
    /// administrator and must have the the appropiate rights for this call to succeed.
    pub fn export_chat_invite_link(&self, chat_id: &i64) -> Result<String> {
        debug!("Calling export_chat_invite_link...");
        let chat_id: &str = &chat_id.to_string();
        let path = ["exportChatInviteLink"];
        let params = [("chat_id", chat_id)];
        self.call(&path, &params)
    }

    /// The actual networking done for making API calls.
    fn call<T: DeserializeOwned>(&self, path: &[&str], params: &[(&str, &str)]) -> Result<T> {
        debug!("Making API call...");
        let url = ::construct_api_url(&self.bot_url, path);
        let mut data = self.client.post(&url)?.form(&params)?.send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let object_json = rjson.get("result").ok_or(JsonNotFound)?;
        let object = serde_json::from_value::<T>(object_json.clone())?;
        Ok(object)
    }
}
<|endoftext|>