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

//! See docs in build/expr/mod.rs

use build::{BlockAnd, BlockAndExtension, Builder};
use build::expr::category::{Category, RvalueFunc};
use hair::*;
use rustc::ty;
use rustc::mir::*;

use syntax::abi::Abi;

impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
    /// Compile `expr`, storing the result into `destination`, which
    /// is assumed to be uninitialized.
    pub fn into_expr(&mut self,
                     destination: &Place<'tcx>,
                     mut block: BasicBlock,
                     expr: Expr<'tcx>)
                     -> BlockAnd<()>
    {
        debug!("into_expr(destination={:?}, block={:?}, expr={:?})",
               destination, block, expr);

        // since we frequently have to reference `self` from within a
        // closure, where `self` would be shadowed, it's easier to
        // just use the name `this` uniformly
        let this = self;
        let expr_span = expr.span;
        let source_info = this.source_info(expr_span);

        match expr.kind {
            ExprKind::Scope { region_scope, lint_level, value } => {
                let region_scope = (region_scope, source_info);
                this.in_scope(region_scope, lint_level, block,
                              |this| this.into(destination, block, value))
            }
            ExprKind::Block { body: ast_block } => {
                this.ast_block(destination, block, ast_block, source_info)
            }
            ExprKind::Match { discriminant, arms } => {
                this.match_expr(destination, expr_span, block, discriminant, arms)
            }
            ExprKind::NeverToAny { source } => {
                let source = this.hir.mirror(source);
                let is_call = match source.kind {
                    ExprKind::Call { .. } => true,
                    _ => false,
                };

                unpack!(block = this.as_local_rvalue(block, source));

                // This is an optimization. If the expression was a call then we already have an
                // unreachable block. Don't bother to terminate it and create a new one.
                if is_call {
                    block.unit()
                } else {
                    this.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
                    let end_block = this.cfg.start_new_block();
                    end_block.unit()
                }
            }
            ExprKind::If { condition: cond_expr, then: then_expr, otherwise: else_expr } => {
                let operand = unpack!(block = this.as_local_operand(block, cond_expr));

                let mut then_block = this.cfg.start_new_block();
                let mut else_block = this.cfg.start_new_block();
                let term = TerminatorKind::if_(this.hir.tcx(), operand, then_block, else_block);
                this.cfg.terminate(block, source_info, term);

                unpack!(then_block = this.into(destination, then_block, then_expr));
                else_block = if let Some(else_expr) = else_expr {
                    unpack!(this.into(destination, else_block, else_expr))
                } else {
                    // Body of the `if` expression without an `else` clause must return `()`, thus
                    // we implicitly generate a `else {}` if it is not specified.
                    this.cfg.push_assign_unit(else_block, source_info, destination);
                    else_block
                };

                let join_block = this.cfg.start_new_block();
                this.cfg.terminate(then_block, source_info,
                                   TerminatorKind::Goto { target: join_block });
                this.cfg.terminate(else_block, source_info,
                                   TerminatorKind::Goto { target: join_block });

                join_block.unit()
            }
            ExprKind::LogicalOp { op, lhs, rhs } => {
                // And:
                //
                // [block: If(lhs)] -true-> [else_block: If(rhs)] -true-> [true_block]
                //        |                          | (false)
                //        +----------false-----------+------------------> [false_block]
                //
                // Or:
                //
                // [block: If(lhs)] -false-> [else_block: If(rhs)] -true-> [true_block]
                //        |                          | (false)
                //        +----------true------------+-------------------> [false_block]

                let (true_block, false_block, mut else_block, join_block) =
                    (this.cfg.start_new_block(), this.cfg.start_new_block(),
                     this.cfg.start_new_block(), this.cfg.start_new_block());

                let lhs = unpack!(block = this.as_local_operand(block, lhs));
                let blocks = match op {
                    LogicalOp::And => (else_block, false_block),
                    LogicalOp::Or => (true_block, else_block),
                };
                let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1);
                this.cfg.terminate(block, source_info, term);

                let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs));
                let term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block);
                this.cfg.terminate(else_block, source_info, term);

                this.cfg.push_assign_constant(
                    true_block, source_info, destination,
                    Constant {
                        span: expr_span,
                        ty: this.hir.bool_ty(),
                        literal: this.hir.true_literal(),
                    });

                this.cfg.push_assign_constant(
                    false_block, source_info, destination,
                    Constant {
                        span: expr_span,
                        ty: this.hir.bool_ty(),
                        literal: this.hir.false_literal(),
                    });

                this.cfg.terminate(true_block, source_info,
                                   TerminatorKind::Goto { target: join_block });
                this.cfg.terminate(false_block, source_info,
                                   TerminatorKind::Goto { target: join_block });

                join_block.unit()
            }
            ExprKind::Loop { condition: opt_cond_expr, body } => {
                // [block] --> [loop_block] ~~> [loop_block_end] -1-> [exit_block]
                //                  ^                  |
                //                  |                  0
                //                  |                  |
                //                  |                  v
                //           [body_block_end] <~~~ [body_block]
                //
                // If `opt_cond_expr` is `None`, then the graph is somewhat simplified:
                //
                // [block] --> [loop_block / body_block ] ~~> [body_block_end]    [exit_block]
                //                         ^                          |
                //                         |                          |
                //                         +--------------------------+
                //

                let loop_block = this.cfg.start_new_block();
                let exit_block = this.cfg.start_new_block();

                // start the loop
                this.cfg.terminate(block, source_info,
                                   TerminatorKind::Goto { target: loop_block });

                this.in_breakable_scope(
                    Some(loop_block), exit_block, destination.clone(),
                    move |this| {
                        // conduct the test, if necessary
                        let body_block;
                        if let Some(cond_expr) = opt_cond_expr {
                            let loop_block_end;
                            let cond = unpack!(
                                loop_block_end = this.as_local_operand(loop_block, cond_expr));
                            body_block = this.cfg.start_new_block();
                            let term = TerminatorKind::if_(this.hir.tcx(), cond,
                                                           body_block, exit_block);
                            this.cfg.terminate(loop_block_end, source_info, term);

                            // if the test is false, there's no `break` to assign `destination`, so
                            // we have to do it; this overwrites any `break`-assigned value but it's
                            // always `()` anyway
                            this.cfg.push_assign_unit(exit_block, source_info, destination);
                        } else {
                            body_block = loop_block;
                        }

                        // The “return” value of the loop body must always be an unit. We therefore
                        // introduce a unit temporary as the destination for the loop body.
                        let tmp = this.get_unit_temp();
                        // Execute the body, branching back to the test.
                        let body_block_end = unpack!(this.into(&tmp, body_block, body));
                        this.cfg.terminate(body_block_end, source_info,
                                           TerminatorKind::Goto { target: loop_block });
                    }
                );
                exit_block.unit()
            }
            ExprKind::Call { ty, fun, args } => {
                // FIXME(canndrew): This is_never should probably be an is_uninhabited
                let diverges = expr.ty.is_never();
                let intrinsic = match ty.sty {
                    ty::TyFnDef(def_id, _)  => {
                        let f = ty.fn_sig(this.hir.tcx());
                        if f.abi() == Abi::RustIntrinsic ||
                           f.abi() == Abi::PlatformIntrinsic {
                            Some(this.hir.tcx().item_name(def_id))
                        } else {
                            None
                        }
                    }
                    _ => None
                };
                let intrinsic = intrinsic.as_ref().map(|s| &s[..]);
                let fun = unpack!(block = this.as_local_operand(block, fun));
                if intrinsic == Some("move_val_init") {
                    // `move_val_init` has "magic" semantics - the second argument is
                    // always evaluated "directly" into the first one.

                    let mut args = args.into_iter();
                    let ptr = args.next().expect("0 arguments to `move_val_init`");
                    let val = args.next().expect("1 argument to `move_val_init`");
                    assert!(args.next().is_none(), ">2 arguments to `move_val_init`");

                    let ptr = this.hir.mirror(ptr);
                    let ptr_ty = ptr.ty;
                    // Create an *internal* temp for the pointer, so that unsafety
                    // checking won't complain about the raw pointer assignment.
                    let ptr_temp = this.local_decls.push(LocalDecl {
                        mutability: Mutability::Mut,
                        ty: ptr_ty,
                        name: None,
                        source_info,
                        syntactic_scope: source_info.scope,
                        internal: true,
                        is_user_variable: false
                    });
                    let ptr_temp = Place::Local(ptr_temp);
                    let block = unpack!(this.into(&ptr_temp, block, ptr));
                    this.into(&ptr_temp.deref(), block, val)
                } else {
                    let args: Vec<_> =
                        args.into_iter()
                            .map(|arg| unpack!(block = this.as_local_operand(block, arg)))
                            .collect();

                    let success = this.cfg.start_new_block();
                    let cleanup = this.diverge_cleanup();
                    this.cfg.terminate(block, source_info, TerminatorKind::Call {
                        func: fun,
                        args,
                        cleanup: Some(cleanup),
                        destination: if diverges {
                            None
                        } else {
                            Some ((destination.clone(), success))
                        }
                    });
                    success.unit()
                }
            }

            // These cases don't actually need a destination
            ExprKind::Assign { .. } |
            ExprKind::AssignOp { .. } |
            ExprKind::Continue { .. } |
            ExprKind::Break { .. } |
            ExprKind::InlineAsm { .. } |
            ExprKind::Return { .. } => {
                unpack!(block = this.stmt_expr(block, expr));
                this.cfg.push_assign_unit(block, source_info, destination);
                block.unit()
            }

            // these are the cases that are more naturally handled by some other mode
            ExprKind::Unary { .. } |
            ExprKind::Binary { .. } |
            ExprKind::Box { .. } |
            ExprKind::Cast { .. } |
            ExprKind::Use { .. } |
            ExprKind::ReifyFnPointer { .. } |
            ExprKind::ClosureFnPointer { .. } |
            ExprKind::UnsafeFnPointer { .. } |
            ExprKind::Unsize { .. } |
            ExprKind::Repeat { .. } |
            ExprKind::Borrow { .. } |
            ExprKind::VarRef { .. } |
            ExprKind::SelfRef |
            ExprKind::StaticRef { .. } |
            ExprKind::Array { .. } |
            ExprKind::Tuple { .. } |
            ExprKind::Adt { .. } |
            ExprKind::Closure { .. } |
            ExprKind::Index { .. } |
            ExprKind::Deref { .. } |
            ExprKind::Literal { .. } |
            ExprKind::Yield { .. } |
            ExprKind::Field { .. } => {
                debug_assert!(match Category::of(&expr.kind).unwrap() {
                    Category::Rvalue(RvalueFunc::Into) => false,
                    _ => true,
                });

                let rvalue = unpack!(block = this.as_local_rvalue(block, expr));
                this.cfg.push_assign(block, source_info, destination, rvalue);
                block.unit()
            }
        }
    }
}
<commit_msg>Fix comment in ExprKind::LogicalOp<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! See docs in build/expr/mod.rs

