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

use syntax::{ast, codemap, visit};
use syntax::attr::AttrMetaMethods;
use rustc::ast_map;
use rustc::lint::{Context, LintPass, LintArray};
use rustc::middle::ty;
use rustc::middle::astconv_util::ast_ty_to_prim_ty;
use utils::{match_def_path, unsafe_context};

declare_lint!(UNROOTED_MUST_ROOT, Deny,
              "Warn and report usage of unrooted jsmanaged objects");

/// Lint for ensuring safe usage of unrooted pointers
///
/// This lint (disable with `-A unrooted-must-root`/`#[allow(unrooted_must_root)]`) ensures that `#[must_root]`
/// values are used correctly.
///
/// "Incorrect" usage includes:
///
///  - Not being used in a struct/enum field which is not `#[must_root]` itself
///  - Not being used as an argument to a function (Except onces named `new` and `new_inherited`)
///  - Not being bound locally in a `let` statement, assignment, `for` loop, or `match` statement.
///
/// This helps catch most situations where pointers like `JS<T>` are used in a way that they can be invalidated by a
/// GC pass.
///
/// Structs which have their own mechanism of rooting their unrooted contents (e.g. `ScriptTask`)
/// can be marked as `#[allow(unrooted_must_root)]`. Smart pointers which root their interior type
/// can be marked as `#[allow_unrooted_interior]`
pub struct UnrootedPass {
    in_new_function: bool
}

impl UnrootedPass {
    pub fn new() -> UnrootedPass {
        UnrootedPass {
            in_new_function: true
        }
    }
}

/// Checks if a type is unrooted or contains any owned unrooted types
fn is_unrooted_ty(cx: &Context, ty: &ty::TyS, in_new_function: bool) -> bool {
    let mut ret = false;
    ty.maybe_walk(|t| {
        match t.sty {
            ty::TyStruct(did, _) |
            ty::TyEnum(did, _) => {
                if cx.tcx.has_attr(did, "must_root") {
                    ret = true;
                    false
                } else if cx.tcx.has_attr(did, "allow_unrooted_interior") {
                    false
                } else if match_def_path(cx, did, &["core", "cell", "Ref"])
                        || match_def_path(cx, did, &["core", "cell", "RefMut"]) {
                        // Ref and RefMut are borrowed pointers, okay to hold unrooted stuff
                        // since it will be rooted elsewhere
                    false
                } else {
                    true
                }
            },
            ty::TyBox(..) if in_new_function => false, // box in new() is okay
            ty::TyRef(..) => false, // don't recurse down &ptrs
            ty::TyRawPtr(..) => false, // don't recurse down *ptrs
            _ => true
        }
    });
    ret
}

impl LintPass for UnrootedPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNROOTED_MUST_ROOT)
    }
    /// All structs containing #[must_root] types must be #[must_root] themselves
    fn check_struct_def(&mut self,
                        cx: &Context,
                        def: &ast::StructDef,
                        _i: ast::Ident,
                        _gen: &ast::Generics,
                        id: ast::NodeId) {
        let item = match cx.tcx.map.get(id) {
            ast_map::Node::NodeItem(item) => item,
            _ => cx.tcx.map.expect_item(cx.tcx.map.get_parent(id)),
        };
        if item.attrs.iter().all(|a| !a.check_name("must_root")) {
            for ref field in def.fields.iter() {
                if is_unrooted_ty(cx, cx.tcx.node_id_to_type(field.node.id), false) {
                    cx.span_lint(UNROOTED_MUST_ROOT, field.span,
                                 "Type must be rooted, use #[must_root] on the struct definition to propagate")
                }
            }
        }
    }
    /// All enums containing #[must_root] types must be #[must_root] themselves
    fn check_variant(&mut self, cx: &Context, var: &ast::Variant, _gen: &ast::Generics) {
        let ref map = cx.tcx.map;
        if map.expect_item(map.get_parent(var.node.id)).attrs.iter().all(|a| !a.check_name("must_root")) {
            match var.node.kind {
                ast::TupleVariantKind(ref vec) => {
                    for ty in vec.iter() {
                        ast_ty_to_prim_ty(cx.tcx, &*ty.ty).map(|t| {
                            if is_unrooted_ty(cx, t, false) {
                                cx.span_lint(UNROOTED_MUST_ROOT, ty.ty.span,
                                             "Type must be rooted, use #[must_root] on \
                                              the enum definition to propagate")
                            }
                        });
                    }
                }
                _ => () // Struct variants already caught by check_struct_def
            }
        }
    }
    /// Function arguments that are #[must_root] types are not allowed
    fn check_fn(&mut self, cx: &Context, kind: visit::FnKind, decl: &ast::FnDecl,
                block: &ast::Block, _span: codemap::Span, id: ast::NodeId) {
        match kind {
            visit::FkItemFn(i, _, _, _, _, _) |
            visit::FkMethod(i, _, _) if i.name.as_str() == "new"
                                        || i.name.as_str() == "new_inherited"
                                        || i.name.as_str() == "new_initialized" => {
                self.in_new_function = true;
                return;
            },
            visit::FkItemFn(_, _, style, _, _, _) => match style {
                ast::Unsafety::Unsafe => return,
                _ => ()
            },
            _ => ()
        }
        self.in_new_function = false;

        if unsafe_context(&cx.tcx.map, id) {
            return;
        }

        match block.rules {
            ast::DefaultBlock => {
                for arg in decl.inputs.iter() {
                    ast_ty_to_prim_ty(cx.tcx, &*arg.ty).map(|t| {
                        if is_unrooted_ty(cx, t, false) {
                            cx.span_lint(UNROOTED_MUST_ROOT, arg.ty.span, "Type must be rooted")
                        }
                    });
                }
            }
            _ => () // fn is `unsafe`
        }
    }

    // Partially copied from rustc::middle::lint::builtin
    // Catches `let` statements and assignments which store a #[must_root] value
    // Expressions which return out of blocks eventually end up in a `let` or assignment
    // statement or a function return (which will be caught when it is used elsewhere)
    fn check_stmt(&mut self, cx: &Context, s: &ast::Stmt) {
        match s.node {
            ast::StmtDecl(_, id) |
            ast::StmtExpr(_, id) |
            ast::StmtSemi(_, id) if unsafe_context(&cx.tcx.map, id) => {
                return
            },
            _ => ()
        };

        let expr = match s.node {
            // Catch a `let` binding
            ast::StmtDecl(ref decl, _) => match decl.node {
                ast::DeclLocal(ref loc) => match loc.init {
                    Some(ref e) => &**e,
                    _ => return
                },
                _ => return
            },
            ast::StmtExpr(ref expr, _) => match expr.node {
                // This catches deferred `let` statements
                ast::ExprAssign(_, ref e) |
                // Match statements allow you to bind onto the variable later in an arm
                // We need not check arms individually since enum/struct fields are already
                // linted in `check_struct_def` and `check_variant`
                // (so there is no way of destructuring out a `#[must_root]` field)
                ast::ExprMatch(ref e, _, _) |
                // For loops allow you to bind a return value locally
                ast::ExprForLoop(_, ref e, _, _) => &**e,
                // XXXManishearth look into `if let` once it lands in our rustc
                _ => return
            },
            _ => return
        };

        let ty = cx.tcx.expr_ty(&*expr);
        if is_unrooted_ty(cx, ty, self.in_new_function) {
            cx.span_lint(UNROOTED_MUST_ROOT, expr.span,
                                     &format!("Expression of type {:?} must be rooted", ty))
        }
    }
}
<commit_msg>Auto merge of #6855 - pcwalton:more-rooting-soundness, r=Manishearth<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use syntax::{ast, codemap, visit};
use syntax::attr::AttrMetaMethods;
use rustc::ast_map;
use rustc::lint::{Context, LintPass, LintArray};
use rustc::middle::ty;
use rustc::middle::astconv_util::ast_ty_to_prim_ty;
use utils::{match_def_path, unsafe_context};

declare_lint!(UNROOTED_MUST_ROOT, Deny,
              "Warn and report usage of unrooted jsmanaged objects");

/// Lint for ensuring safe usage of unrooted pointers
///
/// This lint (disable with `-A unrooted-must-root`/`#[allow(unrooted_must_root)]`) ensures that `#[must_root]`
/// values are used correctly.
///
/// "Incorrect" usage includes:
///
///  - Not being used in a struct/enum field which is not `#[must_root]` itself
///  - Not being used as an argument to a function (Except onces named `new` and `new_inherited`)
///  - Not being bound locally in a `let` statement, assignment, `for` loop, or `match` statement.
///
/// This helps catch most situations where pointers like `JS<T>` are used in a way that they can be invalidated by a
/// GC pass.
///
/// Structs which have their own mechanism of rooting their unrooted contents (e.g. `ScriptTask`)
/// can be marked as `#[allow(unrooted_must_root)]`. Smart pointers which root their interior type
/// can be marked as `#[allow_unrooted_interior]`
pub struct UnrootedPass {
    in_new_function: bool
}

impl UnrootedPass {
    pub fn new() -> UnrootedPass {
        UnrootedPass {
            in_new_function: true
        }
    }
}

/// Checks if a type is unrooted or contains any owned unrooted types
fn is_unrooted_ty(cx: &Context, ty: &ty::TyS, in_new_function: bool) -> bool {
    let mut ret = false;
    ty.maybe_walk(|t| {
        match t.sty {
            ty::TyStruct(did, _) |
            ty::TyEnum(did, _) => {
                if cx.tcx.has_attr(did, "must_root") {
                    ret = true;
                    false
                } else if cx.tcx.has_attr(did, "allow_unrooted_interior") {
                    false
                } else if match_def_path(cx, did, &["core", "cell", "Ref"])
                        || match_def_path(cx, did, &["core", "cell", "RefMut"]) {
                        // Ref and RefMut are borrowed pointers, okay to hold unrooted stuff
                        // since it will be rooted elsewhere
                    false
                } else {
                    true
                }
            },
            ty::TyBox(..) if in_new_function => false, // box in new() is okay
            ty::TyRef(..) => false, // don't recurse down &ptrs
            ty::TyRawPtr(..) => false, // don't recurse down *ptrs
            _ => true
        }
    });
    ret
}