use build::{BlockAnd, BlockAndExtension, Builder};
use build::expr::category::{Category, RvalueFunc};
use hair::*;
use rustc::ty;
use rustc::mir::*;

use syntax::abi::Abi;

impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
    /// Compile `expr`, storing the result into `destination`, which
    /// is assumed to be uninitialized.
    pub fn into_expr(&mut self,
                     destination: &Place<'tcx>,
                     mut block: BasicBlock,
                     expr: Expr<'tcx>)
                     -> BlockAnd<()>
    {
        debug!("into_expr(destination={:?}, block={:?}, expr={:?})",
               destination, block, expr);

        // since we frequently have to reference `self` from within a
        // closure, where `self` would be shadowed, it's easier to
        // just use the name `this` uniformly
        let this = self;
        let expr_span = expr.span;
        let source_info = this.source_info(expr_span);

        match expr.kind {
            ExprKind::Scope { region_scope, lint_level, value } => {
                let region_scope = (region_scope, source_info);
                this.in_scope(region_scope, lint_level, block,
                              |this| this.into(destination, block, value))
            }
            ExprKind::Block { body: ast_block } => {
                this.ast_block(destination, block, ast_block, source_info)
            }
            ExprKind::Match { discriminant, arms } => {
                this.match_expr(destination, expr_span, block, discriminant, arms)
            }
            ExprKind::NeverToAny { source } => {
                let source = this.hir.mirror(source);
                let is_call = match source.kind {
                    ExprKind::Call { .. } => true,
                    _ => false,
                };

                unpack!(block = this.as_local_rvalue(block, source));

                // This is an optimization. If the expression was a call then we already have an
                // unreachable block. Don't bother to terminate it and create a new one.
                if is_call {
                    block.unit()
                } else {
                    this.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
                    let end_block = this.cfg.start_new_block();
                    end_block.unit()
                }
            }
            ExprKind::If { condition: cond_expr, then: then_expr, otherwise: else_expr } => {
                let operand = unpack!(block = this.as_local_operand(block, cond_expr));

                let mut then_block = this.cfg.start_new_block();
                let mut else_block = this.cfg.start_new_block();
                let term = TerminatorKind::if_(this.hir.tcx(), operand, then_block, else_block);
                this.cfg.terminate(block, source_info, term);

                unpack!(then_block = this.into(destination, then_block, then_expr));
                else_block = if let Some(else_expr) = else_expr {
                    unpack!(this.into(destination, else_block, else_expr))
                } else {
                    // Body of the `if` expression without an `else` clause must return `()`, thus
                    // we implicitly generate a `else {}` if it is not specified.
                    this.cfg.push_assign_unit(else_block, source_info, destination);
                    else_block
                };

                let join_block = this.cfg.start_new_block();
                this.cfg.terminate(then_block, source_info,
                                   TerminatorKind::Goto { target: join_block });
                this.cfg.terminate(else_block, source_info,
                                   TerminatorKind::Goto { target: join_block });

                join_block.unit()
            }
            ExprKind::LogicalOp { op, lhs, rhs } => {
                // And:
                //
                // [block: If(lhs)] -true-> [else_block: If(rhs)] -true-> [true_block]
                //        |                          | (false)
                //        +----------false-----------+------------------> [false_block]
                //
                // Or:
                //
                // [block: If(lhs)] -false-> [else_block: If(rhs)] -true-> [true_block]
                //        | (true)                   | (false)
                //  [true_block]               [false_block]

                let (true_block, false_block, mut else_block, join_block) =
                    (this.cfg.start_new_block(), this.cfg.start_new_block(),
                     this.cfg.start_new_block(), this.cfg.start_new_block());

                let lhs = unpack!(block = this.as_local_operand(block, lhs));
                let blocks = match op {
                    LogicalOp::And => (else_block, false_block),
                    LogicalOp::Or => (true_block, else_block),
                };
                let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1);
                this.cfg.terminate(block, source_info, term);

                let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs));
                let term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block);
                this.cfg.terminate(else_block, source_info, term);

                this.cfg.push_assign_constant(
                    true_block, source_info, destination,
                    Constant {
                        span: expr_span,
                        ty: this.hir.bool_ty(),
                        literal: this.hir.true_literal(),
                    });

                this.cfg.push_assign_constant(
                    false_block, source_info, destination,
                    Constant {
                        span: expr_span,
                        ty: this.hir.bool_ty(),
                        literal: this.hir.false_literal(),
                    });

                this.cfg.terminate(true_block, source_info,
                                   TerminatorKind::Goto { target: join_block });
                this.cfg.terminate(false_block, source_info,
                                   TerminatorKind::Goto { target: join_block });

                join_block.unit()
            }
            ExprKind::Loop { condition: opt_cond_expr, body } => {
                // [block] --> [loop_block] ~~> [loop_block_end] -1-> [exit_block]
                //                  ^                  |
                //                  |                  0
                //                  |                  |
                //                  |                  v
                //           [body_block_end] <~~~ [body_block]
                //
                // If `opt_cond_expr` is `None`, then the graph is somewhat simplified:
                //
                // [block] --> [loop_block / body_block ] ~~> [body_block_end]    [exit_block]
                //                         ^                          |
                //                         |                          |
                //                         +--------------------------+
                //

                let loop_block = this.cfg.start_new_block();
                let exit_block = this.cfg.start_new_block();

                // start the loop
                this.cfg.terminate(block, source_info,
                                   TerminatorKind::Goto { target: loop_block });

                this.in_breakable_scope(
                    Some(loop_block), exit_block, destination.clone(),
                    move |this| {
                        // conduct the test, if necessary
                        let body_block;
                        if let Some(cond_expr) = opt_cond_expr {
                            let loop_block_end;
                            let cond = unpack!(
                                loop_block_end = this.as_local_operand(loop_block, cond_expr));
                            body_block = this.cfg.start_new_block();
                            let term = TerminatorKind::if_(this.hir.tcx(), cond,
                                                           body_block, exit_block);
                            this.cfg.terminate(loop_block_end, source_info, term);

                            // if the test is false, there's no `break` to assign `destination`, so
                            // we have to do it; this overwrites any `break`-assigned value but it's
                            // always `()` anyway
                            this.cfg.push_assign_unit(exit_block, source_info, destination);
                        } else {
                            body_block = loop_block;
                        }

                        // The “return” value of the loop body must always be an unit. We therefore
                        // introduce a unit temporary as the destination for the loop body.
                        let tmp = this.get_unit_temp();
                        // Execute the body, branching back to the test.
                        let body_block_end = unpack!(this.into(&tmp, body_block, body));
                        this.cfg.terminate(body_block_end, source_info,
                                           TerminatorKind::Goto { target: loop_block });
                    }
                );
                exit_block.unit()
            }
            ExprKind::Call { ty, fun, args } => {
                // FIXME(canndrew): This is_never should probably be an is_uninhabited
                let diverges = expr.ty.is_never();
                let intrinsic = match ty.sty {
                    ty::TyFnDef(def_id, _)  => {
                        let f = ty.fn_sig(this.hir.tcx());
                        if f.abi() == Abi::RustIntrinsic ||
                           f.abi() == Abi::PlatformIntrinsic {
                            Some(this.hir.tcx().item_name(def_id))
                        } else {
                            None
                        }
                    }
                    _ => None
                };
                let intrinsic = intrinsic.as_ref().map(|s| &s[..]);
                let fun = unpack!(block = this.as_local_operand(block, fun));
                if intrinsic == Some("move_val_init") {
                    // `move_val_init` has "magic" semantics - the second argument is
                    // always evaluated "directly" into the first one.

                    let mut args = args.into_iter();
                    let ptr = args.next().expect("0 arguments to `move_val_init`");
                    let val = args.next().expect("1 argument to `move_val_init`");
                    assert!(args.next().is_none(), ">2 arguments to `move_val_init`");

                    let ptr = this.hir.mirror(ptr);
                    let ptr_ty = ptr.ty;
                    // Create an *internal* temp for the pointer, so that unsafety
                    // checking won't complain about the raw pointer assignment.
                    let ptr_temp = this.local_decls.push(LocalDecl {
                        mutability: Mutability::Mut,
                        ty: ptr_ty,
                        name: None,
                        source_info,
                        syntactic_scope: source_info.scope,
                        internal: true,
                        is_user_variable: false
                    });
                    let ptr_temp = Place::Local(ptr_temp);
                    let block = unpack!(this.into(&ptr_temp, block, ptr));
                    this.into(&ptr_temp.deref(), block, val)
                } else {
                    let args: Vec<_> =
                        args.into_iter()
                            .map(|arg| unpack!(block = this.as_local_operand(block, arg)))
                            .collect();

                    let success = this.cfg.start_new_block();
                    let cleanup = this.diverge_cleanup();
                    this.cfg.terminate(block, source_info, TerminatorKind::Call {
                        func: fun,
                        args,
                        cleanup: Some(cleanup),
                        destination: if diverges {
                            None
                        } else {
                            Some ((destination.clone(), success))
                        }
                    });
                    success.unit()
                }
            }

            // These cases don't actually need a destination
            ExprKind::Assign { .. } |
            ExprKind::AssignOp { .. } |
            ExprKind::Continue { .. } |
            ExprKind::Break { .. } |
            ExprKind::InlineAsm { .. } |
            ExprKind::Return { .. } => {
                unpack!(block = this.stmt_expr(block, expr));
                this.cfg.push_assign_unit(block, source_info, destination);
                block.unit()
            }

            // these are the cases that are more naturally handled by some other mode
            ExprKind::Unary { .. } |
            ExprKind::Binary { .. } |
            ExprKind::Box { .. } |
            ExprKind::Cast { .. } |
            ExprKind::Use { .. } |
            ExprKind::ReifyFnPointer { .. } |
            ExprKind::ClosureFnPointer { .. } |
            ExprKind::UnsafeFnPointer { .. } |
            ExprKind::Unsize { .. } |
            ExprKind::Repeat { .. } |
            ExprKind::Borrow { .. } |
            ExprKind::VarRef { .. } |
            ExprKind::SelfRef |
            ExprKind::StaticRef { .. } |
            ExprKind::Array { .. } |
            ExprKind::Tuple { .. } |
            ExprKind::Adt { .. } |
            ExprKind::Closure { .. } |
            ExprKind::Index { .. } |
            ExprKind::Deref { .. } |
            ExprKind::Literal { .. } |
            ExprKind::Yield { .. } |
            ExprKind::Field { .. } => {
                debug_assert!(match Category::of(&expr.kind).unwrap() {
                    Category::Rvalue(RvalueFunc::Into) => false,
                    _ => true,
                });

                let rvalue = unpack!(block = this.as_local_rvalue(block, expr));
                this.cfg.push_assign(block, source_info, destination, rvalue);
                block.unit()
            }
        }
    }
}
<|endoftext|>


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