impl LintPass for UnrootedPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNROOTED_MUST_ROOT)
    }
    /// All structs containing #[must_root] types must be #[must_root] themselves
    fn check_struct_def(&mut self,
                        cx: &Context,
                        def: &ast::StructDef,
                        _i: ast::Ident,
                        _gen: &ast::Generics,
                        id: ast::NodeId) {
        let item = match cx.tcx.map.get(id) {
            ast_map::Node::NodeItem(item) => item,
            _ => cx.tcx.map.expect_item(cx.tcx.map.get_parent(id)),
        };
        if item.attrs.iter().all(|a| !a.check_name("must_root")) {
            for ref field in def.fields.iter() {
                if is_unrooted_ty(cx, cx.tcx.node_id_to_type(field.node.id), false) {
                    cx.span_lint(UNROOTED_MUST_ROOT, field.span,
                                 "Type must be rooted, use #[must_root] on the struct definition to propagate")
                }
            }
        }
    }
    /// All enums containing #[must_root] types must be #[must_root] themselves
    fn check_variant(&mut self, cx: &Context, var: &ast::Variant, _gen: &ast::Generics) {
        let ref map = cx.tcx.map;
        if map.expect_item(map.get_parent(var.node.id)).attrs.iter().all(|a| !a.check_name("must_root")) {
            match var.node.kind {
                ast::TupleVariantKind(ref vec) => {
                    for ty in vec.iter() {
                        ast_ty_to_prim_ty(cx.tcx, &*ty.ty).map(|t| {
                            if is_unrooted_ty(cx, t, false) {
                                cx.span_lint(UNROOTED_MUST_ROOT, ty.ty.span,
                                             "Type must be rooted, use #[must_root] on \
                                              the enum definition to propagate")
                            }
                        });
                    }
                }
                _ => () // Struct variants already caught by check_struct_def
            }
        }
    }
    /// Function arguments that are #[must_root] types are not allowed
    fn check_fn(&mut self, cx: &Context, kind: visit::FnKind, decl: &ast::FnDecl,
                block: &ast::Block, _span: codemap::Span, id: ast::NodeId) {
        match kind {
            visit::FkItemFn(i, _, _, _, _, _) |
            visit::FkMethod(i, _, _) if i.name.as_str() == "new"
                                        || i.name.as_str() == "new_inherited"
                                        || i.name.as_str() == "new_initialized" => {
                self.in_new_function = true;
                return;
            },
            visit::FkItemFn(_, _, style, _, _, _) => match style {
                ast::Unsafety::Unsafe => return,
                _ => ()
            },
            _ => ()
        }
        self.in_new_function = false;

        if unsafe_context(&cx.tcx.map, id) {
            return;
        }

        match block.rules {
            ast::DefaultBlock => {
                for arg in decl.inputs.iter() {
                    ast_ty_to_prim_ty(cx.tcx, &*arg.ty).map(|t| {
                        if is_unrooted_ty(cx, t, false) {
                            cx.span_lint(UNROOTED_MUST_ROOT, arg.ty.span, "Type must be rooted")
                        }
                    });
                }
            }
            _ => () // fn is `unsafe`
        }
    }

    /// Trait casts from #[must_root] types are not allowed
    fn check_expr(&mut self, cx: &Context, expr: &ast::Expr) {
        fn require_rooted(cx: &Context, in_new_function: bool, subexpr: &ast::Expr) {
            let ty = cx.tcx.expr_ty(&*subexpr);
            if is_unrooted_ty(cx, ty, in_new_function) {
                cx.span_lint(UNROOTED_MUST_ROOT,
                             subexpr.span,
                             &format!("Expression of type {:?} must be rooted", ty))
            }
        };

        match expr.node {
            ast::ExprCast(ref subexpr, _) => require_rooted(cx, self.in_new_function, &*subexpr),
            _ => {
                // TODO(pcwalton): Check generics with a whitelist of allowed generics.
            }
        }
    }

    // Partially copied from rustc::middle::lint::builtin
    // Catches `let` statements and assignments which store a #[must_root] value
    // Expressions which return out of blocks eventually end up in a `let` or assignment
    // statement or a function return (which will be caught when it is used elsewhere)
    fn check_stmt(&mut self, cx: &Context, s: &ast::Stmt) {
        match s.node {
            ast::StmtDecl(_, id) |
            ast::StmtExpr(_, id) |
            ast::StmtSemi(_, id) if unsafe_context(&cx.tcx.map, id) => {
                return
            },
            _ => ()
        };

        let expr = match s.node {
            // Catch a `let` binding
            ast::StmtDecl(ref decl, _) => match decl.node {
                ast::DeclLocal(ref loc) => match loc.init {
                    Some(ref e) => &**e,
                    _ => return
                },
                _ => return
            },
            ast::StmtExpr(ref expr, _) => match expr.node {
                // This catches deferred `let` statements
                ast::ExprAssign(_, ref e) |
                // Match statements allow you to bind onto the variable later in an arm
                // We need not check arms individually since enum/struct fields are already
                // linted in `check_struct_def` and `check_variant`
                // (so there is no way of destructuring out a `#[must_root]` field)
                ast::ExprMatch(ref e, _, _) |
                // For loops allow you to bind a return value locally
                ast::ExprForLoop(_, ref e, _, _) => &**e,
                // XXXManishearth look into `if let` once it lands in our rustc
                _ => return
            },
            _ => return
        };

        let ty = cx.tcx.expr_ty(&*expr);
        if is_unrooted_ty(cx, ty, self.in_new_function) {
            cx.span_lint(UNROOTED_MUST_ROOT, expr.span,
                                     &format!("Expression of type {:?} must be rooted", ty))
        }
    }
}
<|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.

//! Overlap: No two impls for the same trait are implemented for the
//! same type.

use middle::cstore::{CrateStore, LOCAL_CRATE};
use middle::def_id::DefId;
use middle::traits;
use middle::ty;
use middle::infer;
use syntax::ast;
use syntax::codemap::Span;
use rustc_front::hir;
use rustc_front::intravisit;
use util::nodemap::DefIdMap;

pub fn check(tcx: &ty::ctxt) {
    let mut overlap = OverlapChecker { tcx: tcx, default_impls: DefIdMap() };
    overlap.check_for_overlapping_impls();

    // this secondary walk specifically checks for some other cases,
    // like defaulted traits, for which additional overlap rules exist
    tcx.map.krate().visit_all_items(&mut overlap);
}

struct OverlapChecker<'cx, 'tcx:'cx> {
    tcx: &'cx ty::ctxt<'tcx>,

    // maps from a trait def-id to an impl id
    default_impls: DefIdMap<ast::NodeId>,
}

impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
    fn check_for_overlapping_impls(&self) {
        debug!("check_for_overlapping_impls");

        // Collect this into a vector to avoid holding the
        // refcell-lock during the
        // check_for_overlapping_impls_of_trait() check, since that
        // check can populate this table further with impls from other
        // crates.
        let trait_defs: Vec<_> = self.tcx.trait_defs.borrow().values().cloned().collect();

        for trait_def in trait_defs {
            self.tcx.populate_implementations_for_trait_if_necessary(trait_def.trait_ref.def_id);
            self.check_for_overlapping_impls_of_trait(trait_def);
        }
    }

    fn check_for_overlapping_impls_of_trait(&self,
                                            trait_def: &'tcx ty::TraitDef<'tcx>)
    {
        debug!("check_for_overlapping_impls_of_trait(trait_def={:?})",
               trait_def);

        // We should already know all impls of this trait, so these
        // borrows are safe.
        let blanket_impls = trait_def.blanket_impls.borrow();
        let nonblanket_impls = trait_def.nonblanket_impls.borrow();

        // Conflicts can only occur between a blanket impl and another impl,
        // or between 2 non-blanket impls of the same kind.

        for (i, &impl1_def_id) in blanket_impls.iter().enumerate() {
            for &impl2_def_id in &blanket_impls[(i+1)..] {
                self.check_if_impls_overlap(impl1_def_id,
                                            impl2_def_id);
            }

            for v in nonblanket_impls.values() {
                for &impl2_def_id in v {
                    self.check_if_impls_overlap(impl1_def_id,
                                                impl2_def_id);
                }
            }
        }

        for impl_group in nonblanket_impls.values() {
            for (i, &impl1_def_id) in impl_group.iter().enumerate() {
                for &impl2_def_id in &impl_group[(i+1)..] {
                    self.check_if_impls_overlap(impl1_def_id,
                                                impl2_def_id);
                }
            }
        }
    }

    // We need to coherently pick which impl will be displayed
    // as causing the error message, and it must be the in the current
    // crate. Just pick the smaller impl in the file.
    fn order_impls(&self, impl1_def_id: DefId, impl2_def_id: DefId)
            -> Option<(DefId, DefId)> {
        if impl1_def_id.krate != LOCAL_CRATE {
            if impl2_def_id.krate != LOCAL_CRATE {
                // we don't need to check impls if both are external;
                // that's the other crate's job.
                None
            } else {
                Some((impl2_def_id, impl1_def_id))
            }
        } else if impl2_def_id.krate != LOCAL_CRATE {
            Some((impl1_def_id, impl2_def_id))
        } else if impl1_def_id < impl2_def_id {
            Some((impl1_def_id, impl2_def_id))
        } else {
            Some((impl2_def_id, impl1_def_id))
        }
    }

    fn check_if_impls_overlap(&self,
                              impl1_def_id: DefId,
                              impl2_def_id: DefId)
    {
        if let Some((impl1_def_id, impl2_def_id)) = self.order_impls(
            impl1_def_id, impl2_def_id)
        {
            debug!("check_if_impls_overlap({:?}, {:?})",
                   impl1_def_id,
                   impl2_def_id);

            let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None, false);
            if let Some(trait_ref) = traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) {
                self.report_overlap_error(impl1_def_id, impl2_def_id, trait_ref);
            }
        }
    }

    fn report_overlap_error(&self,
                            impl1: DefId,
                            impl2: DefId,
                            trait_ref: ty::TraitRef)
    {
        // only print the Self type if it's concrete; otherwise, it's not adding much information.
        let self_type = {
            trait_ref.substs.self_ty().and_then(|ty| {
                if let ty::TyInfer(_) = ty.sty {
                    None
                } else {
                    Some(format!(" for type `{}`", ty))
                }
            }).unwrap_or(String::new())
        };

        let mut err = struct_span_err!(self.tcx.sess, self.span_of_impl(impl1), E0119,
                                       "conflicting implementations of trait `{}`{}:",
                                       trait_ref,
                                       self_type);

        if impl2.is_local() {
            span_note!(&mut err, self.span_of_impl(impl2),
                       "conflicting implementation is here:");
        } else {
            let cname = self.tcx.sess.cstore.crate_name(impl2.krate);
            err.note(&format!("conflicting implementation in crate `{}`", cname));
        }
        err.emit();
    }

    fn span_of_impl(&self, impl_did: DefId) -> Span {
        let node_id = self.tcx.map.as_local_node_id(impl_did).unwrap();
        self.tcx.map.span(node_id)
    }
}

impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
    fn visit_item(&mut self, item: &'v hir::Item) {
        match item.node {
            hir::ItemDefaultImpl(_, _) => {
                // look for another default impl; note that due to the
                // general orphan/coherence rules, it must always be
                // in this crate.
                let impl_def_id = self.tcx.map.local_def_id(item.id);
                let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
                let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id);
                match prev_default_impl {
                    Some(prev_id) => {
                        self.report_overlap_error(impl_def_id,
                                                  self.tcx.map.local_def_id(prev_id),
                                                  trait_ref);
                    }
                    None => { }
                }
            }
            hir::ItemImpl(_, _, _, Some(_), _, _) => {
                let impl_def_id = self.tcx.map.local_def_id(item.id);
                let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
                let trait_def_id = trait_ref.def_id;
                match trait_ref.self_ty().sty {
                    ty::TyTrait(ref data) => {
                        // This is something like impl Trait1 for Trait2. Illegal
                        // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.

                        if !traits::is_object_safe(self.tcx, data.principal_def_id()) {
                            // This is an error, but it will be
                            // reported by wfcheck.  Ignore it
                            // here. This is tested by
                            // `coherence-impl-trait-for-trait-object-safe.rs`.
                        } else {
                            let mut supertrait_def_ids =
                                traits::supertrait_def_ids(self.tcx, data.principal_def_id());
                            if supertrait_def_ids.any(|d| d == trait_def_id) {
                                span_err!(self.tcx.sess, item.span, E0371,
                                          "the object type `{}` automatically \
                                           implements the trait `{}`",
                                          trait_ref.self_ty(),
                                          self.tcx.item_path_str(trait_def_id));
                            }
                        }
                    }
                    _ => { }
                }
            }
            _ => {
            }
        }
    }
}
<commit_msg>Refactor overlap checker so that it walks the HIR instead of poking into random tables. The old code was weird anyway because it would potentially walk traits from other crates etc. The new code fits seamlessly with the dependency tracking.<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.

//! Overlap: No two impls for the same trait are implemented for the
//! same type.

use middle::cstore::{CrateStore, LOCAL_CRATE};
use middle::def_id::DefId;
use middle::traits;
use middle::ty;
use middle::infer;
use syntax::ast;
use syntax::codemap::Span;
use rustc::dep_graph::DepNode;
use rustc_front::hir;
use rustc_front::intravisit;
use util::nodemap::{DefIdMap, DefIdSet};

pub fn check(tcx: &ty::ctxt) {
    let mut overlap = OverlapChecker { tcx: tcx,
                                       traits_checked: DefIdSet(),
                                       default_impls: DefIdMap() };

    // this secondary walk specifically checks for some other cases,
    // like defaulted traits, for which additional overlap rules exist
    tcx.visit_all_items_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap);
}

struct OverlapChecker<'cx, 'tcx:'cx> {
    tcx: &'cx ty::ctxt<'tcx>,

    // The set of traits where we have checked for overlap.  This is
    // used to avoid checking the same trait twice.
    //
    // NB. It's ok to skip tracking this set because we fully
    // encapsulate it, and we always create a task
    // (`CoherenceOverlapCheck`) corresponding to each entry.
    traits_checked: DefIdSet,

    // maps from a trait def-id to an impl id
    default_impls: DefIdMap<ast::NodeId>,
}

impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
    fn check_for_overlapping_impls_of_trait(&mut self, trait_def_id: DefId) {
        debug!("check_for_overlapping_impls_of_trait(trait_def_id={:?})",
               trait_def_id);

        let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id));
        if !self.traits_checked.insert(trait_def_id) {
            return;
        }

        let trait_def = self.tcx.lookup_trait_def(trait_def_id);
        self.tcx.populate_implementations_for_trait_if_necessary(
            trait_def.trait_ref.def_id);

        // We should already know all impls of this trait, so these
        // borrows are safe.
        let (blanket_impls, nonblanket_impls) = trait_def.borrow_impl_lists(self.tcx);

        // Conflicts can only occur between a blanket impl and another impl,
        // or between 2 non-blanket impls of the same kind.

        for (i, &impl1_def_id) in blanket_impls.iter().enumerate() {
            for &impl2_def_id in &blanket_impls[(i+1)..] {
                self.check_if_impls_overlap(impl1_def_id,
                                            impl2_def_id);
            }

            for v in nonblanket_impls.values() {
                for &impl2_def_id in v {
                    self.check_if_impls_overlap(impl1_def_id,
                                                impl2_def_id);
                }
            }
        }

        for impl_group in nonblanket_impls.values() {
            for (i, &impl1_def_id) in impl_group.iter().enumerate() {
                for &impl2_def_id in &impl_group[(i+1)..] {
                    self.check_if_impls_overlap(impl1_def_id,
                                                impl2_def_id);
                }
            }
        }
    }

    // We need to coherently pick which impl will be displayed
    // as causing the error message, and it must be the in the current
    // crate. Just pick the smaller impl in the file.
    fn order_impls(&self, impl1_def_id: DefId, impl2_def_id: DefId)
            -> Option<(DefId, DefId)> {
        if impl1_def_id.krate != LOCAL_CRATE {
            if impl2_def_id.krate != LOCAL_CRATE {
                // we don't need to check impls if both are external;
                // that's the other crate's job.
                None
            } else {
                Some((impl2_def_id, impl1_def_id))
            }
        } else if impl2_def_id.krate != LOCAL_CRATE {
            Some((impl1_def_id, impl2_def_id))
        } else if impl1_def_id < impl2_def_id {
            Some((impl1_def_id, impl2_def_id))
        } else {
            Some((impl2_def_id, impl1_def_id))
        }
    }

    fn check_if_impls_overlap(&self,
                              impl1_def_id: DefId,
                              impl2_def_id: DefId)
    {
        if let Some((impl1_def_id, impl2_def_id)) = self.order_impls(
            impl1_def_id, impl2_def_id)
        {
            debug!("check_if_impls_overlap({:?}, {:?})",
                   impl1_def_id,
                   impl2_def_id);

            let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None, false);
            if let Some(trait_ref) = traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) {
                self.report_overlap_error(impl1_def_id, impl2_def_id, trait_ref);
            }
        }
    }

    fn report_overlap_error(&self,
                            impl1: DefId,
                            impl2: DefId,
                            trait_ref: ty::TraitRef)
    {
        // only print the Self type if it's concrete; otherwise, it's not adding much information.
        let self_type = {
            trait_ref.substs.self_ty().and_then(|ty| {
                if let ty::TyInfer(_) = ty.sty {
                    None
                } else {
                    Some(format!(" for type `{}`", ty))
                }
            }).unwrap_or(String::new())
        };

        let mut err = struct_span_err!(self.tcx.sess, self.span_of_impl(impl1), E0119,
                                       "conflicting implementations of trait `{}`{}:",
                                       trait_ref,
                                       self_type);

        if impl2.is_local() {
            span_note!(&mut err, self.span_of_impl(impl2),
                       "conflicting implementation is here:");
        } else {
            let cname = self.tcx.sess.cstore.crate_name(impl2.krate);
            err.note(&format!("conflicting implementation in crate `{}`", cname));
        }
        err.emit();
    }

    fn span_of_impl(&self, impl_did: DefId) -> Span {
        let node_id = self.tcx.map.as_local_node_id(impl_did).unwrap();
        self.tcx.map.span(node_id)
    }
}

impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
    fn visit_item(&mut self, item: &'v hir::Item) {
        match item.node {
            hir::ItemTrait(..) => {
                let trait_def_id = self.tcx.map.local_def_id(item.id);
                self.check_for_overlapping_impls_of_trait(trait_def_id);
            }

            hir::ItemDefaultImpl(..) => {
                // look for another default impl; note that due to the
                // general orphan/coherence rules, it must always be
                // in this crate.
                let impl_def_id = self.tcx.map.local_def_id(item.id);
                let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();

                self.check_for_overlapping_impls_of_trait(trait_ref.def_id);

                let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id);
                match prev_default_impl {
                    Some(prev_id) => {
                        self.report_overlap_error(impl_def_id,
                                                  self.tcx.map.local_def_id(prev_id),
                                                  trait_ref);
                    }
                    None => { }
                }
            }
            hir::ItemImpl(_, _, _, Some(_), _, _) => {
                let impl_def_id = self.tcx.map.local_def_id(item.id);
                let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
                let trait_def_id = trait_ref.def_id;
                self.check_for_overlapping_impls_of_trait(trait_def_id);
                match trait_ref.self_ty().sty {
                    ty::TyTrait(ref data) => {
                        // This is something like impl Trait1 for Trait2. Illegal
                        // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.

                        if !traits::is_object_safe(self.tcx, data.principal_def_id()) {
                            // This is an error, but it will be
                            // reported by wfcheck.  Ignore it
                            // here. This is tested by
                            // `coherence-impl-trait-for-trait-object-safe.rs`.
                        } else {
                            let mut supertrait_def_ids =
                                traits::supertrait_def_ids(self.tcx, data.principal_def_id());
                            if supertrait_def_ids.any(|d| d == trait_def_id) {
                                span_err!(self.tcx.sess, item.span, E0371,
                                          "the object type `{}` automatically \
                                           implements the trait `{}`",
                                          trait_ref.self_ty(),
                                          self.tcx.item_path_str(trait_def_id));
                            }
                        }
                    }
                    _ => { }
                }
            }
            _ => {
            }
        }
    }
}
<|endoftext|>


<commit_before>// Unfortunately, the test framework does not support 'only-linux',
// so we need to ignore Windows and macOS instead.
// ignore-macos: Uses Linux-only APIs
// ignore-windows: Uses Linux-only APIs
// compile-flags: -Zmiri-disable-isolation

#![feature(rustc_private)]
extern crate libc;

use std::ptr;
use std::thread;
use std::time::{Duration, Instant};

fn wake_nobody() {
    let futex = 0;

    // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &futex as *const i32,
            libc::FUTEX_WAKE,
            1,
        ), 0);
    }

    // Same, but without omitting the unused arguments.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &futex as *const i32,
            libc::FUTEX_WAKE,
            1,
            0,
            0,
            0,
        ), 0);
    }
}

fn wake_dangling() {
    let futex = Box::new(0);
    let ptr: *const i32 = &*futex;
    drop(futex);

    // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            ptr,
            libc::FUTEX_WAKE,
            1,
        ), 0);
    }
}

fn wait_wrong_val() {
    let futex: i32 = 123;

    // Only wait if the futex value is 456.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &futex as *const i32,
            libc::FUTEX_WAIT,
            456,
            ptr::null::<libc::timespec>(),
        ), -1);
        assert_eq!(*libc::__errno_location(), libc::EAGAIN);
    }
}

fn wait_timeout() {
    let start = Instant::now();

    let futex: i32 = 123;

    // Wait for 200ms, with nobody waking us up early.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &futex as *const i32,
            libc::FUTEX_WAIT,
            123,
            &libc::timespec {
                tv_sec: 0,
                tv_nsec: 200_000_000,
            },
        ), -1);
        assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT);
    }

    assert!((200..1000).contains(&start.elapsed().as_millis()));
}

fn wait_wake() {
    let start = Instant::now();

    static FUTEX: i32 = 0;

    thread::spawn(move || {
        thread::sleep(Duration::from_millis(200));
        unsafe {
            assert_eq!(libc::syscall(
                libc::SYS_futex,
                &FUTEX as *const i32,
                libc::FUTEX_WAKE,
                10, // Wake up at most 10 threads.
            ), 1); // Woken up one thread.
        }
    });

    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &FUTEX as *const i32,
            libc::FUTEX_WAIT,
            0,
            ptr::null::<libc::timespec>(),
        ), 0);
    }

    assert!((200..1000).contains(&start.elapsed().as_millis()));
}

fn main() {
    wake_nobody();
    wake_dangling();
    wait_wrong_val();
    wait_timeout();
    wait_wake();
}
<commit_msg>Add test for FUTEX_WAIT_BITSET.<commit_after>// Unfortunately, the test framework does not support 'only-linux',
// so we need to ignore Windows and macOS instead.
// ignore-macos: Uses Linux-only APIs
// ignore-windows: Uses Linux-only APIs
// compile-flags: -Zmiri-disable-isolation

#![feature(rustc_private)]
extern crate libc;

use std::mem::MaybeUninit;
use std::ptr;
use std::thread;
use std::time::{Duration, Instant};

fn wake_nobody() {
    let futex = 0;

    // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &futex as *const i32,
            libc::FUTEX_WAKE,
            1,
        ), 0);
    }

    // Same, but without omitting the unused arguments.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &futex as *const i32,
            libc::FUTEX_WAKE,
            1,
            0,
            0,
            0,
        ), 0);
    }
}

fn wake_dangling() {
    let futex = Box::new(0);
    let ptr: *const i32 = &*futex;
    drop(futex);

    // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            ptr,
            libc::FUTEX_WAKE,
            1,
        ), 0);
    }
}

fn wait_wrong_val() {
    let futex: i32 = 123;

    // Only wait if the futex value is 456.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &futex as *const i32,
            libc::FUTEX_WAIT,
            456,
            ptr::null::<libc::timespec>(),
        ), -1);
        assert_eq!(*libc::__errno_location(), libc::EAGAIN);
    }
}

fn wait_timeout() {
    let start = Instant::now();

    let futex: i32 = 123;

    // Wait for 200ms, with nobody waking us up early.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &futex as *const i32,
            libc::FUTEX_WAIT,
            123,
            &libc::timespec {
                tv_sec: 0,
                tv_nsec: 200_000_000,
            },
        ), -1);
        assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT);
    }

    assert!((200..1000).contains(&start.elapsed().as_millis()));
}

fn wait_absolute_timeout() {
    let start = Instant::now();

    // Get the current monotonic timestamp as timespec.
    let mut timeout = unsafe {
        let mut now: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
        assert_eq!(libc::clock_gettime(libc::CLOCK_MONOTONIC, now.as_mut_ptr()), 0);
        now.assume_init()
    };

    // Add 200ms.
    timeout.tv_nsec += 200_000_000;
    if timeout.tv_nsec > 1_000_000_000 {
        timeout.tv_nsec -= 1_000_000_000;
        timeout.tv_sec += 1;
    }

    let futex: i32 = 123;

    // Wait for 200ms from now, with nobody waking us up early.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &futex as *const i32,
            libc::FUTEX_WAIT_BITSET,
            123,
            &timeout,
            0,
            u32::MAX,
        ), -1);
        assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT);
    }

    assert!((200..1000).contains(&start.elapsed().as_millis()));
}

fn wait_wake() {
    let start = Instant::now();

    static FUTEX: i32 = 0;

    thread::spawn(move || {
        thread::sleep(Duration::from_millis(200));
        unsafe {
            assert_eq!(libc::syscall(
                libc::SYS_futex,
                &FUTEX as *const i32,
                libc::FUTEX_WAKE,
                10, // Wake up at most 10 threads.
            ), 1); // Woken up one thread.
        }
    });

    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &FUTEX as *const i32,
            libc::FUTEX_WAIT,
            0,
            ptr::null::<libc::timespec>(),
        ), 0);
    }

    assert!((200..1000).contains(&start.elapsed().as_millis()));
}

fn main() {
    wake_nobody();
    wake_dangling();
    wait_wrong_val();
    wait_timeout();
    wait_absolute_timeout();
    wait_wake();
}
<|endoftext|>


<commit_before>use super::Cli;
use std::fs::{metadata, remove_file};
use std::io::ErrorKind;
use std::path::PathBuf;
use std::process::Command;

fn get_platform_architecture(platform: &str) -> Option<&'static str> {
    match platform {
        "raspberrypi_pico" | "nano_rp2040_connect" => Some("cortex-m0"),
        "apollo3"
        | "clue_nrf52840"
        | "hail"
        | "imix"
        | "microbit_v2"
        | "msp432"
        | "nano33bl3"
        | "nrf52"
        | "nrf52840"
        | "nucleo_f429zi"
        | "nucleo_f446re"
        | "stm32f3discovery"
        | "stm32f412gdiscovery" => Some("cortex-m4"),
        "imxrt1050" | "teensy40" => Some("cortex-m7"),
        "opentitan" | "esp32_c3_devkitm_1" => Some("riscv32imc"),
        "hifive1" => Some("riscv32imac"),
        _ => None,
    }
}

// Converts the ELF file specified on the command line into TBF and TAB files,
// and returns the paths to those files.
pub fn convert_elf(cli: &Cli, platform: &str) -> OutFiles {
    let package_name = cli.elf.file_stem().expect("ELF must be a file");
    let mut tab_path = cli.elf.clone();
    tab_path.set_extension("tab");
    let protected_size = TBF_HEADER_SIZE.to_string();
    if cli.verbose {
        println!("Package name: {:?}", package_name);
        println!("TAB path: {}", tab_path.display());
        println!("Protected region size: {}", protected_size);
    }
    let stack_size = read_stack_size(cli);
    let elf = cli.elf.as_os_str();
    let mut tbf_path = cli.elf.clone();
    tbf_path.set_extension("tbf");
    let architecture =
        get_platform_architecture(platform).expect("Failed to determine ELF's architecture");
    if cli.verbose {
        println!("ELF file: {:?}", elf);
        println!("TBF path: {}", tbf_path.display());
    }

    // If elf2tab returns a successful status but does not write to the TBF
    // file, then we run the risk of using an outdated TBF file, creating a
    // hard-to-debug situation. Therefore, we delete the TBF file, forcing
    // elf2tab to create it, and later verify that it exists.
    if let Err(io_error) = remove_file(&tbf_path) {
        // Ignore file-no-found errors, panic on any other error.
        if io_error.kind() != ErrorKind::NotFound {
            panic!("Unable to remove the TBF file. Error: {}", io_error);
        }
    }

    let mut command = Command::new("elf2tab");

    #[rustfmt::skip]
    command.args([
        // TODO: libtock-rs' crates are designed for Tock 2.1's Allow interface,
        // so we should increment this as soon as the Tock kernel will accept a
        // 2.1 app.
        "--kernel-major".as_ref(), "2".as_ref(),
        "--kernel-minor".as_ref(), "0".as_ref(),
        "-n".as_ref(), package_name,
        "-o".as_ref(), tab_path.as_os_str(),
        "--protected-region-size".as_ref(), protected_size.as_ref(),
        "--stack".as_ref(), stack_size.as_ref(),
        format!("{},{}", elf.to_str().unwrap(), architecture).as_ref(),
    ]);
    if cli.verbose {
        command.arg("-v");
        println!("elf2tab command: {:?}", command);
        println!("Spawning elf2tab");
    }
    let mut child = command.spawn().expect("failed to spawn elf2tab");
    let status = child.wait().expect("failed to wait for elf2tab");
    if cli.verbose {
        println!("elf2tab finished. {}", status);
    }
    assert!(status.success(), "elf2tab returned an error. {}", status);

    // Verify that elf2tab created the TBF file, and that it is a file.
    match metadata(&tbf_path) {
        Err(io_error) => {
            if io_error.kind() == ErrorKind::NotFound {
                panic!("elf2tab did not create {}", tbf_path.display());
            }
            panic!(
                "Unable to query metadata for {}: {}",
                tbf_path.display(),
                io_error
            );
        }
        Ok(metadata) => {
            assert!(metadata.is_file(), "{} is not a file", tbf_path.display());
        }
    }

    OutFiles { tab_path, tbf_path }
}