#![allow(non_snake_case)]

// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {

E0154: r##"
Imports (`use` statements) are not allowed after non-item statements, such as
variable declarations and expression statements.

Here is an example that demonstrates the error:

```
fn f() {
    // Variable declaration before import
    let x = 0;
    use std::io::Read;
    ...
}
```

The solution is to declare the imports at the top of the block, function, or
file.

Here is the previous example again, with the correct order:

```
fn f() {
    use std::io::Read;
    let x = 0;
    ...
}
```

See the Declaration Statements section of the reference for more information
about what constitutes an Item declaration and what does not:

http://doc.rust-lang.org/reference.html#statements
"##,

E0251: r##"
Two items of the same name cannot be imported without rebinding one of the
items under a new local name.

An example of this error:

```
use foo::baz;
use bar::*; // error, do `use foo::baz as quux` instead on the previous line

fn main() {}

mod foo {
    pub struct baz;
}

mod bar {
    pub mod baz {}
}
```
"##,

E0252: r##"
Two items of the same name cannot be imported without rebinding one of the
items under a new local name.

An example of this error:

```
use foo::baz;
use bar::baz; // error, do `use bar::baz as quux` instead

fn main() {}

mod foo {
    pub struct baz;
}

mod bar {
    pub mod baz {}
}
```
"##,

E0255: r##"
You can't import a value whose name is the same as another value defined in the
module.

An example of this error:

```
use bar::foo; // error, do `use bar::foo as baz` instead

fn foo() {}

mod bar {
     pub fn foo() {}
}

fn main() {}
```
"##,

E0256: r##"
You can't import a type or module when the name of the item being imported is
the same as another type or submodule defined in the module.

An example of this error:

```
use foo::Bar; // error

type Bar = u32;

mod foo {
    pub mod Bar { }
}

fn main() {}
```
"##,

E0259: r##"
The name chosen for an external crate conflicts with another external crate that
has been imported into the current module.

Wrong example:

```
extern crate a;
extern crate crate_a as a;
```

The solution is to choose a different name that doesn't conflict with any
external crate imported into the current module.

Correct example:

```
extern crate a;
extern crate crate_a as other_name;
```
"##,

E0260: r##"
The name for an item declaration conflicts with an external crate's name.

For instance,

```
extern crate abc;

struct abc;
```

There are two possible solutions:

Solution #1: Rename the item.

```
extern crate abc;

struct xyz;
```

Solution #2: Import the crate with a different name.

```
extern crate abc as xyz;

struct abc;
```

See the Declaration Statements section of the reference for more information
about what constitutes an Item declaration and what does not:

http://doc.rust-lang.org/reference.html#statements
"##,

E0317: r##"
User-defined types or type parameters cannot shadow the primitive types.
This error indicates you tried to define a type, struct or enum with the same
name as an existing primitive type.

See the Types section of the reference for more information about the primitive
types:

http://doc.rust-lang.org/reference.html#types
"##,

E0364: r##"
Private items cannot be publicly re-exported.  This error indicates that
you attempted to `pub use` a type or value that was not itself public.

Here is an example that demonstrates the error:

```
mod foo {
    const X: u32 = 1;
}
pub use foo::X;
```

The solution to this problem is to ensure that the items that you are
re-exporting are themselves marked with `pub`:

```
mod foo {
    pub const X: u32 = 1;
}
pub use foo::X;
```

See the 'Use Declarations' section of the reference for more information
on this topic:

http://doc.rust-lang.org/reference.html#use-declarations
"##,

E0365: r##"
Private modules cannot be publicly re-exported.  This error indicates
that you attempted to `pub use` a module that was not itself public.

Here is an example that demonstrates the error:

```
mod foo {
    pub const X: u32 = 1;
}
pub use foo as foo2;

```
The solution to this problem is to ensure that the module that you are
re-exporting is itself marked with `pub`:

```
pub mod foo {
    pub const X: u32 = 1;
}
pub use foo as foo2;
```

See the 'Use Declarations' section of the reference for more information
on this topic:

http://doc.rust-lang.org/reference.html#use-declarations
"##

}

register_diagnostics! {
    E0153, // called no where
    E0157, // called from no where
    E0253, // not directly importable
    E0254, // import conflicts with imported crate in this module
    E0257,
    E0258,
    E0401, // can't use type parameters from outer function
    E0402, // cannot use an outer type parameter in this context
    E0403, // the name `{}` is already used
    E0404, // is not a trait
    E0405, // use of undeclared trait name
    E0406, // undeclared associated type
    E0407, // method is not a member of trait
    E0408, // variable from pattern #1 is not bound in pattern #
    E0409, // variable is bound with different mode in pattern # than in
           // pattern #1
    E0410, // variable from pattern is not bound in pattern 1
    E0411, // use of `Self` outside of an impl or trait
    E0412, // use of undeclared
    E0413, // declaration of shadows an enum variant or unit-like struct in
           // scope
    E0414, // only irrefutable patterns allowed here
    E0415, // identifier is bound more than once in this parameter list
    E0416, // identifier is bound more than once in the same pattern
    E0417, // static variables cannot be referenced in a pattern, use a
           // `const` instead
    E0418, // is not an enum variant, struct or const
    E0419, // unresolved enum variant, struct or const
    E0420, // is not an associated const
    E0421, // unresolved associated const
    E0422, // does not name a structure
    E0423, // is a struct variant name, but this expression uses it like a
           // function name
    E0424, // `self` is not available in a static method.
    E0425, // unresolved name
    E0426, // use of undeclared label
    E0427, // cannot use `ref` binding mode with ...
    E0428, // duplicate definition of ...
    E0429, // `self` imports are only allowed within a { } list
    E0430, // `self` import can only appear once in the list
    E0431, // `self` import can only appear in an import list with a non-empty
           // prefix
    E0432, // unresolved import
    E0433, // failed to resolve
    E0434, // can't capture dynamic environment in a fn item
    E0435  // attempt to use a non-constant value in a constant
}
<commit_msg>Add diagnostics for E0253<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_snake_case)]

// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {

E0154: r##"
Imports (`use` statements) are not allowed after non-item statements, such as
variable declarations and expression statements.

Here is an example that demonstrates the error:

```
fn f() {
    // Variable declaration before import
    let x = 0;
    use std::io::Read;
    ...
}
```

The solution is to declare the imports at the top of the block, function, or
file.

Here is the previous example again, with the correct order:

```
fn f() {
    use std::io::Read;
    let x = 0;
    ...
}
```

See the Declaration Statements section of the reference for more information
about what constitutes an Item declaration and what does not:

http://doc.rust-lang.org/reference.html#statements
"##,

E0251: r##"
Two items of the same name cannot be imported without rebinding one of the
items under a new local name.

An example of this error:

```
use foo::baz;
use bar::*; // error, do `use foo::baz as quux` instead on the previous line

fn main() {}

mod foo {
    pub struct baz;
}

mod bar {
    pub mod baz {}
}
```
"##,

E0252: r##"
Two items of the same name cannot be imported without rebinding one of the
items under a new local name.

An example of this error:

```
use foo::baz;
use bar::baz; // error, do `use bar::baz as quux` instead

fn main() {}

mod foo {
    pub struct baz;
}

mod bar {
    pub mod baz {}
}
```
"##,

E0253: r##"
Attempt was made to import an unimportable value.  This can happen when
trying to import a function from a trait.  An example of this error:

```
mod foo {
    pub trait MyTrait {
        fn doSomething();
    }
}
use foo::MyTrait::doSomething;
```

In general, it's not legal to directly import functions from a crate or
concrete type.
"##,

E0255: r##"
You can't import a value whose name is the same as another value defined in the
module.

An example of this error:

```
use bar::foo; // error, do `use bar::foo as baz` instead

fn foo() {}

mod bar {
     pub fn foo() {}
}

fn main() {}
```
"##,

E0256: r##"
You can't import a type or module when the name of the item being imported is
the same as another type or submodule defined in the module.

An example of this error:

```
use foo::Bar; // error

type Bar = u32;

mod foo {
    pub mod Bar { }
}

fn main() {}
```
"##,

E0259: r##"
The name chosen for an external crate conflicts with another external crate that
has been imported into the current module.

Wrong example:

```
extern crate a;
extern crate crate_a as a;
```

The solution is to choose a different name that doesn't conflict with any
external crate imported into the current module.

Correct example:

```
extern crate a;
extern crate crate_a as other_name;
```
"##,

E0260: r##"
The name for an item declaration conflicts with an external crate's name.

For instance,

```
extern crate abc;

struct abc;
```

There are two possible solutions:

Solution #1: Rename the item.

```
extern crate abc;

struct xyz;
```

Solution #2: Import the crate with a different name.

```
extern crate abc as xyz;

struct abc;
```

See the Declaration Statements section of the reference for more information
about what constitutes an Item declaration and what does not:

http://doc.rust-lang.org/reference.html#statements
"##,

E0317: r##"
User-defined types or type parameters cannot shadow the primitive types.
This error indicates you tried to define a type, struct or enum with the same
name as an existing primitive type.

See the Types section of the reference for more information about the primitive
types:

http://doc.rust-lang.org/reference.html#types
"##,

E0364: r##"
Private items cannot be publicly re-exported.  This error indicates that
you attempted to `pub use` a type or value that was not itself public.

Here is an example that demonstrates the error:

```
mod foo {
    const X: u32 = 1;
}
pub use foo::X;
```

The solution to this problem is to ensure that the items that you are
re-exporting are themselves marked with `pub`:

```
mod foo {
    pub const X: u32 = 1;
}
pub use foo::X;
```

See the 'Use Declarations' section of the reference for more information
on this topic:

http://doc.rust-lang.org/reference.html#use-declarations
"##,

E0365: r##"
Private modules cannot be publicly re-exported.  This error indicates
that you attempted to `pub use` a module that was not itself public.

Here is an example that demonstrates the error:

```
mod foo {
    pub const X: u32 = 1;
}
pub use foo as foo2;

```
The solution to this problem is to ensure that the module that you are
re-exporting is itself marked with `pub`:

```
pub mod foo {
    pub const X: u32 = 1;
}
pub use foo as foo2;
```

See the 'Use Declarations' section of the reference for more information
on this topic:

http://doc.rust-lang.org/reference.html#use-declarations
"##

}

register_diagnostics! {
    E0153, // called no where
    E0157, // called from no where
    E0254, // import conflicts with imported crate in this module
    E0257,
    E0258,
    E0401, // can't use type parameters from outer function
    E0402, // cannot use an outer type parameter in this context
    E0403, // the name `{}` is already used
    E0404, // is not a trait
    E0405, // use of undeclared trait name
    E0406, // undeclared associated type
    E0407, // method is not a member of trait
    E0408, // variable from pattern #1 is not bound in pattern #
    E0409, // variable is bound with different mode in pattern # than in
           // pattern #1
    E0410, // variable from pattern is not bound in pattern 1
    E0411, // use of `Self` outside of an impl or trait
    E0412, // use of undeclared
    E0413, // declaration of shadows an enum variant or unit-like struct in
           // scope
    E0414, // only irrefutable patterns allowed here
    E0415, // identifier is bound more than once in this parameter list
    E0416, // identifier is bound more than once in the same pattern
    E0417, // static variables cannot be referenced in a pattern, use a
           // `const` instead
    E0418, // is not an enum variant, struct or const
    E0419, // unresolved enum variant, struct or const
    E0420, // is not an associated const
    E0421, // unresolved associated const
    E0422, // does not name a structure
    E0423, // is a struct variant name, but this expression uses it like a
           // function name
    E0424, // `self` is not available in a static method.
    E0425, // unresolved name
    E0426, // use of undeclared label
    E0427, // cannot use `ref` binding mode with ...
    E0428, // duplicate definition of ...
    E0429, // `self` imports are only allowed within a { } list
    E0430, // `self` import can only appear once in the list
    E0431, // `self` import can only appear in an import list with a non-empty
           // prefix
    E0432, // unresolved import
    E0433, // failed to resolve
    E0434, // can't capture dynamic environment in a fn item
    E0435  // attempt to use a non-constant value in a constant
}
<|endoftext|>


<commit_before>use clap::crate_version;

use std::env;
use std::path::{Path, PathBuf};

use clap::{App, AppSettings, ArgMatches, SubCommand};

use mdbook::errors::Result as Result3;
use mdbook::MDBook;

fn main() {
    let d_message = "-d, --dest-dir=[dest-dir]
'The output directory for your book{n}(Defaults to ./book when omitted)'";
    let dir_message = "[dir]
'A directory for your book{n}(Defaults to Current Directory when omitted)'";

    let matches = App::new("rustbook")
        .about("Build a book with mdBook")
        .author("Steve Klabnik <steve@steveklabnik.com>")
        .version(&*format!("v{}", crate_version!()))
        .setting(AppSettings::SubcommandRequired)
        .subcommand(
            SubCommand::with_name("build")
                .about("Build the book from the markdown files")
                .arg_from_usage(d_message)
                .arg_from_usage(dir_message),
        )
        .subcommand(
            SubCommand::with_name("linkcheck")
                .about("Run linkcheck with mdBook 3")
                .arg_from_usage(dir_message),
        )
        .get_matches();

    // Check which subcomamnd the user ran...
    match matches.subcommand() {
        ("build", Some(sub_matches)) => {
            if let Err(e) = build(sub_matches) {
                eprintln!("Error: {}", e);

                for cause in e.iter().skip(1) {
                    eprintln!("\tCaused By: {}", cause);
                }

                ::std::process::exit(101);
            }
        }
        ("linkcheck", Some(sub_matches)) => {
            #[cfg(feature = "linkcheck")]
            {
                let (diags, files) = linkcheck(sub_matches).expect("Error while linkchecking.");
                if !diags.is_empty() {
                    let color = codespan_reporting::term::termcolor::ColorChoice::Auto;
                    let mut writer =
                        codespan_reporting::term::termcolor::StandardStream::stderr(color);
                    let cfg = codespan_reporting::term::Config::default();

                    for diag in diags {
                        codespan_reporting::term::emit(&mut writer, &cfg, &files, &diag)
                            .expect("Unable to emit linkcheck error.");
                    }

                    std::process::exit(101);
                }
            }

            #[cfg(not(feature = "linkcheck"))]
            {
                // This avoids the `unused_binding` lint.
                println!(
                    "mdbook-linkcheck is disabled, but arguments were passed: {:?}",
                    sub_matches
                );
            }
        }
        (_, _) => unreachable!(),
    };
}

#[cfg(feature = "linkcheck")]
pub fn linkcheck(
    args: &ArgMatches<'_>,
) -> Result<(Vec<codespan_reporting::diagnostic::Diagnostic>, codespan::Files), failure::Error> {
    use mdbook_linkcheck::Reason;

    let book_dir = get_book_dir(args);
    let src_dir = book_dir.join("src");
    let book = MDBook::load(&book_dir).unwrap();
    let linkck_cfg = mdbook_linkcheck::get_config(&book.config)?;
    let mut files = codespan::Files::new();
    let target_files = mdbook_linkcheck::load_files_into_memory(&book.book, &mut files);
    let cache = mdbook_linkcheck::Cache::default();

    let (links, incomplete) = mdbook_linkcheck::extract_links(target_files, &files);

    let outcome =
        mdbook_linkcheck::validate(&links, &linkck_cfg, &src_dir, &cache, &files, incomplete)?;

    let mut is_real_error = false;

    for link in outcome.invalid_links.iter() {
        match &link.reason {
            Reason::FileNotFound | Reason::TraversesParentDirectories => {
                is_real_error = true;
            }
            Reason::UnsuccessfulServerResponse(status) => {
                if status.is_client_error() {
                    is_real_error = true;
                } else {
                    eprintln!("Unsuccessful server response for link `{}`", link.link.uri);
                }
            }
            Reason::Client(err) => {
                if err.is_timeout() {
                    eprintln!("Timeout for link `{}`", link.link.uri);
                } else if err.is_server_error() {
                    eprintln!("Server error for link `{}`", link.link.uri);
                } else {
                    is_real_error = true;
                }
            }
        }
    }

    if is_real_error {
        Ok((outcome.generate_diagnostics(&files, linkck_cfg.warning_policy), files))
    } else {
        Ok((vec![], files))
    }
}

// Build command implementation
pub fn build(args: &ArgMatches<'_>) -> Result3<()> {
    let book_dir = get_book_dir(args);
    let mut book = MDBook::load(&book_dir)?;

    // Set this to allow us to catch bugs in advance.
    book.config.build.create_missing = false;

    if let Some(dest_dir) = args.value_of("dest-dir") {
        book.config.build.build_dir = PathBuf::from(dest_dir);
    }

    book.build()?;

    Ok(())
}

fn get_book_dir(args: &ArgMatches<'_>) -> PathBuf {
    if let Some(dir) = args.value_of("dir") {
        // Check if path is relative from current dir, or absolute...
        let p = Path::new(dir);
        if p.is_relative() { env::current_dir().unwrap().join(dir) } else { p.to_path_buf() }
    } else {
        env::current_dir().unwrap()
    }
}
<commit_msg>don't error on network failures<commit_after>use clap::crate_version;

use std::env;
use std::path::{Path, PathBuf};

use clap::{App, AppSettings, ArgMatches, SubCommand};

use mdbook::errors::Result as Result3;
use mdbook::MDBook;

fn main() {
    let d_message = "-d, --dest-dir=[dest-dir]
'The output directory for your book{n}(Defaults to ./book when omitted)'";
    let dir_message = "[dir]
'A directory for your book{n}(Defaults to Current Directory when omitted)'";

    let matches = App::new("rustbook")
        .about("Build a book with mdBook")
        .author("Steve Klabnik <steve@steveklabnik.com>")
        .version(&*format!("v{}", crate_version!()))
        .setting(AppSettings::SubcommandRequired)
        .subcommand(
            SubCommand::with_name("build")
                .about("Build the book from the markdown files")
                .arg_from_usage(d_message)
                .arg_from_usage(dir_message),
        )
        .subcommand(
            SubCommand::with_name("linkcheck")
                .about("Run linkcheck with mdBook 3")
                .arg_from_usage(dir_message),
        )
        .get_matches();

    // Check which subcomamnd the user ran...
    match matches.subcommand() {
        ("build", Some(sub_matches)) => {
            if let Err(e) = build(sub_matches) {
                eprintln!("Error: {}", e);

                for cause in e.iter().skip(1) {
                    eprintln!("\tCaused By: {}", cause);
                }

                ::std::process::exit(101);
            }
        }
        ("linkcheck", Some(sub_matches)) => {
            #[cfg(feature = "linkcheck")]
            {
                let (diags, files) = linkcheck(sub_matches).expect("Error while linkchecking.");
                if !diags.is_empty() {
                    let color = codespan_reporting::term::termcolor::ColorChoice::Auto;
                    let mut writer =
                        codespan_reporting::term::termcolor::StandardStream::stderr(color);
                    let cfg = codespan_reporting::term::Config::default();

                    for diag in diags {
                        codespan_reporting::term::emit(&mut writer, &cfg, &files, &diag)
                            .expect("Unable to emit linkcheck error.");
                    }

                    std::process::exit(101);
                }
            }

            #[cfg(not(feature = "linkcheck"))]
            {
                // This avoids the `unused_binding` lint.
                println!(
                    "mdbook-linkcheck is disabled, but arguments were passed: {:?}",
                    sub_matches
                );
            }
        }
        (_, _) => unreachable!(),
    };
}