// Paths to the files output by elf2tab.
pub struct OutFiles {
    pub tab_path: PathBuf,
    pub tbf_path: PathBuf,
}

// The amount of space to reserve for the TBF header. This must match the
// TBF_HEADER_SIZE value in the layout file for the platform, which is currently
// 0x48 for all platforms.
const TBF_HEADER_SIZE: u32 = 0x48;

// Reads the stack size, and returns it as a String for use on elf2tab's command
// line.
fn read_stack_size(cli: &Cli) -> String {
    let file = elf::File::open_path(&cli.elf).expect("Unable to open ELF");
    for section in file.sections {
        // This section name comes from runtime/libtock_layout.ld, and it
        // matches the size (and location) of the process binary's stack.
        if section.shdr.name == ".stack" {
            let stack_size = section.shdr.size.to_string();
            if cli.verbose {
                println!("Found .stack section, size: {}", stack_size);
            }
            return stack_size;
        }
    }

    panic!("Unable to find the .stack section in {}", cli.elf.display());
}
<commit_msg>format<commit_after>use super::Cli;
use std::fs::{metadata, remove_file};
use std::io::ErrorKind;
use std::path::PathBuf;
use std::process::Command;

fn get_platform_architecture(platform: &str) -> Option<&'static str> {
    match platform {
        "raspberrypi_pico" | "nano_rp2040_connect" => Some("cortex-m0"),
        "apollo3"
        | "clue_nrf52840"
        | "hail"
        | "imix"
        | "microbit_v2"
        | "msp432"
        | "nano33bl3"
        | "nrf52"
        | "nrf52840"
        | "nucleo_f429zi"
        | "nucleo_f446re"
        | "stm32f3discovery"
        | "stm32f412gdiscovery" => Some("cortex-m4"),
        "imxrt1050" | "teensy40" => Some("cortex-m7"),
        "opentitan" | "esp32_c3_devkitm_1" => Some("riscv32imc"),
        "hifive1" => Some("riscv32imac"),
        _ => None,
    }
}

// Converts the ELF file specified on the command line into TBF and TAB files,
// and returns the paths to those files.
pub fn convert_elf(cli: &Cli, platform: &str) -> OutFiles {
    let package_name = cli.elf.file_stem().expect("ELF must be a file");
    let mut tab_path = cli.elf.clone();
    tab_path.set_extension("tab");
    let protected_size = TBF_HEADER_SIZE.to_string();
    if cli.verbose {
        println!("Package name: {:?}", package_name);
        println!("TAB path: {}", tab_path.display());
        println!("Protected region size: {}", protected_size);
    }
    let stack_size = read_stack_size(cli);
    let elf = cli.elf.as_os_str();
    let mut tbf_path = cli.elf.clone();
    tbf_path.set_extension("tbf");
    let architecture =
        get_platform_architecture(platform).expect("Failed to determine ELF's architecture");
    if cli.verbose {
        println!("ELF file: {:?}", elf);
        println!("TBF path: {}", tbf_path.display());
    }

    // If elf2tab returns a successful status but does not write to the TBF
    // file, then we run the risk of using an outdated TBF file, creating a
    // hard-to-debug situation. Therefore, we delete the TBF file, forcing
    // elf2tab to create it, and later verify that it exists.
    if let Err(io_error) = remove_file(&tbf_path) {
        // Ignore file-no-found errors, panic on any other error.
        if io_error.kind() != ErrorKind::NotFound {
            panic!("Unable to remove the TBF file. Error: {}", io_error);
        }
    }

    let mut command = Command::new("elf2tab");
    #[rustfmt::skip]
    command.args([
        // TODO: libtock-rs' crates are designed for Tock 2.1's Allow interface,
        // so we should increment this as soon as the Tock kernel will accept a
        // 2.1 app.
        "--kernel-major".as_ref(), "2".as_ref(),
        "--kernel-minor".as_ref(), "0".as_ref(),
        "-n".as_ref(), package_name,
        "-o".as_ref(), tab_path.as_os_str(),
        "--protected-region-size".as_ref(), protected_size.as_ref(),
        "--stack".as_ref(), stack_size.as_ref(),
        format!("{},{}", elf.to_str().unwrap(), architecture).as_ref(),
    ]);
    if cli.verbose {
        command.arg("-v");
        println!("elf2tab command: {:?}", command);
        println!("Spawning elf2tab");
    }
    let mut child = command.spawn().expect("failed to spawn elf2tab");
    let status = child.wait().expect("failed to wait for elf2tab");
    if cli.verbose {
        println!("elf2tab finished. {}", status);
    }
    assert!(status.success(), "elf2tab returned an error. {}", status);

    // Verify that elf2tab created the TBF file, and that it is a file.
    match metadata(&tbf_path) {
        Err(io_error) => {
            if io_error.kind() == ErrorKind::NotFound {
                panic!("elf2tab did not create {}", tbf_path.display());
            }
            panic!(
                "Unable to query metadata for {}: {}",
                tbf_path.display(),
                io_error
            );
        }
        Ok(metadata) => {
            assert!(metadata.is_file(), "{} is not a file", tbf_path.display());
        }
    }

    OutFiles { tab_path, tbf_path }
}

// Paths to the files output by elf2tab.
pub struct OutFiles {
    pub tab_path: PathBuf,
    pub tbf_path: PathBuf,
}

// The amount of space to reserve for the TBF header. This must match the
// TBF_HEADER_SIZE value in the layout file for the platform, which is currently
// 0x48 for all platforms.
const TBF_HEADER_SIZE: u32 = 0x48;

// Reads the stack size, and returns it as a String for use on elf2tab's command
// line.
fn read_stack_size(cli: &Cli) -> String {
    let file = elf::File::open_path(&cli.elf).expect("Unable to open ELF");
    for section in file.sections {
        // This section name comes from runtime/libtock_layout.ld, and it
        // matches the size (and location) of the process binary's stack.
        if section.shdr.name == ".stack" {
            let stack_size = section.shdr.size.to_string();
            if cli.verbose {
                println!("Found .stack section, size: {}", stack_size);
            }
            return stack_size;
        }
    }

    panic!("Unable to find the .stack section in {}", cli.elf.display());
}
<|endoftext|>


<commit_before>
use std::cmp::PartialEq;

//

pub fn append_vectors_once<'a, T : PartialEq + Copy, F : FnMut(T)>( dst : &'a mut Vec<T>, src : &'a Vec<Vec<T>>, on_evaluate : Option<F> ) -> &'a mut Vec<T>
{
  if on_evaluate.is_none()
  {
    for vec in src
    {
      for el in vec
      {
        if !dst.contains( el )
        {
          dst.push( *el );
        }
      }
    }
  }
  else
  {
    unimplemented!( "callbacks is not implemented" );
  }

  dst
}

//

pub fn left_index<'a, T : PartialEq + Copy, F : FnMut(&'a T, &'a T) -> bool>( src : &'a Vec<T>, el : &'a T, on_equalize : Option<F> ) -> Option<usize>
{
  if on_equalize.is_none()
  {
    return src.iter().position( | &x | x == *el );
  }
  else
  {
    let mut equalizer = on_equalize.unwrap();
    for x in 0..src.len()
    {
      if equalizer( &src[ x ], el )
      {
        return Some( x );
      }
    }
    return None
    // unimplemented!( "not implemented for callbacks" );
  }
}

<commit_msg>Add structure `left_index`, implement trait `Default` for structure, implement method `call`<commit_after>
#![ allow( non_camel_case_types ) ]

use std::cmp::PartialEq;

//

pub fn append_vectors_once<'a, T : PartialEq + Copy, F : FnMut(T)>( dst : &'a mut Vec<T>, src : &'a Vec<Vec<T>>, on_evaluate : Option<F> ) -> &'a mut Vec<T>
{
  if on_evaluate.is_none()
  {
    for vec in src
    {
      for el in vec
      {
        if !dst.contains( el )
        {
          dst.push( *el );
        }
      }
    }
  }
  else
  {
    unimplemented!( "callbacks is not implemented" );
  }

  dst
}

//

pub struct left_index<T>
{
  src : Vec<T>,
  ins : T,
  start_from : usize,
  on_evaluate1 : Option<fn(&T) -> T>,
  on_evaluate2 : Option<fn(&T) -> T>,
  on_equalize : Option<fn(&T, &T) -> bool>,
  formed : u8,
}

//