#[cfg(feature = "linkcheck")]
pub fn linkcheck(
    args: &ArgMatches<'_>,
) -> Result<(Vec<codespan_reporting::diagnostic::Diagnostic>, codespan::Files), failure::Error> {
    use mdbook_linkcheck::Reason;

    let book_dir = get_book_dir(args);
    let src_dir = book_dir.join("src");
    let book = MDBook::load(&book_dir).unwrap();
    let linkck_cfg = mdbook_linkcheck::get_config(&book.config)?;
    let mut files = codespan::Files::new();
    let target_files = mdbook_linkcheck::load_files_into_memory(&book.book, &mut files);
    let cache = mdbook_linkcheck::Cache::default();

    let (links, incomplete) = mdbook_linkcheck::extract_links(target_files, &files);

    let outcome =
        mdbook_linkcheck::validate(&links, &linkck_cfg, &src_dir, &cache, &files, incomplete)?;

    let mut is_real_error = false;

    for link in outcome.invalid_links.iter() {
        match &link.reason {
            Reason::FileNotFound | Reason::TraversesParentDirectories => {
                is_real_error = true;
            }
            Reason::UnsuccessfulServerResponse(status) => {
                if status.is_client_error() {
                    is_real_error = true;
                } else {
                    eprintln!("Unsuccessful server response for link `{}`", link.link.uri);
                }
            }
            Reason::Client(err) => {
                if err.is_timeout() {
                    eprintln!("Timeout for link `{}`", link.link.uri);
                } else if err.is_server_error() {
                    eprintln!("Server error for link `{}`", link.link.uri);
                } else if !err.is_http() {
                    eprintln!("Non-HTTP-related error for link: {} {}", link.link.uri, err);
                } else {
                    is_real_error = true;
                }
            }
        }
    }

    if is_real_error {
        Ok((outcome.generate_diagnostics(&files, linkck_cfg.warning_policy), files))
    } else {
        Ok((vec![], files))
    }
}

// Build command implementation
pub fn build(args: &ArgMatches<'_>) -> Result3<()> {
    let book_dir = get_book_dir(args);
    let mut book = MDBook::load(&book_dir)?;

    // Set this to allow us to catch bugs in advance.
    book.config.build.create_missing = false;

    if let Some(dest_dir) = args.value_of("dest-dir") {
        book.config.build.build_dir = PathBuf::from(dest_dir);
    }

    book.build()?;

    Ok(())
}

fn get_book_dir(args: &ArgMatches<'_>) -> PathBuf {
    if let Some(dir) = args.value_of("dir") {
        // Check if path is relative from current dir, or absolute...
        let p = Path::new(dir);
        if p.is_relative() { env::current_dir().unwrap().join(dir) } else { p.to_path_buf() }
    } else {
        env::current_dir().unwrap()
    }
}
<|endoftext|>


<commit_before>use serde::de::Error;
use serde_json::{self, Error as JsonError};

use std::collections::{BTreeMap, HashSet};

use storage::StorageValue;
use events::Milliseconds;
use crypto::{hash, PublicKey, Hash};

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct StoredConfiguration {
    pub previous_cfg_hash: Hash,
    pub actual_from: u64,
    /// List of validator's consensus and service public keys.
    pub validator_keys: Vec<PublicKey>,
    pub service_keys: Vec<PublicKey>,
    pub consensus: ConsensusConfig,
    pub services: BTreeMap<String, serde_json::Value>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct ConsensusConfig {
    pub round_timeout: Milliseconds,
    pub status_timeout: Milliseconds,
    pub peers_timeout: Milliseconds,
    pub propose_timeout: Milliseconds,
    pub txs_block_limit: u32,
}

impl Default for ConsensusConfig {
    fn default() -> Self {
        ConsensusConfig {
            round_timeout: 3000,
            propose_timeout: 500,
            status_timeout: 5000,
            peers_timeout: 10000,
            txs_block_limit: 1000,
        }
    }
}

impl StoredConfiguration {
    pub fn try_serialize(&self) -> Result<Vec<u8>, JsonError> {
        serde_json::to_vec(&self)
    }

    pub fn try_deserialize(serialized: &[u8]) -> Result<StoredConfiguration, JsonError> {
        let config: StoredConfiguration = serde_json::from_slice(serialized)?;

        if config.validator_keys.len() != config.service_keys.len() {
            return Err(
                JsonError::custom("The amount of validator and service keys should be equal"));
        }

        {
            // Check that there are no duplicated keys.
            let keys: HashSet<_> = config
                .validator_keys
                .iter()
                .chain(config.service_keys.iter())
                .collect();
            if keys.len() != config.validator_keys.len() * 2 {
                return Err(JsonError::custom("Duplicated validator keys are found"));
            }
        }

        Ok(config)
    }
}

impl StorageValue for StoredConfiguration {
    fn serialize(self) -> Vec<u8> {
        self.try_serialize().unwrap()
    }

    fn deserialize(v: Vec<u8>) -> Self {
        StoredConfiguration::try_deserialize(&v).unwrap()
    }

    fn hash(&self) -> Hash {
        let vec_bytes = self.try_serialize().unwrap();
        hash(&vec_bytes)
    }
}

#[cfg(test)]
mod tests {
    use toml;
    use super::*;

    // TOML doesn't support all rust types, but `StoredConfiguration` must be able to save as TOML.
    #[test]
    fn stored_configuration_toml() {
        let original = StoredConfiguration {
            previous_cfg_hash: Hash::zero(),
            actual_from: 42,
            validator_keys: vec![PublicKey::zero()],
            service_keys: vec![PublicKey::zero()],
            consensus: ConsensusConfig::default(),
            services: BTreeMap::new(),
        };
        let toml = toml::to_string(&original).unwrap();
        let deserialized: StoredConfiguration = toml::from_str(&toml).unwrap();
        assert_eq!(original, deserialized);
    }
}
<commit_msg>More tests for StoredConfiguration<commit_after>use serde::de::Error;
use serde_json::{self, Error as JsonError};

use std::collections::{BTreeMap, HashSet};

use storage::StorageValue;
use events::Milliseconds;
use crypto::{hash, PublicKey, Hash};

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct StoredConfiguration {
    pub previous_cfg_hash: Hash,
    pub actual_from: u64,
    /// List of validator's consensus and service public keys.
    pub validator_keys: Vec<PublicKey>,
    pub service_keys: Vec<PublicKey>,
    pub consensus: ConsensusConfig,
    pub services: BTreeMap<String, serde_json::Value>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct ConsensusConfig {
    pub round_timeout: Milliseconds,
    pub status_timeout: Milliseconds,
    pub peers_timeout: Milliseconds,
    pub propose_timeout: Milliseconds,
    pub txs_block_limit: u32,
}

impl Default for ConsensusConfig {
    fn default() -> Self {
        ConsensusConfig {
            round_timeout: 3000,
            propose_timeout: 500,
            status_timeout: 5000,
            peers_timeout: 10000,
            txs_block_limit: 1000,
        }
    }
}

impl StoredConfiguration {
    pub fn try_serialize(&self) -> Result<Vec<u8>, JsonError> {
        serde_json::to_vec(&self)
    }

    pub fn try_deserialize(serialized: &[u8]) -> Result<StoredConfiguration, JsonError> {
        let config: StoredConfiguration = serde_json::from_slice(serialized)?;

        if config.validator_keys.len() != config.service_keys.len() {
            return Err(
                JsonError::custom("The amount of validator and service keys should be equal"));
        }

        // Check that there are no duplicated keys.
        {
            let keys: HashSet<_> = config
                .validator_keys
                .iter()
                .chain(config.service_keys.iter())
                .collect();
            if keys.len() != config.validator_keys.len() * 2 {
                return Err(JsonError::custom("Duplicated validator keys are found"));
            }
        }

        Ok(config)
    }
}

impl StorageValue for StoredConfiguration {
    fn serialize(self) -> Vec<u8> {
        self.try_serialize().unwrap()
    }

    fn deserialize(v: Vec<u8>) -> Self {
        StoredConfiguration::try_deserialize(&v).unwrap()
    }

    fn hash(&self) -> Hash {
        let vec_bytes = self.try_serialize().unwrap();
        hash(&vec_bytes)
    }
}

#[cfg(test)]
mod tests {
    use toml;
    use crypto::{Seed, gen_keypair_from_seed};
    use super::*;

    // TOML doesn't support all rust types, but `StoredConfiguration` must be able to save as TOML.
    #[test]
    fn stored_configuration_toml() {
        let original = create_test_configuration();
        let toml = toml::to_string(&original).unwrap();
        let deserialized: StoredConfiguration = toml::from_str(&toml).unwrap();
        assert_eq!(original, deserialized);
    }

    #[test]
    fn stored_configuration_serialize_deserialize() {
        let configuration = create_test_configuration();
        serialize_deserialize(&configuration);
    }

    #[test]
    #[should_panic(expected = "The amount of validator and service keys should be equal")]
    fn stored_configuration_different_keys_amount() {
        let mut configuration = create_test_configuration();
        configuration.service_keys.push(PublicKey::zero());
        serialize_deserialize(&configuration);
    }

    #[test]
    #[should_panic(expected = "Duplicated validator keys are found")]
    fn stored_configuration_duplicated_keys() {
        let mut configuration = create_test_configuration();
        configuration.validator_keys.push(PublicKey::zero());
        configuration.service_keys.push(PublicKey::zero());
        serialize_deserialize(&configuration);
    }

    fn create_test_configuration() -> StoredConfiguration {
        let validator_keys = vec![gen_keypair_from_seed(&Seed::new([1; 32])).0,
                                  gen_keypair_from_seed(&Seed::new([2; 32])).0];
        let service_keys = vec![gen_keypair_from_seed(&Seed::new([3; 32])).0,
                                gen_keypair_from_seed(&Seed::new([4; 32])).0];
        StoredConfiguration {
            previous_cfg_hash: Hash::zero(),
            actual_from: 42,
            validator_keys,
            service_keys,
            consensus: ConsensusConfig::default(),
            services: BTreeMap::new(),
        }
    }

    fn serialize_deserialize(configuration: &StoredConfiguration) {
        let serialized = configuration.try_serialize().unwrap();
        let _ = StoredConfiguration::try_deserialize(&serialized).unwrap();
    }
}
<|endoftext|>


<commit_before>/*!
WARNING: This signature software is a prototype. It has been replaced by the final system
[Ed25519](http://ed25519.cr.yp.to/). It is only kept here for compatibility reasons.
*/
use std::libc::{c_ulonglong, c_int};
use std::vec::{from_elem};
use std::vec::raw::{to_mut_ptr, to_ptr};

#[link(name = "sodium")]
#[link_args = "-lsodium"]
extern {
    fn crypto_sign_edwards25519sha512batch_keypair(pk: *mut u8,
                                                   sk: *mut u8) -> c_int;
    fn crypto_sign_edwards25519sha512batch(sm: *mut u8,
                                           smlen: *mut c_ulonglong,
                                           m: *u8,
                                           mlen: c_ulonglong,
                                           sk: *u8) -> c_int;
    fn crypto_sign_edwards25519sha512batch_open(m: *mut u8,
                                                mlen: *mut c_ulonglong,
                                                sm: *u8,
                                                smlen: c_ulonglong,
                                                pk: *u8) -> c_int;
}

pub static SECRETKEYBYTES: uint = 64;
pub static PUBLICKEYBYTES: uint = 32;
pub static SIGNATUREBYTES: uint = 64;

/**
 * `SecretKey` for signatures
 *
 * When a `SecretKey` goes out of scope its contents
 * will be zeroed out
 */
pub struct SecretKey([u8, ..SECRETKEYBYTES]);
impl Drop for SecretKey {
    fn drop(&mut self) {
        for e in self.mut_iter() { *e = 0 }
    }
}
/**
 * `PublicKey` for signatures
 */
pub struct PublicKey([u8, ..PUBLICKEYBYTES]);

/**
 * `gen_keypair()` randomly generates a secret key and a corresponding public
 * key.
 *
 * THREAD SAFETY: `gen_keypair()` is thread-safe provided that you have
 * called `sodiumoxide::init()` once before using any other function
 * from sodiumoxide.
 */
#[fixed_stack_segment]
pub fn gen_keypair() -> (~PublicKey, ~SecretKey) {
    unsafe {
        let mut pk = ~PublicKey([0u8, ..PUBLICKEYBYTES]);
        let mut sk = ~SecretKey([0u8, ..SECRETKEYBYTES]);
        crypto_sign_edwards25519sha512batch_keypair(to_mut_ptr(**pk), to_mut_ptr(**sk));
        (pk, sk)
    }
}

/**
 * `sign()` signs a message `m` using the signer's secret key `sk`.
 * `sign()` returns the resulting signed message `sm`.
 */
#[fixed_stack_segment]
pub fn sign(m: &[u8], sk: &SecretKey) -> ~[u8] {
    unsafe {
        let mut sm = from_elem(m.len() + SIGNATUREBYTES, 0u8);
        let mut smlen = 0;
        crypto_sign_edwards25519sha512batch(to_mut_ptr(sm),
                                            &mut smlen,
                                            to_ptr(m),
                                            m.len() as c_ulonglong,
                                            to_ptr(**sk));
        sm.truncate(smlen as uint);
        sm
    }
}

/**
 * `verify()` verifies the signature in `sm` using the signer's public key `pk`.
 * `verify()` returns the message `Some(m)`.
 * If the signature fails verification, `verify()` returns `None`.
 */
#[fixed_stack_segment]
pub fn verify(sm: &[u8], pk: &PublicKey) -> Option<~[u8]> {
    unsafe {
        let mut m = from_elem(sm.len(), 0u8);
        let mut mlen = 0;
        if crypto_sign_edwards25519sha512batch_open(to_mut_ptr(m),
                                                    &mut mlen,
                                                    to_ptr(sm),
                                                    sm.len() as c_ulonglong,
                                                    to_ptr(**pk)) == 0 {
            m.truncate(mlen as uint);
            Some(m)
        } else {
            None
        }
    }
}

#[test]
fn test_sign_verify() {
    use randombytes::randombytes;
    for _ in range(0, 256) {
        let (pk, sk) = gen_keypair();
        let m = randombytes(1024);
        let sm = sign(m, sk);
        let m2 = verify(sm, pk);
        assert!(Some(m) == m2);
    }
}

#[test]
fn test_sign_verify_tamper() {
    use randombytes::randombytes;
    for _ in range(0, 32) {
        let (pk, sk) = gen_keypair();
        let m = randombytes(1024);
        let mut sm = sign(m, sk);
        for i in range(0, sm.len()) {
            sm[i] ^= 0x20;
            assert!(None == verify(sm, pk));
            sm[i] ^= 0x20;
        }
    }
}
<commit_msg>lowered the test count for edwards25519sha512batch<commit_after>/*!
WARNING: This signature software is a prototype. It has been replaced by the final system
[Ed25519](http://ed25519.cr.yp.to/). It is only kept here for compatibility reasons.
*/
use std::libc::{c_ulonglong, c_int};
use std::vec::{from_elem};
use std::vec::raw::{to_mut_ptr, to_ptr};

#[link(name = "sodium")]
#[link_args = "-lsodium"]
extern {
    fn crypto_sign_edwards25519sha512batch_keypair(pk: *mut u8,
                                                   sk: *mut u8) -> c_int;
    fn crypto_sign_edwards25519sha512batch(sm: *mut u8,
                                           smlen: *mut c_ulonglong,
                                           m: *u8,
                                           mlen: c_ulonglong,
                                           sk: *u8) -> c_int;
    fn crypto_sign_edwards25519sha512batch_open(m: *mut u8,
                                                mlen: *mut c_ulonglong,
                                                sm: *u8,
                                                smlen: c_ulonglong,
                                                pk: *u8) -> c_int;
}

pub static SECRETKEYBYTES: uint = 64;
pub static PUBLICKEYBYTES: uint = 32;
pub static SIGNATUREBYTES: uint = 64;

/**
 * `SecretKey` for signatures
 *
 * When a `SecretKey` goes out of scope its contents
 * will be zeroed out
 */
pub struct SecretKey([u8, ..SECRETKEYBYTES]);
impl Drop for SecretKey {
    fn drop(&mut self) {
        for e in self.mut_iter() { *e = 0 }
    }
}
/**
 * `PublicKey` for signatures
 */
pub struct PublicKey([u8, ..PUBLICKEYBYTES]);

/**
 * `gen_keypair()` randomly generates a secret key and a corresponding public
 * key.
 *
 * THREAD SAFETY: `gen_keypair()` is thread-safe provided that you have
 * called `sodiumoxide::init()` once before using any other function
 * from sodiumoxide.
 */
#[fixed_stack_segment]
pub fn gen_keypair() -> (~PublicKey, ~SecretKey) {
    unsafe {
        let mut pk = ~PublicKey([0u8, ..PUBLICKEYBYTES]);
        let mut sk = ~SecretKey([0u8, ..SECRETKEYBYTES]);
        crypto_sign_edwards25519sha512batch_keypair(to_mut_ptr(**pk), to_mut_ptr(**sk));
        (pk, sk)
    }
}

/**
 * `sign()` signs a message `m` using the signer's secret key `sk`.
 * `sign()` returns the resulting signed message `sm`.
 */
#[fixed_stack_segment]
pub fn sign(m: &[u8], sk: &SecretKey) -> ~[u8] {
    unsafe {
        let mut sm = from_elem(m.len() + SIGNATUREBYTES, 0u8);
        let mut smlen = 0;
        crypto_sign_edwards25519sha512batch(to_mut_ptr(sm),
                                            &mut smlen,
                                            to_ptr(m),
                                            m.len() as c_ulonglong,
                                            to_ptr(**sk));
        sm.truncate(smlen as uint);
        sm
    }
}

/**
 * `verify()` verifies the signature in `sm` using the signer's public key `pk`.
 * `verify()` returns the message `Some(m)`.
 * If the signature fails verification, `verify()` returns `None`.
 */
#[fixed_stack_segment]
pub fn verify(sm: &[u8], pk: &PublicKey) -> Option<~[u8]> {
    unsafe {
        let mut m = from_elem(sm.len(), 0u8);
        let mut mlen = 0;
        if crypto_sign_edwards25519sha512batch_open(to_mut_ptr(m),
                                                    &mut mlen,
                                                    to_ptr(sm),
                                                    sm.len() as c_ulonglong,
                                                    to_ptr(**pk)) == 0 {
            m.truncate(mlen as uint);
            Some(m)
        } else {
            None
        }
    }
}

#[test]
fn test_sign_verify() {
    use randombytes::randombytes;
    for _ in range(0, 32) {
        let (pk, sk) = gen_keypair();
        let m = randombytes(1024);
        let sm = sign(m, sk);
        let m2 = verify(sm, pk);
        assert!(Some(m) == m2);
    }
}

#[test]
fn test_sign_verify_tamper() {
    use randombytes::randombytes;
    for _ in range(0, 32) {
        let (pk, sk) = gen_keypair();
        let m = randombytes(1024);
        let mut sm = sign(m, sk);
        for i in range(0, sm.len()) {
            sm[i] ^= 0x20;
            assert!(None == verify(sm, pk));
            sm[i] ^= 0x20;
        }
    }
}
<|endoftext|>


<commit_before>//! Library service providers implementation.

extern crate hyper;

use hyper::client::{Client, Response};
use hyper::header::ContentType;

/// Used to specify which provider to use to generate a short URL.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Provider {
    /// https://bam.bz provider
    BamBz,
    /// https://bn.gy provider
    BnGy,
    /// http://fifo.cc provider
    FifoCc,
    /// https://hec.su provider
    ///
    /// * Limited to 3000 API requests per day
    HecSu,
    /// https://is.gd provider
    IsGd,
    /// http://nowlinks.net provider
    NowLinks,
    /// http://phx.co.in provider
    /// After some time shows ads
    PhxCoIn,
    /// http://psbe.co provider
    PsbeCo,
    /// http://s.coop provider
    SCoop,
    /// http://readbility.com provider
    Rdd,
    /// http://rlu.ru provider
    ///
    /// * Attention! If you send a lot of requests from one IP, it can be
    /// blocked. If you plan to add more then 100 URLs in one hour, please let
    /// the technical support know. Otherwise your IP can be blocked
    /// unexpectedly. Prior added URLs can be deleted.
    Rlu,
    /// http://sirbz.com provider
    /// * Note: By default, you get 250 requests per 15 min for the SirBz URL Shortener API.
    SirBz,
    /// http://tinyurl.com provider
    /// * Note: this service does not provide any API.
    /// The implementation result depends on the service result web page.
    TinyUrl,
    /// http://tiny.ph provider
    TinyPh,
    /// http://tny.im provider
    TnyIm,
    /// https://v.gd provider
    VGd,
}

impl Provider {
    /// Converts the Provider variant into its domain name equivilant
    pub fn to_name(&self) -> &str {
        match *self {
            Provider::BamBz => "bam.bz",
            Provider::BnGy => "bn.gy",
            Provider::FifoCc => "fifo.cc",
            Provider::HecSu => "hec.su",
            Provider::IsGd => "is.gd",
            Provider::NowLinks => "nowlinks.net",
            Provider::PhxCoIn => "phx.co.in",
            Provider::PsbeCo => "psbe.co",
            Provider::SCoop => "s.coop",
            Provider::SirBz => "sirbz.com",
            Provider::Rdd => "readability.com",
            Provider::Rlu => "rlu.ru",
            Provider::TinyUrl => "tinyurl.com",
            Provider::TinyPh => "tiny.ph",
            Provider::TnyIm => "tny.im",
            Provider::VGd => "v.gd",
        }
    }
}

/// Returns a vector of all `Provider` variants.
///
/// The providers which are discouraged from use due to limitations such as
/// rate limitations are at the end of the resultant vector.
pub fn providers() -> Vec<Provider> {
    vec![
        Provider::IsGd,
        Provider::BnGy,
        Provider::VGd,
        Provider::Rdd,
        Provider::BamBz,
        Provider::TinyPh,
        Provider::FifoCc,
        Provider::TnyIm,
        Provider::SCoop,

        // The following list are items that are discouraged from use.
        // Reason: rate limit (250 requests per 15 minutes)
        Provider::SirBz,
        // Reason: rate limit (100 requests per hour)
        Provider::Rlu,
        // Reason: rate limit (3000 requests per day)
        Provider::HecSu,
        // Reason: does not provide an api
        Provider::TinyUrl,
        // Reason: unstable work
        Provider::PsbeCo,

        // The following list are items that show previews instead of direct links.
        Provider::NowLinks,

        // The following list are items that show ads and have a timeout before
        // you may go on the original link.
        Provider::PhxCoIn,
    ]
}

fn bambz_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let value = string.split("\"url\"")
                      .nth(1).unwrap_or("")
                      .split(",").next().unwrap_or("")
                      .split("\"").nth(1);
    if let Some(string) = value {
        Some(string.to_owned().replace("\\", ""))
    } else {
        None
    }
}