impl<T : std::default::Default> Default for left_index<T>
{
  fn default() -> Self
  {
    let opts = Self
    {
      src : vec![],
      ins : Default::default(),
      start_from : 0,
      on_evaluate1 : None,
      on_evaluate2 : None,
      on_equalize : None,
      formed : 0,
    };
    return opts;
  }
}

impl<T : PartialEq + Copy +  Clone> left_index<T>
{
  pub fn src( &mut self, src : Vec<T> ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.src = src;
    self
  }

  //

  pub fn ins( &mut self, ins : T ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.ins = ins;
    self
  }

  //

  pub fn start_from( &mut self, start_from : usize ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.start_from = start_from;
    self
  }

  //

  pub fn on_equalize( &mut self, on_equalize : fn( &T, &T ) -> bool ) -> &mut Self
  {
    assert!( self.on_evaluate1.is_none() && self.on_evaluate2.is_none(), "Expects no evaluation callbacks." );
    assert!( self.formed == 0, "Context is already formed" );
    self.on_equalize = Some( on_equalize );
    self
  }

  //

  pub fn on_evaluate1( &mut self, on_evaluate1 : fn( &T ) -> T ) -> &mut Self
  {
    assert!( self.on_equalize.is_none(), "Expects no equalizer callback." );
    assert!( self.formed == 0, "Context is already formed" );
    self.on_evaluate1 = Some( on_evaluate1 );
    self
  }

  //

  pub fn on_evaluate2( &mut self, on_evaluate2 : fn( &T ) -> T ) -> &mut Self
  {
    assert!( self.on_equalize.is_none(), "Expects no equalizer callback." );
    assert!( self.formed == 0, "Context is already formed" );
    self.on_evaluate2 = Some( on_evaluate2 );
    self
  }

  //

  pub fn form( self ) -> Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    Self { formed : 1, .. self }
  }

  //

  pub fn call( &self ) -> Option<usize>
  {
    if self.on_equalize.is_some()
    {
      let mut equalizer = self.on_equalize.unwrap();
      for i in 0..self.src.len()
      {
        if equalizer( &self.src[ i ], &self.ins )
        {
          return Some( i );
        }
      }
    }
    else if self.on_evaluate1.is_some()
    {
      let mut ins;
      let evaluate1 = self.on_evaluate1.unwrap();

      if self.on_evaluate2.is_some()
      {
        let evaluate2 = self.on_evaluate2.unwrap();
        ins = evaluate2( &self.ins );
      }
      else
      {
        ins = evaluate1( &self.ins );
      }

      for i in self.start_from..self.src.len()
      {
        if evaluate1( &self.src[ i ] ) == ins
        {
          return Some( i );
        }
      }
    }
    else
    {
      assert!( self.on_evaluate2.is_none(), "Expects callback {-on_evaluate1-}." );
      return self.src.iter().position( | &x | x == self.ins );
    }

    None
  }
}

<|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.

use rustc::infer::canonical::{Canonical, QueryResult};
use rustc::traits::query::type_op::prove_predicate::ProvePredicate;
use rustc::traits::query::NoSolution;
use rustc::traits::{FulfillmentContext, Obligation, ObligationCause, TraitEngine};
use rustc::ty::TyCtxt;
use rustc_data_structures::sync::Lrc;
use syntax::codemap::DUMMY_SP;

crate fn type_op_prove_predicate<'tcx>(
    tcx: TyCtxt<'_, 'tcx, 'tcx>,
    canonicalized: Canonical<'tcx, ProvePredicate<'tcx>>,
) -> Result<Lrc<Canonical<'tcx, QueryResult<'tcx, ()>>>, NoSolution> {
    let tcx = tcx.global_tcx();
    tcx.infer_ctxt().enter(|ref infcx| {
        let (ProvePredicate { param_env, predicate }, canonical_inference_vars) =
            infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonicalized);
        let fulfill_cx = &mut FulfillmentContext::new();
        let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
        fulfill_cx.register_predicate_obligation(infcx, obligation);
        infcx.make_canonicalized_query_result(canonical_inference_vars, (), fulfill_cx)
    })
}
<commit_msg>use query boilerplate for prove-predicate -- slightly inefficient<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.

use rustc::infer::InferOk;
use rustc::infer::canonical::{Canonical, QueryResult};
use rustc::traits::query::type_op::prove_predicate::ProvePredicate;
use rustc::traits::query::NoSolution;
use rustc::traits::{Obligation, ObligationCause};
use rustc::ty::TyCtxt;
use rustc_data_structures::sync::Lrc;

crate fn type_op_prove_predicate<'tcx>(
    tcx: TyCtxt<'_, 'tcx, 'tcx>,
    canonicalized: Canonical<'tcx, ProvePredicate<'tcx>>,
) -> Result<Lrc<Canonical<'tcx, QueryResult<'tcx, ()>>>, NoSolution> {
    tcx.infer_ctxt()
        .enter_canonical_trait_query(&canonicalized, |_infcx, key| {
            let ProvePredicate {
                param_env,
                predicate,
            } = key;
            Ok(InferOk {
                value: (),
                obligations: vec![Obligation::new(
                    ObligationCause::dummy(),
                    param_env,
                    predicate,
                )],
            })
        })
}
<|endoftext|>


<commit_before>use std::borrow::Borrow;
use std::io;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::cmp::min;

pub use mio::{EventSet, PollOpt, Token};
use mio::Timeout as MioTimeout;
use mio::tcp::{TcpListener, TcpStream};
use mio::util::Slab;

use super::connection::{IncomingConnection, OutgoingConnection};
use super::{Timeout, InternalTimeout, EventLoop};

use super::super::messages::{MessageBuffer, RawMessage};

pub type PeerId = Token;

const SERVER_ID: PeerId = Token(1);
const RECONNECT_GROW_FACTOR: f32 = 2.0;

#[derive(Debug)]
pub enum Output {
    Data(MessageBuffer),
    Connected(SocketAddr),
    Disconnected(SocketAddr),
}

#[derive(Debug, Clone, Copy)]
pub struct NetworkConfiguration {
    // TODO: think more about config parameters
    pub listen_address: SocketAddr,
    pub max_incoming_connections: usize,
    pub max_outgoing_connections: usize,
    pub tcp_nodelay: bool,
    pub tcp_keep_alive: Option<u32>,
    pub tcp_reconnect_timeout: u64,
    pub tcp_reconnect_timeout_max: u64,
}

pub struct Network {
    config: NetworkConfiguration,
    listener: Option<TcpListener>,

    incoming: Slab<IncomingConnection>,
    outgoing: Slab<OutgoingConnection>,
    addresses: HashMap<SocketAddr, PeerId>,

    reconnects: HashMap<SocketAddr, MioTimeout>,
}

enum PeerKind {
    Server,
    Incoming,
    Outgoing,
}

fn make_error<T: Borrow<str>>(s: T) -> io::Error {
    io::Error::new(io::ErrorKind::Other, s.borrow())
}

impl Network {
    pub fn with_config(config: NetworkConfiguration) -> Network {
        Network {
            config: config,
            listener: None,

            incoming: Slab::new_starting_at(Token(2), config.max_incoming_connections),
            outgoing: Slab::new_starting_at(Token(2 + config.max_incoming_connections),
                                            config.max_outgoing_connections),
            addresses: HashMap::new(),

            reconnects: HashMap::new(),
        }
    }

    pub fn address(&self) -> &SocketAddr {
        &self.config.listen_address
    }

    // TODO use error trait
    pub fn bind(&mut self, event_loop: &mut EventLoop) -> io::Result<()> {
        if let Some(_) = self.listener {
            return Err(make_error("Already binded"));
        }
        let listener = TcpListener::bind(&self.config.listen_address)?;
        event_loop.register(&listener, SERVER_ID, EventSet::readable(), PollOpt::edge())?;
        self.listener = Some(listener);
        Ok(())
    }

    // TODO: Use ticks for fast reregistering sockets
    // TODO: Implement Connections collection with (re)registering
    pub fn io(&mut self,
              event_loop: &mut EventLoop,
              id: PeerId,
              set: EventSet)
              -> io::Result<Option<Output>> {

        match self.peer_kind(id) {
            PeerKind::Server => {
                // Accept new connections
                // FIXME: Fail-safe accepting of new connections?
                let pair = match self.listener {
                    Some(ref listener) => listener.accept()?,
                    None => None,
                };
                if let Some((socket, address)) = pair {
                    let peer = IncomingConnection::new(socket, address);
                    self.add_incoming_connection(event_loop, peer)?;

                    debug!("{}: Accepted incoming connection from {} id: {}",
                           self.address(),
                           address,
                           id.0);
                }
                return Ok(None);
            }
            PeerKind::Incoming => {
                if !self.incoming.contains(id) {
                    return Ok(None);
                }

                if set.is_hup() | set.is_error() {
                    debug!("{}: incoming connection with addr {} closed",
                           self.address(),
                           self.incoming[id].address());

                    self.remove_incoming_connection(event_loop, id);
                    return Ok(None);
                }

                if set.is_readable() {
                    let address = *self.incoming[id].address();

                    trace!("{}: Socket is readable {} id: {}",
                           self.address(),
                           address,
                           id.0);

                    return match self.incoming[id].try_read() {
                        Ok(Some(buffer)) => Ok(Some(Output::Data(buffer))),
                        Ok(None) => Ok(None),
                        Err(e) => {
                            self.remove_incoming_connection(event_loop, id);
                            Err(e)
                        }
                    };
                }
            }
            PeerKind::Outgoing => {
                if !self.outgoing.contains(id) {
                    return Ok(None);
                }

                if set.is_hup() | set.is_error() {
                    let address = *self.outgoing[id].address();

                    debug!("{}: outgoing connection with addr {} closed",
                           self.address(),
                           self.outgoing[id].address());

                    self.remove_outgoing_connection(event_loop, id);
                    if self.reconnects.contains_key(&address) {
                        return Ok(None);
                    }
                    return Ok(Some(Output::Disconnected(address)));
                }

                if set.is_writable() {
                    let address = *self.outgoing[id].address();

                    trace!("{}: Socket is writable {} id: {}",
                           self.address(),
                           address,
                           id.0);

                    let r = {
                        self.outgoing[id].try_write()?;
                        event_loop.reregister(self.outgoing[id].socket(),
                                        id,
                                        self.outgoing[id].interest(),
                                        PollOpt::edge())?;
                        Ok(())
                    };

                    // Write data into socket
                    if let Err(e) = r {
                        self.remove_outgoing_connection(event_loop, id);
                        return Err(e);
                    }
                    return Ok(self.mark_connected(event_loop, id));
                }
            }
        }
        // FIXME: Can we be here?
        Ok(None)
    }