fn bambz_request(url: &str, client: &Client) -> Option<Response> {
    client.post("https://bam.bz/api/short")
        .body(&format!("target={}", url))
        .header(ContentType::form_url_encoded())
        .send()
        .ok()
}

fn bngy_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let iter = string.split("<ShortenedUrl>").skip(1).next();
    if iter.is_none() {
        return None
    }
    if let Some(string) = iter.unwrap().split("</ShortenedUrl>").next() {
        Some(string.to_owned())
    } else {
        None
    }
}

fn bngy_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("https://bn.gy/API.asmx/CreateUrl?real_url={}", url))
        .send()
        .ok()
}

fn fifocc_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let value = string.split("\"shortner\"")
                      .nth(1).unwrap_or("")
                      .split(",").next().unwrap_or("")
                      .split("\"").nth(1);
    if let Some(string) = value {
        let mut short_url = string.to_owned();
        short_url = format!("http://fifo.cc/{}", short_url);
        Some(short_url)
    } else {
        None
    }
}

fn fifocc_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("https://fifo.cc/api/v2?url={}", url))
        .send()
        .ok()
}

fn hecsu_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let iter = string.split("<short>").skip(1).next();
    if iter.is_none() {
        return None
    }
    if let Some(string) = iter.unwrap().split("</short>").next() {
        Some(string.to_owned())
    } else {
        None
    }
}

fn hecsu_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("https://hec.su/api?url={}&method=xml", url))
        .send()
        .ok()
}

fn isgd_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn isgd_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("https://is.gd/create.php?format=simple&url={}", url))
        .send()
        .ok()
}

fn nowlinks_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn nowlinks_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://nowlinks.net/api?url={}", url))
        .send()
        .ok()
}

fn phxcoin_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn phxcoin_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://phx.co.in/shrink.asp?url={}", url))
        .send()
        .ok()
}

fn psbeco_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let iter = string.split("<ShortUrl>").skip(1).next();
    if iter.is_none() {
        return None
    }
    if let Some(string) = iter.unwrap().split("</ShortUrl>").next() {
        Some(string.to_owned())
    } else {
        None
    }
}

fn psbeco_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://psbe.co/API.asmx/CreateUrl?real_url={}", url))
        .send()
        .ok()
}

fn scoop_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn scoop_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://s.coop/devapi.php?action=shorturl&url={}&format=RETURN", url))
        .send()
        .ok()
}

fn rdd_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let value = string.split("\"rdd_url\"")
                      .nth(1).unwrap_or("")
                      .split(",").next().unwrap_or("")
                      .split("\"").nth(1);
    if let Some(string) = value {
        let mut short_url = string.to_owned();
        let _ = short_url.pop();
        Some(short_url)
    } else {
        None
    }
}

fn rdd_request(url: &str, client: &Client) -> Option<Response> {
    client.post("https://readability.com/api/shortener/v1/urls")
        .body(&format!("url={}", url))
        .send()
        .ok()
}

fn rlu_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn rlu_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://rlu.ru/index.sema?a=api&link={}", url))
        .send()
        .ok()
}

fn sirbz_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let value = string.split("\"short_link\"")
                      .nth(1).unwrap_or("")
                      .split("\"").skip(1).next();
    if let Some(string) = value {
        Some(string.to_owned())
    } else {
        None
    }
}

fn sirbz_request(url: &str, client: &Client) -> Option<Response> {
    client.post("http://sirbz.com/api/shorten_url")
        .body(&format!("url={}", url))
        .header(ContentType::form_url_encoded())
        .send()
        .ok()
}

fn tinyurl_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let value = string.split("data-clipboard-text=\"")
                      .nth(1).unwrap_or("")
                      .split("\">").next();
    if let Some(string) = value {
        Some(string.to_owned())
    } else {
        None
    }
}

fn tinyurl_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://tinyurl.com/create.php?url={}", url))
        .send()
        .ok()
}

fn tinyph_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let value = string.split("\"hash\"")
                      .nth(1).unwrap_or("")
                      .split("\"").skip(1).next();
    if let Some(string) = value {
        Some(format!("http://tiny.ph/{}", string))
    } else {
        None
    }
}

fn tinyph_request(url: &str, client: &Client) -> Option<Response> {
    client.post("http://tiny.ph/api/url/create")
        .body(&format!("url={}", url))
        .header(ContentType::form_url_encoded())
        .send()
        .ok()
}

fn tnyim_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let iter = string.split("<shorturl>").skip(1).next();
    if iter.is_none() {
        return None
    }
    if let Some(string) = iter.unwrap().split("</shorturl>").next() {
        Some(string.to_owned())
    } else {
        None
    }
}

fn tnyim_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://tny.im/yourls-api.php?action=shorturl&url={}", url))
        .send()
        .ok()
}

fn vgd_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn vgd_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://v.gd/create.php?format=simple&url={}", url))
        .send()
        .ok()
}

/// Parses the response from a successful request to a provider into the
/// URL-shortened string.
pub fn parse(res: &str, provider: Provider) -> Option<String> {
    match provider {
        Provider::BamBz => bambz_parse(res),
        Provider::BnGy => bngy_parse(res),
        Provider::FifoCc => fifocc_parse(res),
        Provider::HecSu => hecsu_parse(res),
        Provider::IsGd => isgd_parse(res),
        Provider::NowLinks => nowlinks_parse(res),
        Provider::PhxCoIn => phxcoin_parse(res),
        Provider::PsbeCo => psbeco_parse(res),
        Provider::SCoop => scoop_parse(res),
        Provider::SirBz => sirbz_parse(res),
        Provider::Rdd => rdd_parse(res),
        Provider::Rlu => rlu_parse(res),
        Provider::TinyUrl => tinyurl_parse(res),
        Provider::TinyPh => tinyph_parse(res),
        Provider::TnyIm => tnyim_parse(res),
        Provider::VGd => vgd_parse(res),
    }
}

/// Performs a request to the short link provider.
/// Response to be parsed or `None` on a error.
pub fn request(url: &str, client: &Client, provider: Provider) -> Option<Response> {
    match provider {
        Provider::BamBz => bambz_request(url, client),
        Provider::BnGy => bngy_request(url, client),
        Provider::FifoCc => fifocc_request(url, client),
        Provider::HecSu => hecsu_request(url, client),
        Provider::IsGd => isgd_request(url, client),
        Provider::NowLinks => nowlinks_request(url, client),
        Provider::PhxCoIn => phxcoin_request(url, client),
        Provider::PsbeCo => psbeco_request(url, client),
        Provider::SCoop => scoop_request(url, client),
        Provider::SirBz => sirbz_request(url, client),
        Provider::Rdd => rdd_request(url, client),
        Provider::Rlu => rlu_request(url, client),
        Provider::TinyUrl => tinyurl_request(url, client),
        Provider::TinyPh => tinyph_request(url, client),
        Provider::TnyIm => tnyim_request(url, client),
        Provider::VGd => vgd_request(url, client),
    }
}
<commit_msg>abv8.me provider implemented<commit_after>//! Library service providers implementation.

extern crate hyper;

use hyper::client::{Client, Response};
use hyper::header::ContentType;

/// Used to specify which provider to use to generate a short URL.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Provider {
    /// http://abv8.me provider
    /// Limits:
    /// * You may not shorten more than 20 unique URLs in a 3-minute span.
    /// * You may not shorten more than 60 unique URLs in a 15-minute span.
    Abv8,
    /// https://bam.bz provider
    BamBz,
    /// https://bn.gy provider
    BnGy,
    /// http://fifo.cc provider
    FifoCc,
    /// https://hec.su provider
    ///
    /// * Limited to 3000 API requests per day
    HecSu,
    /// https://is.gd provider
    IsGd,
    /// http://nowlinks.net provider
    NowLinks,
    /// http://phx.co.in provider
    /// After some time shows ads
    PhxCoIn,
    /// http://psbe.co provider
    PsbeCo,
    /// http://s.coop provider
    SCoop,
    /// http://readbility.com provider
    Rdd,
    /// http://rlu.ru provider
    ///
    /// * Attention! If you send a lot of requests from one IP, it can be
    /// blocked. If you plan to add more then 100 URLs in one hour, please let
    /// the technical support know. Otherwise your IP can be blocked
    /// unexpectedly. Prior added URLs can be deleted.
    Rlu,
    /// http://sirbz.com provider
    /// * Note: By default, you get 250 requests per 15 min for the SirBz URL Shortener API.
    SirBz,
    /// http://tinyurl.com provider
    /// * Note: this service does not provide any API.
    /// The implementation result depends on the service result web page.
    TinyUrl,
    /// http://tiny.ph provider
    TinyPh,
    /// http://tny.im provider
    TnyIm,
    /// https://v.gd provider
    VGd,
}