    pub fn tick(&mut self, _: &mut EventLoop) {}

    pub fn send_to(&mut self,
                   event_loop: &mut EventLoop,
                   address: &SocketAddr,
                   message: RawMessage)
                   -> io::Result<()> {
        let r = match self.get_outgoing_peer(address) {
            Ok(id) => {
                self.outgoing[id]
                    .send(message)
                    .and_then(|_| {
                        event_loop.reregister(self.outgoing[id].socket(),
                                        id,
                                        self.outgoing[id].interest(),
                                        PollOpt::edge())?;
                        self.mark_connected(event_loop, id);
                        Ok(())
                    })
                    .or_else(|e| {
                        self.remove_outgoing_connection(event_loop, id);
                        Err(e)
                    })
            }
            Err(e) => Err(e),
        };
        r
    }

    pub fn connect(&mut self, event_loop: &mut EventLoop, address: &SocketAddr) -> io::Result<()> {
        if !self.addresses.contains_key(address) {
            let peer = OutgoingConnection::new(TcpStream::connect(address)?, *address);
            let id = self.add_outgoing_connection(event_loop, peer)?;
            self.try_reconnect_addr(event_loop, *address)?;

            debug!("{}: Establish connection with {}, id: {}",
                   self.address(),
                   address,
                   id.0);
        }
        Ok(())
    }

    pub fn handle_timeout(&mut self, event_loop: &mut EventLoop, timeout: InternalTimeout) {
        match timeout {
            InternalTimeout::Reconnect(addr, delay) => {
                if self.reconnects.contains_key(&addr) {
                    debug!("Try to reconnect with delay {}", delay);

                    if let Err(e) = self.connect(event_loop, &addr) {
                        error!("{}: Unable to create connection to addr {}, error: {:?}",
                               self.address(),
                               addr,
                               e);
                    }

                    let delay = min((delay as f32 * RECONNECT_GROW_FACTOR) as u64,
                                    self.config.tcp_reconnect_timeout_max);

                    if let Err(e) = self.add_reconnect_timeout(event_loop, addr, delay) {
                        error!("{}: Unable to add timeout, error: {:?}", self.address(), e);
                    }
                }
            }
        }
    }

    fn peer_kind(&self, id: PeerId) -> PeerKind {
        if id == SERVER_ID {
            PeerKind::Server
        } else if id.0 >= (2 + self.config.max_incoming_connections) {
            PeerKind::Outgoing
        } else {
            PeerKind::Incoming
        }
    }

    fn get_outgoing_peer(&self, addr: &SocketAddr) -> io::Result<PeerId> {
        if let Some(id) = self.addresses.get(addr) {
            return Ok(*id);
        };
        Err(make_error(format!("{}: Outgoing peer not found {}", self.address(), addr)))
    }

    fn add_incoming_connection(&mut self,
                               event_loop: &mut EventLoop,
                               mut connection: IncomingConnection)
                               -> io::Result<PeerId> {
        self.configure_stream(connection.socket_mut())?;
        let address = *connection.address();
        let id = self.incoming
            .insert(connection)
            .map_err(|_| make_error("Maximum incoming onnections"))?;
        self.addresses.insert(address, id);

        let r = event_loop.register(self.incoming[id].socket(),
                                    id,
                                    self.incoming[id].interest(),
                                    PollOpt::edge());

        if let Err(e) = r {
            self.remove_incoming_connection(event_loop, id);
            return Err(e);
        }
        Ok(id)
    }

    fn add_outgoing_connection(&mut self,
                               event_loop: &mut EventLoop,
                               connection: OutgoingConnection)
                               -> io::Result<PeerId> {
        let address = *connection.address();
        let id = self.outgoing
            .insert(connection)
            .map_err(|_| make_error("Maximum outgoing onnections"))?;
        self.addresses.insert(address, id);

        let r = event_loop.register(self.outgoing[id].socket(),
                                    id,
                                    self.outgoing[id].interest() | EventSet::writable(),
                                    PollOpt::edge());

        if let Err(e) = r {
            self.remove_outgoing_connection(event_loop, id);
            return Err(e);
        }
        Ok(id)
    }

    fn remove_incoming_connection(&mut self, event_loop: &mut EventLoop, id: PeerId) {
        let addr = *self.incoming[id].address();
        self.addresses.remove(&addr);
        if let Some(connection) = self.incoming.remove(id) {
            if let Err(e) = event_loop.deregister(connection.socket()) {
                error!("{}: Unable to deregister incoming connection, id: {}, error: {:?}",
                       self.address(),
                       id.0,
                       e);
            }
        }
    }

    fn remove_outgoing_connection(&mut self, event_loop: &mut EventLoop, id: PeerId) {
        let addr = *self.outgoing[id].address();
        self.addresses.remove(&addr);
        if let Some(connection) = self.outgoing.remove(id) {
            if let Err(e) = event_loop.deregister(connection.socket()) {
                error!("{}: Unable to deregister outgoing connection, id: {}, error: {:?}",
                       self.address(),
                       id.0,
                       e);
            }
        }
    }

    fn configure_stream(&self, stream: &mut TcpStream) -> io::Result<()> {
        stream.set_keepalive(self.config.tcp_keep_alive)?;
        stream.set_nodelay(self.config.tcp_nodelay)
    }

    fn try_reconnect_addr(&mut self,
                          event_loop: &mut EventLoop,
                          address: SocketAddr)
                          -> io::Result<()> {
        if !self.reconnects.contains_key(&address) {
            let delay = self.config.tcp_reconnect_timeout;
            return self.add_reconnect_timeout(event_loop, address, delay);
        }
        Ok(())
    }

    fn add_reconnect_timeout(&mut self,
                             event_loop: &mut EventLoop,
                             address: SocketAddr,
                             delay: u64)
                             -> io::Result<()> {
        let reconnect = Timeout::Internal(InternalTimeout::Reconnect(address, delay));
        let timeout = event_loop.timeout_ms(reconnect, delay)
            .map_err(|e| make_error(format!("A mio error occured {:?}", e)))?;
        self.reconnects.insert(address, timeout);
        Ok(())
    }

    fn mark_connected(&mut self, event_loop: &mut EventLoop, id: Token) -> Option<Output> {
        let address = *self.outgoing[id].address();
        self.clear_reconnect_request(event_loop, &address)
    }

    fn clear_reconnect_request(&mut self,
                               event_loop: &mut EventLoop,
                               addr: &SocketAddr)
                               -> Option<Output> {
        if let Some(timeout) = self.reconnects.remove(addr) {
            event_loop.clear_timeout(timeout);
            return Some(Output::Connected(*addr));
        }
        None
    }
}

#[cfg(test)]
mod tests {}
<commit_msg>Add TODOs<commit_after>use std::borrow::Borrow;
use std::io;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::cmp::min;

pub use mio::{EventSet, PollOpt, Token};
use mio::Timeout as MioTimeout;
use mio::tcp::{TcpListener, TcpStream};
use mio::util::Slab;

use super::connection::{IncomingConnection, OutgoingConnection};
use super::{Timeout, InternalTimeout, EventLoop};

use super::super::messages::{MessageBuffer, RawMessage};

pub type PeerId = Token;

const SERVER_ID: PeerId = Token(1);
const RECONNECT_GROW_FACTOR: f32 = 2.0;

#[derive(Debug)]
pub enum Output {
    Data(MessageBuffer),
    Connected(SocketAddr),
    Disconnected(SocketAddr),
}

#[derive(Debug, Clone, Copy)]
pub struct NetworkConfiguration {
    // TODO: think more about config parameters
    pub listen_address: SocketAddr,
    pub max_incoming_connections: usize,
    pub max_outgoing_connections: usize,
    pub tcp_nodelay: bool,
    pub tcp_keep_alive: Option<u32>,
    pub tcp_reconnect_timeout: u64,
    pub tcp_reconnect_timeout_max: u64,
}

// TODO Implement generic ConnectionPool struct to avoid copy paste.
// Write proper code to configure outgoing streams
pub struct Network {
    config: NetworkConfiguration,
    listener: Option<TcpListener>,

    incoming: Slab<IncomingConnection>,
    outgoing: Slab<OutgoingConnection>,
    //FIXME addresses only needs for outgoing connections
    addresses: HashMap<SocketAddr, PeerId>,

    reconnects: HashMap<SocketAddr, MioTimeout>,
}

enum PeerKind {
    Server,
    Incoming,
    Outgoing,
}

fn make_error<T: Borrow<str>>(s: T) -> io::Error {
    io::Error::new(io::ErrorKind::Other, s.borrow())
}

impl Network {
    pub fn with_config(config: NetworkConfiguration) -> Network {
        Network {
            config: config,
            listener: None,

            incoming: Slab::new_starting_at(Token(2), config.max_incoming_connections),
            outgoing: Slab::new_starting_at(Token(2 + config.max_incoming_connections),
                                            config.max_outgoing_connections),
            addresses: HashMap::new(),

            reconnects: HashMap::new(),
        }
    }

    pub fn address(&self) -> &SocketAddr {
        &self.config.listen_address
    }

    // TODO use error trait
    pub fn bind(&mut self, event_loop: &mut EventLoop) -> io::Result<()> {
        if let Some(_) = self.listener {
            return Err(make_error("Already binded"));
        }
        let listener = TcpListener::bind(&self.config.listen_address)?;
        event_loop.register(&listener, SERVER_ID, EventSet::readable(), PollOpt::edge())?;
        self.listener = Some(listener);
        Ok(())
    }

    // TODO: Use ticks for fast reregistering sockets
    // TODO: Implement Connections collection with (re)registering
    pub fn io(&mut self,
              event_loop: &mut EventLoop,
              id: PeerId,
              set: EventSet)
              -> io::Result<Option<Output>> {

        match self.peer_kind(id) {
            PeerKind::Server => {
                // Accept new connections
                // FIXME: Fail-safe accepting of new connections?
                let pair = match self.listener {
                    Some(ref listener) => listener.accept()?,
                    None => None,
                };
                if let Some((socket, address)) = pair {
                    let peer = IncomingConnection::new(socket, address);
                    self.add_incoming_connection(event_loop, peer)?;

                    debug!("{}: Accepted incoming connection from {} id: {}",
                           self.address(),
                           address,
                           id.0);
                }
                return Ok(None);
            }
            PeerKind::Incoming => {
                if !self.incoming.contains(id) {
                    return Ok(None);
                }

                if set.is_hup() | set.is_error() {
                    debug!("{}: incoming connection with addr {} closed",
                           self.address(),
                           self.incoming[id].address());

                    self.remove_incoming_connection(event_loop, id);
                    return Ok(None);
                }

                if set.is_readable() {
                    let address = *self.incoming[id].address();

                    trace!("{}: Socket is readable {} id: {}",
                           self.address(),
                           address,
                           id.0);

                    return match self.incoming[id].try_read() {
                        Ok(Some(buffer)) => Ok(Some(Output::Data(buffer))),
                        Ok(None) => Ok(None),
                        Err(e) => {
                            self.remove_incoming_connection(event_loop, id);
                            Err(e)
                        }
                    };
                }
            }
            PeerKind::Outgoing => {
                if !self.outgoing.contains(id) {
                    return Ok(None);
                }

                if set.is_hup() | set.is_error() {
                    let address = *self.outgoing[id].address();

                    debug!("{}: outgoing connection with addr {} closed",
                           self.address(),
                           self.outgoing[id].address());

                    self.remove_outgoing_connection(event_loop, id);
                    if self.reconnects.contains_key(&address) {
                        return Ok(None);
                    }
                    return Ok(Some(Output::Disconnected(address)));
                }

                if set.is_writable() {
                    let address = *self.outgoing[id].address();

                    trace!("{}: Socket is writable {} id: {}",
                           self.address(),
                           address,
                           id.0);

                    let r = {
                        self.outgoing[id].try_write()?;
                        event_loop.reregister(self.outgoing[id].socket(),
                                        id,
                                        self.outgoing[id].interest(),
                                        PollOpt::edge())?;
                        Ok(())
                    };

                    // Write data into socket
                    if let Err(e) = r {
                        self.remove_outgoing_connection(event_loop, id);
                        return Err(e);
                    }
                    return Ok(self.mark_connected(event_loop, id));
                }
            }
        }
        // FIXME: Can we be here?
        Ok(None)
    }

    pub fn tick(&mut self, _: &mut EventLoop) {}

    pub fn send_to(&mut self,
                   event_loop: &mut EventLoop,
                   address: &SocketAddr,
                   message: RawMessage)
                   -> io::Result<()> {
        let r = match self.get_outgoing_peer(address) {
            Ok(id) => {
                self.outgoing[id]
                    .send(message)
                    .and_then(|_| {
                        event_loop.reregister(self.outgoing[id].socket(),
                                        id,
                                        self.outgoing[id].interest(),
                                        PollOpt::edge())?;
                        self.mark_connected(event_loop, id);
                        Ok(())
                    })
                    .or_else(|e| {
                        self.remove_outgoing_connection(event_loop, id);
                        Err(e)
                    })
            }
            Err(e) => Err(e),
        };
        r
    }

    pub fn connect(&mut self, event_loop: &mut EventLoop, address: &SocketAddr) -> io::Result<()> {
        if !self.addresses.contains_key(address) {
            let peer = OutgoingConnection::new(TcpStream::connect(address)?, *address);
            let id = self.add_outgoing_connection(event_loop, peer)?;
            self.try_reconnect_addr(event_loop, *address)?;

            debug!("{}: Establish connection with {}, id: {}",
                   self.address(),
                   address,
                   id.0);
        }
        Ok(())
    }

    pub fn handle_timeout(&mut self, event_loop: &mut EventLoop, timeout: InternalTimeout) {
        match timeout {
            InternalTimeout::Reconnect(addr, delay) => {
                if self.reconnects.contains_key(&addr) {
                    debug!("Try to reconnect with delay {}", delay);

                    if let Err(e) = self.connect(event_loop, &addr) {
                        error!("{}: Unable to create connection to addr {}, error: {:?}",
                               self.address(),
                               addr,
                               e);
                    }

                    let delay = min((delay as f32 * RECONNECT_GROW_FACTOR) as u64,
                                    self.config.tcp_reconnect_timeout_max);

                    if let Err(e) = self.add_reconnect_timeout(event_loop, addr, delay) {
                        error!("{}: Unable to add timeout, error: {:?}", self.address(), e);
                    }
                }
            }
        }
    }

    fn peer_kind(&self, id: PeerId) -> PeerKind {
        if id == SERVER_ID {
            PeerKind::Server
        } else if id.0 >= (2 + self.config.max_incoming_connections) {
            PeerKind::Outgoing
        } else {
            PeerKind::Incoming
        }
    }

    fn get_outgoing_peer(&self, addr: &SocketAddr) -> io::Result<PeerId> {
        if let Some(id) = self.addresses.get(addr) {
            return Ok(*id);
        };
        Err(make_error(format!("{}: Outgoing peer not found {}", self.address(), addr)))
    }

    fn add_incoming_connection(&mut self,
                               event_loop: &mut EventLoop,
                               mut connection: IncomingConnection)
                               -> io::Result<PeerId> {
        self.configure_stream(connection.socket_mut())?;
        let address = *connection.address();
        let id = self.incoming
            .insert(connection)
            .map_err(|_| make_error("Maximum incoming onnections"))?;
        self.addresses.insert(address, id);

        let r = event_loop.register(self.incoming[id].socket(),
                                    id,
                                    self.incoming[id].interest(),
                                    PollOpt::edge());

        if let Err(e) = r {
            self.remove_incoming_connection(event_loop, id);
            return Err(e);
        }
        Ok(id)
    }

    fn add_outgoing_connection(&mut self,
                               event_loop: &mut EventLoop,
                               connection: OutgoingConnection)
                               -> io::Result<PeerId> {
        let address = *connection.address();
        let id = self.outgoing
            .insert(connection)
            .map_err(|_| make_error("Maximum outgoing onnections"))?;
        self.addresses.insert(address, id);

        let r = event_loop.register(self.outgoing[id].socket(),
                                    id,
                                    self.outgoing[id].interest() | EventSet::writable(),
                                    PollOpt::edge());

        if let Err(e) = r {
            self.remove_outgoing_connection(event_loop, id);
            return Err(e);
        }
        Ok(id)
    }

    fn remove_incoming_connection(&mut self, event_loop: &mut EventLoop, id: PeerId) {
        let addr = *self.incoming[id].address();
        self.addresses.remove(&addr);
        if let Some(connection) = self.incoming.remove(id) {
            if let Err(e) = event_loop.deregister(connection.socket()) {
                error!("{}: Unable to deregister incoming connection, id: {}, error: {:?}",
                       self.address(),
                       id.0,
                       e);
            }
        }
    }

    fn remove_outgoing_connection(&mut self, event_loop: &mut EventLoop, id: PeerId) {
        let addr = *self.outgoing[id].address();
        self.addresses.remove(&addr);
        if let Some(connection) = self.outgoing.remove(id) {
            if let Err(e) = event_loop.deregister(connection.socket()) {
                error!("{}: Unable to deregister outgoing connection, id: {}, error: {:?}",
                       self.address(),
                       id.0,
                       e);
            }
        }
    }

    fn configure_stream(&self, stream: &mut TcpStream) -> io::Result<()> {
        stream.set_keepalive(self.config.tcp_keep_alive)?;
        stream.set_nodelay(self.config.tcp_nodelay)
    }

    fn try_reconnect_addr(&mut self,
                          event_loop: &mut EventLoop,
                          address: SocketAddr)
                          -> io::Result<()> {
        if !self.reconnects.contains_key(&address) {
            let delay = self.config.tcp_reconnect_timeout;
            return self.add_reconnect_timeout(event_loop, address, delay);
        }
        Ok(())
    }

    fn add_reconnect_timeout(&mut self,
                             event_loop: &mut EventLoop,
                             address: SocketAddr,
                             delay: u64)
                             -> io::Result<()> {
        let reconnect = Timeout::Internal(InternalTimeout::Reconnect(address, delay));
        let timeout = event_loop.timeout_ms(reconnect, delay)
            .map_err(|e| make_error(format!("A mio error occured {:?}", e)))?;
        self.reconnects.insert(address, timeout);
        Ok(())
    }

    fn mark_connected(&mut self, event_loop: &mut EventLoop, id: Token) -> Option<Output> {
        let address = *self.outgoing[id].address();
        self.clear_reconnect_request(event_loop, &address)
    }

    fn clear_reconnect_request(&mut self,
                               event_loop: &mut EventLoop,
                               addr: &SocketAddr)
                               -> Option<Output> {
        if let Some(timeout) = self.reconnects.remove(addr) {
            event_loop.clear_timeout(timeout);
            return Some(Output::Connected(*addr));
        }
        None
    }
}

#[cfg(test)]
mod tests {}
<|endoftext|>