impl Provider {
    /// Converts the Provider variant into its domain name equivilant
    pub fn to_name(&self) -> &str {
        match *self {
            Provider::Abv8 => "abv8.me",
            Provider::BamBz => "bam.bz",
            Provider::BnGy => "bn.gy",
            Provider::FifoCc => "fifo.cc",
            Provider::HecSu => "hec.su",
            Provider::IsGd => "is.gd",
            Provider::NowLinks => "nowlinks.net",
            Provider::PhxCoIn => "phx.co.in",
            Provider::PsbeCo => "psbe.co",
            Provider::SCoop => "s.coop",
            Provider::SirBz => "sirbz.com",
            Provider::Rdd => "readability.com",
            Provider::Rlu => "rlu.ru",
            Provider::TinyUrl => "tinyurl.com",
            Provider::TinyPh => "tiny.ph",
            Provider::TnyIm => "tny.im",
            Provider::VGd => "v.gd",
        }
    }
}

/// Returns a vector of all `Provider` variants.
///
/// The providers which are discouraged from use due to limitations such as
/// rate limitations are at the end of the resultant vector.
pub fn providers() -> Vec<Provider> {
    vec![
        Provider::IsGd,
        Provider::BnGy,
        Provider::VGd,
        Provider::Rdd,
        Provider::BamBz,
        Provider::TinyPh,
        Provider::FifoCc,
        Provider::TnyIm,
        Provider::SCoop,

        // The following list are items that are discouraged from use.
        // Reason: rate limit (250 requests per 15 minutes)
        Provider::SirBz,
        // Reason: rate limit (100 requests per hour)
        Provider::Rlu,
        // Reason: rate limit (3000 requests per day)
        Provider::HecSu,
        // Reason: rate limit (20r/3min; 60r/15min for a UNIQUE urls only)
        Provider::Abv8,
        // Reason: does not provide an api
        Provider::TinyUrl,
        // Reason: unstable work
        Provider::PsbeCo,

        // The following list are items that show previews instead of direct links.
        Provider::NowLinks,

        // The following list are items that show ads and have a timeout before
        // you may go on the original link.
        Provider::PhxCoIn,
    ]
}

fn abv8_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn abv8_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://abv8.me/?url={}", url))
        .send()
        .ok()
}

fn bambz_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let value = string.split("\"url\"")
                      .nth(1).unwrap_or("")
                      .split(",").next().unwrap_or("")
                      .split("\"").nth(1);
    if let Some(string) = value {
        Some(string.to_owned().replace("\\", ""))
    } else {
        None
    }
}

fn bambz_request(url: &str, client: &Client) -> Option<Response> {
    client.post("https://bam.bz/api/short")
        .body(&format!("target={}", url))
        .header(ContentType::form_url_encoded())
        .send()
        .ok()
}

fn bngy_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let iter = string.split("<ShortenedUrl>").skip(1).next();
    if iter.is_none() {
        return None
    }
    if let Some(string) = iter.unwrap().split("</ShortenedUrl>").next() {
        Some(string.to_owned())
    } else {
        None
    }
}

fn bngy_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("https://bn.gy/API.asmx/CreateUrl?real_url={}", url))
        .send()
        .ok()
}

fn fifocc_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let value = string.split("\"shortner\"")
                      .nth(1).unwrap_or("")
                      .split(",").next().unwrap_or("")
                      .split("\"").nth(1);
    if let Some(string) = value {
        let mut short_url = string.to_owned();
        short_url = format!("http://fifo.cc/{}", short_url);
        Some(short_url)
    } else {
        None
    }
}

fn fifocc_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("https://fifo.cc/api/v2?url={}", url))
        .send()
        .ok()
}

fn hecsu_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let iter = string.split("<short>").skip(1).next();
    if iter.is_none() {
        return None
    }
    if let Some(string) = iter.unwrap().split("</short>").next() {
        Some(string.to_owned())
    } else {
        None
    }
}

fn hecsu_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("https://hec.su/api?url={}&method=xml", url))
        .send()
        .ok()
}

fn isgd_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn isgd_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("https://is.gd/create.php?format=simple&url={}", url))
        .send()
        .ok()
}

fn nowlinks_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn nowlinks_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://nowlinks.net/api?url={}", url))
        .send()
        .ok()
}

fn phxcoin_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn phxcoin_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://phx.co.in/shrink.asp?url={}", url))
        .send()
        .ok()
}

fn psbeco_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let iter = string.split("<ShortUrl>").skip(1).next();
    if iter.is_none() {
        return None
    }
    if let Some(string) = iter.unwrap().split("</ShortUrl>").next() {
        Some(string.to_owned())
    } else {
        None
    }
}

fn psbeco_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://psbe.co/API.asmx/CreateUrl?real_url={}", url))
        .send()
        .ok()
}

fn scoop_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn scoop_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://s.coop/devapi.php?action=shorturl&url={}&format=RETURN", url))
        .send()
        .ok()
}

fn rdd_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let value = string.split("\"rdd_url\"")
                      .nth(1).unwrap_or("")
                      .split(",").next().unwrap_or("")
                      .split("\"").nth(1);
    if let Some(string) = value {
        let mut short_url = string.to_owned();
        let _ = short_url.pop();
        Some(short_url)
    } else {
        None
    }
}

fn rdd_request(url: &str, client: &Client) -> Option<Response> {
    client.post("https://readability.com/api/shortener/v1/urls")
        .body(&format!("url={}", url))
        .send()
        .ok()
}

fn rlu_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn rlu_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://rlu.ru/index.sema?a=api&link={}", url))
        .send()
        .ok()
}

fn sirbz_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let value = string.split("\"short_link\"")
                      .nth(1).unwrap_or("")
                      .split("\"").skip(1).next();
    if let Some(string) = value {
        Some(string.to_owned())
    } else {
        None
    }
}

fn sirbz_request(url: &str, client: &Client) -> Option<Response> {
    client.post("http://sirbz.com/api/shorten_url")
        .body(&format!("url={}", url))
        .header(ContentType::form_url_encoded())
        .send()
        .ok()
}

fn tinyurl_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let value = string.split("data-clipboard-text=\"")
                      .nth(1).unwrap_or("")
                      .split("\">").next();
    if let Some(string) = value {
        Some(string.to_owned())
    } else {
        None
    }
}

fn tinyurl_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://tinyurl.com/create.php?url={}", url))
        .send()
        .ok()
}

fn tinyph_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let value = string.split("\"hash\"")
                      .nth(1).unwrap_or("")
                      .split("\"").skip(1).next();
    if let Some(string) = value {
        Some(format!("http://tiny.ph/{}", string))
    } else {
        None
    }
}

fn tinyph_request(url: &str, client: &Client) -> Option<Response> {
    client.post("http://tiny.ph/api/url/create")
        .body(&format!("url={}", url))
        .header(ContentType::form_url_encoded())
        .send()
        .ok()
}

fn tnyim_parse(res: &str) -> Option<String> {
    if res.is_empty() {
        return None
    }
    let string = res.to_owned();
    let iter = string.split("<shorturl>").skip(1).next();
    if iter.is_none() {
        return None
    }
    if let Some(string) = iter.unwrap().split("</shorturl>").next() {
        Some(string.to_owned())
    } else {
        None
    }
}

fn tnyim_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://tny.im/yourls-api.php?action=shorturl&url={}", url))
        .send()
        .ok()
}

fn vgd_parse(res: &str) -> Option<String> {
    Some(res.to_owned())
}

fn vgd_request(url: &str, client: &Client) -> Option<Response> {
    client.get(&format!("http://v.gd/create.php?format=simple&url={}", url))
        .send()
        .ok()
}

/// Parses the response from a successful request to a provider into the
/// URL-shortened string.
pub fn parse(res: &str, provider: Provider) -> Option<String> {
    match provider {
        Provider::Abv8 => abv8_parse(res),
        Provider::BamBz => bambz_parse(res),
        Provider::BnGy => bngy_parse(res),
        Provider::FifoCc => fifocc_parse(res),
        Provider::HecSu => hecsu_parse(res),
        Provider::IsGd => isgd_parse(res),
        Provider::NowLinks => nowlinks_parse(res),
        Provider::PhxCoIn => phxcoin_parse(res),
        Provider::PsbeCo => psbeco_parse(res),
        Provider::SCoop => scoop_parse(res),
        Provider::SirBz => sirbz_parse(res),
        Provider::Rdd => rdd_parse(res),
        Provider::Rlu => rlu_parse(res),
        Provider::TinyUrl => tinyurl_parse(res),
        Provider::TinyPh => tinyph_parse(res),
        Provider::TnyIm => tnyim_parse(res),
        Provider::VGd => vgd_parse(res),
    }
}

/// Performs a request to the short link provider.
/// Response to be parsed or `None` on a error.
pub fn request(url: &str, client: &Client, provider: Provider) -> Option<Response> {
    match provider {
        Provider::Abv8 => abv8_request(url, client),
        Provider::BamBz => bambz_request(url, client),
        Provider::BnGy => bngy_request(url, client),
        Provider::FifoCc => fifocc_request(url, client),
        Provider::HecSu => hecsu_request(url, client),
        Provider::IsGd => isgd_request(url, client),
        Provider::NowLinks => nowlinks_request(url, client),
        Provider::PhxCoIn => phxcoin_request(url, client),
        Provider::PsbeCo => psbeco_request(url, client),
        Provider::SCoop => scoop_request(url, client),
        Provider::SirBz => sirbz_request(url, client),
        Provider::Rdd => rdd_request(url, client),
        Provider::Rlu => rlu_request(url, client),
        Provider::TinyUrl => tinyurl_request(url, client),
        Provider::TinyPh => tinyph_request(url, client),
        Provider::TnyIm => tnyim_request(url, client),
        Provider::VGd => vgd_request(url, client),
    }
}
<|endoftext|>