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

// Logic and data structures related to impl specialization, explained in
// greater detail below.
//
// At the moment, this implementation support only the simple "chain" rule:
// If any two impls overlap, one must be a strict subset of the other.
//
// See traits/README.md for a bit more detail on how specialization
// fits together with the rest of the trait machinery.

use super::{SelectionContext, FulfillmentContext};
use super::util::impl_trait_ref_and_oblig;

use rustc_data_structures::fnv::FnvHashMap;
use hir::def_id::DefId;
use infer::{InferCtxt, TypeOrigin};
use middle::region;
use ty::subst::{Subst, Substs};
use traits::{self, Reveal, ObligationCause, Normalized};
use ty::{self, TyCtxt, TypeFoldable};
use syntax_pos::DUMMY_SP;

use syntax::ast;

pub mod specialization_graph;

/// Information pertinent to an overlapping impl error.
pub struct OverlapError {
    pub with_impl: DefId,
    pub trait_desc: String,
    pub self_desc: Option<String>
}

/// Given a subst for the requested impl, translate it to a subst
/// appropriate for the actual item definition (whether it be in that impl,
/// a parent impl, or the trait).
/// When we have selected one impl, but are actually using item definitions from
/// a parent impl providing a default, we need a way to translate between the
/// type parameters of the two impls. Here the `source_impl` is the one we've
/// selected, and `source_substs` is a substitution of its generics.
/// And `target_node` is the impl/trait we're actually going to get the
/// definition from. The resulting substitution will map from `target_node`'s
/// generics to `source_impl`'s generics as instantiated by `source_subst`.
///
/// For example, consider the following scenario:
///
/// ```rust
/// trait Foo { ... }
/// impl<T, U> Foo for (T, U) { ... }  // target impl
/// impl<V> Foo for (V, V) { ... }     // source impl
/// ```
///
/// Suppose we have selected "source impl" with `V` instantiated with `u32`.
/// This function will produce a substitution with `T` and `U` both mapping to `u32`.
///
/// Where clauses add some trickiness here, because they can be used to "define"
/// an argument indirectly:
///
/// ```rust
/// impl<'a, I, T: 'a> Iterator for Cloned<I>
///    where I: Iterator<Item=&'a T>, T: Clone
/// ```
///
/// In a case like this, the substitution for `T` is determined indirectly,
/// through associated type projection. We deal with such cases by using
/// *fulfillment* to relate the two impls, requiring that all projections are
/// resolved.
pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                        source_impl: DefId,
                                        source_substs: &'tcx Substs<'tcx>,
                                        target_node: specialization_graph::Node)
                                        -> &'tcx Substs<'tcx> {
    let source_trait_ref = infcx.tcx
                                .impl_trait_ref(source_impl)
                                .unwrap()
                                .subst(infcx.tcx, &source_substs);

    // translate the Self and TyParam parts of the substitution, since those
    // vary across impls
    let target_substs = match target_node {
        specialization_graph::Node::Impl(target_impl) => {
            // no need to translate if we're targetting the impl we started with
            if source_impl == target_impl {
                return source_substs;
            }

            fulfill_implication(infcx, source_trait_ref, target_impl).unwrap_or_else(|_| {
                bug!("When translating substitutions for specialization, the expected \
                      specializaiton failed to hold")
            })
        }
        specialization_graph::Node::Trait(..) => source_trait_ref.substs,
    };

    // directly inherent the method generics, since those do not vary across impls
    source_substs.rebase_onto(infcx.tcx, source_impl, target_substs)
}

/// Given a selected impl described by `impl_data`, returns the
/// definition and substitions for the method with the name `name`,
/// and trait method substitutions `substs`, in that impl, a less
/// specialized impl, or the trait default, whichever applies.
pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             name: ast::Name,
                             substs: &'tcx Substs<'tcx>,
                             impl_data: &super::VtableImplData<'tcx, ()>)
                             -> (DefId, &'tcx Substs<'tcx>)
{
    assert!(!substs.needs_infer());

    let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap();
    let trait_def = tcx.lookup_trait_def(trait_def_id);

    match trait_def.ancestors(impl_data.impl_def_id).fn_defs(tcx, name).next() {
        Some(node_item) => {
            let substs = tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
                let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
                let substs = translate_substs(&infcx, impl_data.impl_def_id,
                                              substs, node_item.node);
                tcx.lift(&substs).unwrap_or_else(|| {
                    bug!("find_method: translate_substs \
                          returned {:?} which contains inference types/regions",
                         substs);
                })
            });
            (node_item.item.def_id, substs)
        }
        None => {
            bug!("method {:?} not found in {:?}", name, impl_data.impl_def_id)
        }
    }
}

/// Is impl1 a specialization of impl2?
///
/// Specialization is determined by the sets of types to which the impls apply;
/// impl1 specializes impl2 if it applies to a subset of the types impl2 applies
/// to.
pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             impl1_def_id: DefId,
                             impl2_def_id: DefId) -> bool {
    if let Some(r) = tcx.specializes_cache.borrow().check(impl1_def_id, impl2_def_id) {
        return r;
    }

    // The feature gate should prevent introducing new specializations, but not
    // taking advantage of upstream ones.
    if !tcx.sess.features.borrow().specialization &&
        (impl1_def_id.is_local() || impl2_def_id.is_local()) {
        return false;
    }

    // We determine whether there's a subset relationship by:
    //
    // - skolemizing impl1,
    // - assuming the where clauses for impl1,
    // - instantiating impl2 with fresh inference variables,
    // - unifying,
    // - attempting to prove the where clauses for impl2
    //
    // The last three steps are encapsulated in `fulfill_implication`.
    //
    // See RFC 1210 for more details and justification.

    // Currently we do not allow e.g. a negative impl to specialize a positive one
    if tcx.trait_impl_polarity(impl1_def_id) != tcx.trait_impl_polarity(impl2_def_id) {
        return false;
    }

    // create a parameter environment corresponding to a (skolemized) instantiation of impl1
    let mut penv = tcx.construct_parameter_environment(DUMMY_SP,
                                                       impl1_def_id,
                                                       region::DUMMY_CODE_EXTENT);
    let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id)
                             .unwrap()
                             .subst(tcx, &penv.free_substs);

    let result = tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|mut infcx| {
        // Normalize the trait reference, adding any obligations
        // that arise into the impl1 assumptions.
        let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = {
            let selcx = &mut SelectionContext::new(&infcx);
            traits::normalize(selcx, ObligationCause::dummy(), &impl1_trait_ref)
        };
        penv.caller_bounds.extend(normalization_obligations.into_iter().map(|o| {
            match tcx.lift_to_global(&o.predicate) {
                Some(predicate) => predicate,
                None => {
                    bug!("specializes: obligation `{:?}` has inference types/regions", o);
                }
            }
        }));

        // Install the parameter environment, taking the predicates of impl1 as assumptions:
        infcx.parameter_environment = penv;

        // Attempt to prove that impl2 applies, given all of the above.
        fulfill_implication(&infcx, impl1_trait_ref, impl2_def_id).is_ok()
    });

    tcx.specializes_cache.borrow_mut().insert(impl1_def_id, impl2_def_id, result);
    result
}

/// Attempt to fulfill all obligations of `target_impl` after unification with
/// `source_trait_ref`. If successful, returns a substitution for *all* the
/// generics of `target_impl`, including both those needed to unify with
/// `source_trait_ref` and those whose identity is determined via a where
/// clause in the impl.
fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                       source_trait_ref: ty::TraitRef<'tcx>,
                                       target_impl: DefId)
                                       -> Result<&'tcx Substs<'tcx>, ()> {
    let selcx = &mut SelectionContext::new(&infcx);
    let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl);
    let (target_trait_ref, obligations) = impl_trait_ref_and_oblig(selcx,
                                                                   target_impl,
                                                                   target_substs);

    // do the impls unify? If not, no specialization.
    if let Err(_) = infcx.eq_trait_refs(true,
                                        TypeOrigin::Misc(DUMMY_SP),
                                        source_trait_ref,
                                        target_trait_ref) {
        debug!("fulfill_implication: {:?} does not unify with {:?}",
               source_trait_ref,
               target_trait_ref);
        return Err(());
    }

    // attempt to prove all of the predicates for impl2 given those for impl1
    // (which are packed up in penv)

    infcx.save_and_restore_obligations_in_snapshot_flag(|infcx| {
        let mut fulfill_cx = FulfillmentContext::new();
        for oblig in obligations.into_iter() {
            fulfill_cx.register_predicate_obligation(&infcx, oblig);
        }
        match fulfill_cx.select_all_or_error(infcx) {
            Err(errors) => {
                // no dice!
                debug!("fulfill_implication: for impls on {:?} and {:?}, \
                        could not fulfill: {:?} given {:?}",
                       source_trait_ref,
                       target_trait_ref,
                       errors,
                       infcx.parameter_environment.caller_bounds);
                Err(())
            }

            Ok(()) => {
                debug!("fulfill_implication: an impl for {:?} specializes {:?}",
                       source_trait_ref,
                       target_trait_ref);

                // Now resolve the *substitution* we built for the target earlier, replacing
                // the inference variables inside with whatever we got from fulfillment.
                Ok(infcx.resolve_type_vars_if_possible(&target_substs))
            }
        }
    })
}

pub struct SpecializesCache {
    map: FnvHashMap<(DefId, DefId), bool>
}

impl SpecializesCache {
    pub fn new() -> Self {
        SpecializesCache {
            map: FnvHashMap()
        }
    }

    pub fn check(&self, a: DefId, b: DefId) -> Option<bool> {
        self.map.get(&(a, b)).cloned()
    }

    pub fn insert(&mut self, a: DefId, b: DefId, result: bool) {
        self.map.insert((a, b), result);
    }
}
<commit_msg>normalize trait-ref in context of impl<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.

// Logic and data structures related to impl specialization, explained in
// greater detail below.
//
// At the moment, this implementation support only the simple "chain" rule:
// If any two impls overlap, one must be a strict subset of the other.
//
// See traits/README.md for a bit more detail on how specialization
// fits together with the rest of the trait machinery.

use super::{SelectionContext, FulfillmentContext};
use super::util::impl_trait_ref_and_oblig;

use rustc_data_structures::fnv::FnvHashMap;
use hir::def_id::DefId;
use infer::{InferCtxt, TypeOrigin};
use middle::region;
use ty::subst::{Subst, Substs};
use traits::{self, Reveal, ObligationCause, Normalized};
use ty::{self, TyCtxt, TypeFoldable};
use syntax_pos::DUMMY_SP;

use syntax::ast;

pub mod specialization_graph;

/// Information pertinent to an overlapping impl error.
pub struct OverlapError {
    pub with_impl: DefId,
    pub trait_desc: String,
    pub self_desc: Option<String>
}

/// Given a subst for the requested impl, translate it to a subst
/// appropriate for the actual item definition (whether it be in that impl,
/// a parent impl, or the trait).
/// When we have selected one impl, but are actually using item definitions from
/// a parent impl providing a default, we need a way to translate between the
/// type parameters of the two impls. Here the `source_impl` is the one we've
/// selected, and `source_substs` is a substitution of its generics.
/// And `target_node` is the impl/trait we're actually going to get the
/// definition from. The resulting substitution will map from `target_node`'s
/// generics to `source_impl`'s generics as instantiated by `source_subst`.
///
/// For example, consider the following scenario:
///
/// ```rust
/// trait Foo { ... }
/// impl<T, U> Foo for (T, U) { ... }  // target impl
/// impl<V> Foo for (V, V) { ... }     // source impl
/// ```
///
/// Suppose we have selected "source impl" with `V` instantiated with `u32`.
/// This function will produce a substitution with `T` and `U` both mapping to `u32`.
///
/// Where clauses add some trickiness here, because they can be used to "define"
/// an argument indirectly:
///
/// ```rust
/// impl<'a, I, T: 'a> Iterator for Cloned<I>
///    where I: Iterator<Item=&'a T>, T: Clone
/// ```
///
/// In a case like this, the substitution for `T` is determined indirectly,
/// through associated type projection. We deal with such cases by using
/// *fulfillment* to relate the two impls, requiring that all projections are
/// resolved.
pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                        source_impl: DefId,
                                        source_substs: &'tcx Substs<'tcx>,
                                        target_node: specialization_graph::Node)
                                        -> &'tcx Substs<'tcx> {
    let source_trait_ref = infcx.tcx
                                .impl_trait_ref(source_impl)
                                .unwrap()
                                .subst(infcx.tcx, &source_substs);

    // translate the Self and TyParam parts of the substitution, since those
    // vary across impls
    let target_substs = match target_node {
        specialization_graph::Node::Impl(target_impl) => {
            // no need to translate if we're targetting the impl we started with
            if source_impl == target_impl {
                return source_substs;
            }

            fulfill_implication(infcx, source_trait_ref, target_impl).unwrap_or_else(|_| {
                bug!("When translating substitutions for specialization, the expected \
                      specializaiton failed to hold")
            })
        }
        specialization_graph::Node::Trait(..) => source_trait_ref.substs,
    };

    // directly inherent the method generics, since those do not vary across impls
    source_substs.rebase_onto(infcx.tcx, source_impl, target_substs)
}

/// Given a selected impl described by `impl_data`, returns the
/// definition and substitions for the method with the name `name`,
/// and trait method substitutions `substs`, in that impl, a less
/// specialized impl, or the trait default, whichever applies.
pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             name: ast::Name,
                             substs: &'tcx Substs<'tcx>,
                             impl_data: &super::VtableImplData<'tcx, ()>)
                             -> (DefId, &'tcx Substs<'tcx>)
{
    assert!(!substs.needs_infer());

    let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap();
    let trait_def = tcx.lookup_trait_def(trait_def_id);

    match trait_def.ancestors(impl_data.impl_def_id).fn_defs(tcx, name).next() {
        Some(node_item) => {
            let substs = tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
                let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
                let substs = translate_substs(&infcx, impl_data.impl_def_id,
                                              substs, node_item.node);
                tcx.lift(&substs).unwrap_or_else(|| {
                    bug!("find_method: translate_substs \
                          returned {:?} which contains inference types/regions",
                         substs);
                })
            });
            (node_item.item.def_id, substs)
        }
        None => {
            bug!("method {:?} not found in {:?}", name, impl_data.impl_def_id)
        }
    }
}

/// Is impl1 a specialization of impl2?
///
/// Specialization is determined by the sets of types to which the impls apply;
/// impl1 specializes impl2 if it applies to a subset of the types impl2 applies
/// to.
pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             impl1_def_id: DefId,
                             impl2_def_id: DefId) -> bool {
    debug!("specializes({:?}, {:?})", impl1_def_id, impl2_def_id);

    if let Some(r) = tcx.specializes_cache.borrow().check(impl1_def_id, impl2_def_id) {
        return r;
    }

    // The feature gate should prevent introducing new specializations, but not
    // taking advantage of upstream ones.
    if !tcx.sess.features.borrow().specialization &&
        (impl1_def_id.is_local() || impl2_def_id.is_local()) {
        return false;
    }

    // We determine whether there's a subset relationship by:
    //
    // - skolemizing impl1,
    // - assuming the where clauses for impl1,
    // - instantiating impl2 with fresh inference variables,
    // - unifying,
    // - attempting to prove the where clauses for impl2
    //
    // The last three steps are encapsulated in `fulfill_implication`.
    //
    // See RFC 1210 for more details and justification.

    // Currently we do not allow e.g. a negative impl to specialize a positive one
    if tcx.trait_impl_polarity(impl1_def_id) != tcx.trait_impl_polarity(impl2_def_id) {
        return false;
    }

    // create a parameter environment corresponding to a (skolemized) instantiation of impl1
    let penv = tcx.construct_parameter_environment(DUMMY_SP,
                                                   impl1_def_id,
                                                   region::DUMMY_CODE_EXTENT);
    let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id)
                             .unwrap()
                             .subst(tcx, &penv.free_substs);

    // Create a infcx, taking the predicates of impl1 as assumptions:
    let result = tcx.infer_ctxt(None, Some(penv), Reveal::ExactMatch).enter(|mut infcx| {
        // Normalize the trait reference, adding any obligations
        // that arise into the impl1 assumptions.
        let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = {
            let selcx = &mut SelectionContext::new(&infcx);
            traits::normalize(selcx, ObligationCause::dummy(), &impl1_trait_ref)
        };
        infcx.parameter_environment.caller_bounds.extend(normalization_obligations.into_iter().map(|o| {
            match tcx.lift_to_global(&o.predicate) {
                Some(predicate) => predicate,
                None => {
                    bug!("specializes: obligation `{:?}` has inference types/regions", o);
                }
            }
        }));

        // Attempt to prove that impl2 applies, given all of the above.
        fulfill_implication(&infcx, impl1_trait_ref, impl2_def_id).is_ok()
    });

    tcx.specializes_cache.borrow_mut().insert(impl1_def_id, impl2_def_id, result);
    result
}

/// Attempt to fulfill all obligations of `target_impl` after unification with
/// `source_trait_ref`. If successful, returns a substitution for *all* the
/// generics of `target_impl`, including both those needed to unify with
/// `source_trait_ref` and those whose identity is determined via a where
/// clause in the impl.
fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                       source_trait_ref: ty::TraitRef<'tcx>,
                                       target_impl: DefId)
                                       -> Result<&'tcx Substs<'tcx>, ()> {
    let selcx = &mut SelectionContext::new(&infcx);
    let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl);
    let (target_trait_ref, obligations) = impl_trait_ref_and_oblig(selcx,
                                                                   target_impl,
                                                                   target_substs);

    // do the impls unify? If not, no specialization.
    if let Err(_) = infcx.eq_trait_refs(true,
                                        TypeOrigin::Misc(DUMMY_SP),
                                        source_trait_ref,
                                        target_trait_ref) {
        debug!("fulfill_implication: {:?} does not unify with {:?}",
               source_trait_ref,
               target_trait_ref);
        return Err(());
    }

    // attempt to prove all of the predicates for impl2 given those for impl1
    // (which are packed up in penv)

    infcx.save_and_restore_obligations_in_snapshot_flag(|infcx| {
        let mut fulfill_cx = FulfillmentContext::new();
        for oblig in obligations.into_iter() {
            fulfill_cx.register_predicate_obligation(&infcx, oblig);
        }
        match fulfill_cx.select_all_or_error(infcx) {
            Err(errors) => {
                // no dice!
                debug!("fulfill_implication: for impls on {:?} and {:?}, \
                        could not fulfill: {:?} given {:?}",
                       source_trait_ref,
                       target_trait_ref,
                       errors,
                       infcx.parameter_environment.caller_bounds);
                Err(())
            }

            Ok(()) => {
                debug!("fulfill_implication: an impl for {:?} specializes {:?}",
                       source_trait_ref,
                       target_trait_ref);

                // Now resolve the *substitution* we built for the target earlier, replacing
                // the inference variables inside with whatever we got from fulfillment.
                Ok(infcx.resolve_type_vars_if_possible(&target_substs))
            }
        }
    })
}

pub struct SpecializesCache {
    map: FnvHashMap<(DefId, DefId), bool>
}

impl SpecializesCache {
    pub fn new() -> Self {
        SpecializesCache {
            map: FnvHashMap()
        }
    }

    pub fn check(&self, a: DefId, b: DefId) -> Option<bool> {
        self.map.get(&(a, b)).cloned()
    }

    pub fn insert(&mut self, a: DefId, b: DefId, result: bool) {
        self.map.insert((a, b), result);
    }
}
<|endoftext|>


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

// Validate AST before lowering it to HIR
//
// This pass is supposed to catch things that fit into AST data structures,
// but not permitted by the language. It runs after expansion when AST is frozen,
// so it can check for erroneous constructions produced by syntax extensions.
// This pass is supposed to perform only simple checks not requiring name resolution
// or type checking or some other kind of complex analysis.

use rustc::lint;
use rustc::session::Session;
use syntax::ast::*;
use syntax::parse::token::{self, keywords};
use syntax::visit::{self, Visitor};
use syntax_pos::Span;
use errors;

struct AstValidator<'a> {
    session: &'a Session,
}

impl<'a> AstValidator<'a> {
    fn err_handler(&self) -> &errors::Handler {
        &self.session.parse_sess.span_diagnostic
    }

    fn check_label(&self, label: Ident, span: Span, id: NodeId) {
        if label.name == keywords::StaticLifetime.name() {
            self.err_handler().span_err(span, &format!("invalid label name `{}`", label.name));
        }
        if label.name.as_str() == "'_" {
            self.session.add_lint(lint::builtin::LIFETIME_UNDERSCORE,
                                  id,
                                  span,
                                  format!("invalid label name `{}`", label.name));
        }
    }

    fn invalid_visibility(&self, vis: &Visibility, span: Span, note: Option<&str>) {
        if vis != &Visibility::Inherited {
            let mut err = struct_span_err!(self.session,
                                           span,
                                           E0449,
                                           "unnecessary visibility qualifier");
            if let Some(note) = note {
                err.span_note(span, note);
            }
            err.emit();
        }
    }

    fn check_decl_no_pat<ReportFn: Fn(Span, bool)>(&self, decl: &FnDecl, report_err: ReportFn) {
        for arg in &decl.inputs {
            match arg.pat.node {
                PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), _, None) |
                PatKind::Wild => {}
                PatKind::Ident(..) => report_err(arg.pat.span, true),
                _ => report_err(arg.pat.span, false),
            }
        }
    }
}

impl<'a> Visitor for AstValidator<'a> {
    fn visit_lifetime(&mut self, lt: &Lifetime) {
        if lt.name.as_str() == "'_" {
            self.session.add_lint(lint::builtin::LIFETIME_UNDERSCORE,
                                  lt.id,
                                  lt.span,
                                  format!("invalid lifetime name `{}`", lt.name));
        }

        visit::walk_lifetime(self, lt)
    }

    fn visit_expr(&mut self, expr: &Expr) {
        match expr.node {
            ExprKind::While(_, _, Some(ident)) |
            ExprKind::Loop(_, Some(ident)) |
            ExprKind::WhileLet(_, _, _, Some(ident)) |
            ExprKind::ForLoop(_, _, _, Some(ident)) |
            ExprKind::Break(Some(ident)) |
            ExprKind::Continue(Some(ident)) => {
                self.check_label(ident.node, ident.span, expr.id);
            }
            _ => {}
        }

        visit::walk_expr(self, expr)
    }

    fn visit_ty(&mut self, ty: &Ty) {
        match ty.node {
            TyKind::BareFn(ref bfty) => {
                self.check_decl_no_pat(&bfty.decl, |span, _| {
                    let mut err = struct_span_err!(self.session,
                                                   span,
                                                   E0561,
                                                   "patterns aren't allowed in function pointer \
                                                    types");
                    err.span_note(span,
                                  "this is a recent error, see issue #35203 for more details");
                    err.emit();
                });
            }
            _ => {}
        }

        visit::walk_ty(self, ty)
    }

    fn visit_path(&mut self, path: &Path, id: NodeId) {
        if path.global && path.segments.len() > 0 {
            let ident = path.segments[0].identifier;
            if token::Ident(ident).is_path_segment_keyword() {
                self.session.add_lint(lint::builtin::SUPER_OR_SELF_IN_GLOBAL_PATH,
                                      id,
                                      path.span,
                                      format!("global paths cannot start with `{}`", ident));
            }
        }

        visit::walk_path(self, path)
    }

    fn visit_item(&mut self, item: &Item) {
        match item.node {
            ItemKind::Use(ref view_path) => {
                let path = view_path.node.path();
                if !path.segments.iter().all(|segment| segment.parameters.is_empty()) {
                    self.err_handler()
                        .span_err(path.span, "type or lifetime parameters in import path");
                }
            }
            ItemKind::Impl(_, _, _, Some(..), _, ref impl_items) => {
                self.invalid_visibility(&item.vis, item.span, None);
                for impl_item in impl_items {
                    self.invalid_visibility(&impl_item.vis, impl_item.span, None);
                }
            }
            ItemKind::Impl(_, _, _, None, _, _) => {
                self.invalid_visibility(&item.vis,
                                        item.span,
                                        Some("place qualifiers on individual impl items instead"));
            }
            ItemKind::DefaultImpl(..) => {
                self.invalid_visibility(&item.vis, item.span, None);
            }
            ItemKind::ForeignMod(..) => {
                self.invalid_visibility(&item.vis,
                                        item.span,
                                        Some("place qualifiers on individual foreign items \
                                              instead"));
            }
            ItemKind::Enum(ref def, _) => {
                for variant in &def.variants {
                    for field in variant.node.data.fields() {
                        self.invalid_visibility(&field.vis, field.span, None);
                    }
                }
            }
            _ => {}
        }

        visit::walk_item(self, item)
    }

    fn visit_foreign_item(&mut self, fi: &ForeignItem) {
        match fi.node {
            ForeignItemKind::Fn(ref decl, _) => {
                self.check_decl_no_pat(decl, |span, is_recent| {
                    let mut err = struct_span_err!(self.session,
                                                   span,
                                                   E0130,
                                                   "patterns aren't allowed in foreign function \
                                                    declarations");
                    err.span_label(span, &format!("pattern not allowed in foreign function"));
                    if is_recent {
                        err.span_note(span,
                                      "this is a recent error, see issue #35203 for more details");
                    }
                    err.emit();
                });
            }
            ForeignItemKind::Static(..) => {}
        }

        visit::walk_foreign_item(self, fi)
    }

    fn visit_variant_data(&mut self,
                          vdata: &VariantData,
                          _: Ident,
                          _: &Generics,
                          _: NodeId,
                          span: Span) {
        if vdata.fields().is_empty() {
            if vdata.is_tuple() {
                self.err_handler()
                    .struct_span_err(span,
                                     "empty tuple structs and enum variants are not allowed, use \
                                      unit structs and enum variants instead")
                    .span_help(span,
                               "remove trailing `()` to make a unit struct or unit enum variant")
                    .emit();
            }
        }

        visit::walk_struct_def(self, vdata)
    }

    fn visit_vis(&mut self, vis: &Visibility) {
        match *vis {
            Visibility::Restricted { ref path, .. } => {
                if !path.segments.iter().all(|segment| segment.parameters.is_empty()) {
                    self.err_handler()
                        .span_err(path.span, "type or lifetime parameters in visibility path");
                }
            }
            _ => {}
        }

        visit::walk_vis(self, vis)
    }
}

pub fn check_crate(session: &Session, krate: &Crate) {
    visit::walk_crate(&mut AstValidator { session: session }, krate)
}
<commit_msg>Allow attributes to be marked used before `cfg` proccessing.<commit_after>// Copyright 2016 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.

// Validate AST before lowering it to HIR
//
// This pass is supposed to catch things that fit into AST data structures,
// but not permitted by the language. It runs after expansion when AST is frozen,
// so it can check for erroneous constructions produced by syntax extensions.
// This pass is supposed to perform only simple checks not requiring name resolution
// or type checking or some other kind of complex analysis.

use rustc::lint;
use rustc::session::Session;
use syntax::ast::*;
use syntax::attr;
use syntax::parse::token::{self, keywords};
use syntax::visit::{self, Visitor};
use syntax_pos::Span;
use errors;

struct AstValidator<'a> {
    session: &'a Session,
}

impl<'a> AstValidator<'a> {
    fn err_handler(&self) -> &errors::Handler {
        &self.session.parse_sess.span_diagnostic
    }

    fn check_label(&self, label: Ident, span: Span, id: NodeId) {
        if label.name == keywords::StaticLifetime.name() {
            self.err_handler().span_err(span, &format!("invalid label name `{}`", label.name));
        }
        if label.name.as_str() == "'_" {
            self.session.add_lint(lint::builtin::LIFETIME_UNDERSCORE,
                                  id,
                                  span,
                                  format!("invalid label name `{}`", label.name));
        }
    }

    fn invalid_visibility(&self, vis: &Visibility, span: Span, note: Option<&str>) {
        if vis != &Visibility::Inherited {
            let mut err = struct_span_err!(self.session,
                                           span,
                                           E0449,
                                           "unnecessary visibility qualifier");
            if let Some(note) = note {
                err.span_note(span, note);
            }
            err.emit();
        }
    }

    fn check_decl_no_pat<ReportFn: Fn(Span, bool)>(&self, decl: &FnDecl, report_err: ReportFn) {
        for arg in &decl.inputs {
            match arg.pat.node {
                PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), _, None) |
                PatKind::Wild => {}
                PatKind::Ident(..) => report_err(arg.pat.span, true),
                _ => report_err(arg.pat.span, false),
            }
        }
    }
}

impl<'a> Visitor for AstValidator<'a> {
    fn visit_lifetime(&mut self, lt: &Lifetime) {
        if lt.name.as_str() == "'_" {
            self.session.add_lint(lint::builtin::LIFETIME_UNDERSCORE,
                                  lt.id,
                                  lt.span,
                                  format!("invalid lifetime name `{}`", lt.name));
        }

        visit::walk_lifetime(self, lt)
    }

    fn visit_expr(&mut self, expr: &Expr) {
        match expr.node {
            ExprKind::While(_, _, Some(ident)) |
            ExprKind::Loop(_, Some(ident)) |
            ExprKind::WhileLet(_, _, _, Some(ident)) |
            ExprKind::ForLoop(_, _, _, Some(ident)) |
            ExprKind::Break(Some(ident)) |
            ExprKind::Continue(Some(ident)) => {
                self.check_label(ident.node, ident.span, expr.id);
            }
            _ => {}
        }

        visit::walk_expr(self, expr)
    }

    fn visit_ty(&mut self, ty: &Ty) {
        match ty.node {
            TyKind::BareFn(ref bfty) => {
                self.check_decl_no_pat(&bfty.decl, |span, _| {
                    let mut err = struct_span_err!(self.session,
                                                   span,
                                                   E0561,
                                                   "patterns aren't allowed in function pointer \
                                                    types");
                    err.span_note(span,
                                  "this is a recent error, see issue #35203 for more details");
                    err.emit();
                });
            }
            _ => {}
        }

        visit::walk_ty(self, ty)
    }

    fn visit_path(&mut self, path: &Path, id: NodeId) {
        if path.global && path.segments.len() > 0 {
            let ident = path.segments[0].identifier;
            if token::Ident(ident).is_path_segment_keyword() {
                self.session.add_lint(lint::builtin::SUPER_OR_SELF_IN_GLOBAL_PATH,
                                      id,
                                      path.span,
                                      format!("global paths cannot start with `{}`", ident));
            }
        }

        visit::walk_path(self, path)
    }

    fn visit_item(&mut self, item: &Item) {
        match item.node {
            ItemKind::Use(ref view_path) => {
                let path = view_path.node.path();
                if !path.segments.iter().all(|segment| segment.parameters.is_empty()) {
                    self.err_handler()
                        .span_err(path.span, "type or lifetime parameters in import path");
                }
            }
            ItemKind::Impl(_, _, _, Some(..), _, ref impl_items) => {
                self.invalid_visibility(&item.vis, item.span, None);
                for impl_item in impl_items {
                    self.invalid_visibility(&impl_item.vis, impl_item.span, None);
                }
            }
            ItemKind::Impl(_, _, _, None, _, _) => {
                self.invalid_visibility(&item.vis,
                                        item.span,
                                        Some("place qualifiers on individual impl items instead"));
            }
            ItemKind::DefaultImpl(..) => {
                self.invalid_visibility(&item.vis, item.span, None);
            }
            ItemKind::ForeignMod(..) => {
                self.invalid_visibility(&item.vis,
                                        item.span,
                                        Some("place qualifiers on individual foreign items \
                                              instead"));
            }
            ItemKind::Enum(ref def, _) => {
                for variant in &def.variants {
                    for field in variant.node.data.fields() {
                        self.invalid_visibility(&field.vis, field.span, None);
                    }
                }
            }
            ItemKind::Mod(_) => {
                // Ensure that `path` attributes on modules are recorded as used (c.f. #35584).
                attr::first_attr_value_str_by_name(&item.attrs, "path");
            }
            _ => {}
        }

        visit::walk_item(self, item)
    }

    fn visit_foreign_item(&mut self, fi: &ForeignItem) {
        match fi.node {
            ForeignItemKind::Fn(ref decl, _) => {
                self.check_decl_no_pat(decl, |span, is_recent| {
                    let mut err = struct_span_err!(self.session,
                                                   span,
                                                   E0130,
                                                   "patterns aren't allowed in foreign function \
                                                    declarations");
                    err.span_label(span, &format!("pattern not allowed in foreign function"));
                    if is_recent {
                        err.span_note(span,
                                      "this is a recent error, see issue #35203 for more details");
                    }
                    err.emit();
                });
            }
            ForeignItemKind::Static(..) => {}
        }

        visit::walk_foreign_item(self, fi)
    }

    fn visit_variant_data(&mut self,
                          vdata: &VariantData,
                          _: Ident,
                          _: &Generics,
                          _: NodeId,
                          span: Span) {
        if vdata.fields().is_empty() {
            if vdata.is_tuple() {
                self.err_handler()
                    .struct_span_err(span,
                                     "empty tuple structs and enum variants are not allowed, use \
                                      unit structs and enum variants instead")
                    .span_help(span,
                               "remove trailing `()` to make a unit struct or unit enum variant")
                    .emit();
            }
        }

        visit::walk_struct_def(self, vdata)
    }

    fn visit_vis(&mut self, vis: &Visibility) {
        match *vis {
            Visibility::Restricted { ref path, .. } => {
                if !path.segments.iter().all(|segment| segment.parameters.is_empty()) {
                    self.err_handler()
                        .span_err(path.span, "type or lifetime parameters in visibility path");
                }
            }
            _ => {}
        }

        visit::walk_vis(self, vis)
    }
}

pub fn check_crate(session: &Session, krate: &Crate) {
    visit::walk_crate(&mut AstValidator { session: session }, krate)
}
<|endoftext|>


<commit_before>/// External linking is a complex implementation to be able to serve a clean and easy-to-use
/// interface.
///
/// Internally, there are no such things as "external links" (plural). Each Entry in the store can
/// only have _one_ external link.
///
/// This library does the following therefor: It allows you to have several external links with one
/// entry, which are internally one file in the store for each link, linked with "internal
/// linking".
///
/// This helps us greatly with deduplication of URLs.
///

use std::ops::DerefMut;
use std::collections::BTreeMap;

use libimagstore::store::Entry;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;

use error::LinkError as LE;
use error::LinkErrorKind as LEK;
use result::Result;
use internal::InternalLinker;
use module_path::ModuleEntryPath;

use toml::Value;
use url::Url;
use crypto::sha1::Sha1;
use crypto::digest::Digest;

/// "Link" Type, just an abstraction over `FileLockEntry` to have some convenience internally.
pub struct Link<'a> {
    link: FileLockEntry<'a>
}

impl<'a> Link<'a> {

    pub fn new(fle: FileLockEntry<'a>) -> Link<'a> {
        Link { link: fle }
    }

    /// For interal use only. Load an Link from a store id, if this is actually a Link
    fn retrieve(store: &'a Store, id: StoreId) -> Result<Option<Link<'a>>> {
        store.retrieve(id)
            .map(|fle| {
                if let Some(_) = Link::get_link_uri_from_filelockentry(&fle) {
                    Some(Link {
                        link: fle
                    })
                } else {
                    None
                }
            })
            .map_err(|e| LE::new(LEK::StoreReadError, Some(Box::new(e))))
    }

    /// Get a link Url object from a `FileLockEntry`, ignore errors.
    fn get_link_uri_from_filelockentry(file: &FileLockEntry<'a>) -> Option<Url> {
        file.get_header()
            .read("imag.content.uri")
            .ok()
            .and_then(|opt| {
                match opt {
                    Some(Value::String(s)) => Url::parse(&s[..]).ok(),
                    _ => None
                }
            })
    }

    pub fn get_url(&self) -> Result<Option<Url>> {
        let opt = self.link
            .get_header()
            .read("imag.content.uri");

        match opt {
            Ok(Some(Value::String(s))) => {
                Url::parse(&s[..])
                     .map(Some)
                     .map_err(|e| LE::new(LEK::EntryHeaderReadError, Some(Box::new(e))))
            },
            Ok(None) => Ok(None),
            _ => Err(LE::new(LEK::EntryHeaderReadError, None))
        }
    }

}

pub trait ExternalLinker : InternalLinker {

    /// Get the external links from the implementor object
    fn get_external_links(&self, store: &Store) -> Result<Vec<Url>>;

    /// Set the external links for the implementor object
    fn set_external_links(&mut self, store: &Store, links: Vec<Url>) -> Result<()>;

    /// Add an external link to the implementor object
    fn add_external_link(&mut self, store: &Store, link: Url) -> Result<()>;

    /// Remove an external link from the implementor object
    fn remove_external_link(&mut self, store: &Store, link: Url) -> Result<()>;

}

/// Check whether the StoreId starts with `/link/external/`
pub fn is_external_link_storeid(id: &StoreId) -> bool {
    debug!("Checking whether this is a /link/external/*: '{:?}'", id);
    id.starts_with("/link/external/")
}

fn get_external_link_from_file(entry: &FileLockEntry) -> Result<Url> {
    Link::get_link_uri_from_filelockentry(entry) // TODO: Do not hide error by using this function
        .ok_or(LE::new(LEK::StoreReadError, None))
}

/// Implement `ExternalLinker` for `Entry`, hiding the fact that there is no such thing as an external
/// link in an entry, but internal links to other entries which serve as external links, as one
/// entry in the store can only have one external link.
impl ExternalLinker for Entry {

    /// Get the external links from the implementor object
    fn get_external_links(&self, store: &Store) -> Result<Vec<Url>> {
        // Iterate through all internal links and filter for FileLockEntries which live in
        // /link/external/<SHA> -> load these files and get the external link from their headers,
        // put them into the return vector.
        self.get_internal_links()
            .map(|vect| {
                debug!("Getting external links");
                vect.into_iter()
                    .filter(is_external_link_storeid)
                    .map(|id| {
                        debug!("Retrieving entry for id: '{:?}'", id);
                        match store.retrieve(id.clone()) {
                            Ok(f) => get_external_link_from_file(&f),
                            Err(e) => {
                                debug!("Retrieving entry for id: '{:?}' failed", id);
                                Err(LE::new(LEK::StoreReadError, Some(Box::new(e))))
                            }
                        }
                    })
                    .filter_map(|x| x.ok()) // TODO: Do not ignore error here
                    .collect()
            })
            .map_err(|e| LE::new(LEK::StoreReadError, Some(Box::new(e))))
    }

    /// Set the external links for the implementor object
    fn set_external_links(&mut self, store: &Store, links: Vec<Url>) -> Result<()> {
        // Take all the links, generate a SHA sum out of each one, filter out the already existing
        // store entries and store the other URIs in the header of one FileLockEntry each, in
        // the path /link/external/<SHA of the URL>

        debug!("Iterating {} links = {:?}", links.len(), links);
        for link in links { // for all links
            let hash = {
                let mut s = Sha1::new();
                s.input_str(&link.as_str()[..]);
                s.result_str()
            };
            let file_id = ModuleEntryPath::new(format!("external/{}", hash)).into_storeid();

            debug!("Link    = '{:?}'", link);
            debug!("Hash    = '{:?}'", hash);
            debug!("StoreId = '{:?}'", file_id);

            // retrieve the file from the store, which implicitely creates the entry if it does not
            // exist
            let file = store.retrieve(file_id.clone());
            if file.is_err() {
                debug!("Failed to create or retrieve an file for this link '{:?}'", link);
                return Err(LE::new(LEK::StoreWriteError, Some(Box::new(file.unwrap_err()))));
            }
            let mut file = file.unwrap();

            debug!("Generating header content!");
            {
                let mut hdr = file.deref_mut().get_header_mut();

                let mut table = match hdr.read("imag.content") {
                    Ok(Some(Value::Table(table))) => table,
                    Ok(Some(_)) => {
                        warn!("There is a value at 'imag.content' which is not a table.");
                        warn!("Going to override this value");
                        BTreeMap::new()
                    },
                    Ok(None) => BTreeMap::new(),
                    Err(e)   => return Err(LE::new(LEK::StoreWriteError, Some(Box::new(e)))),
                };

                let v = Value::String(link.into_string());

                debug!("setting URL = '{:?}", v);
                table.insert(String::from("url"), v);

                if let Err(e) = hdr.set("imag.content", Value::Table(table)) {
                    return Err(LE::new(LEK::StoreWriteError, Some(Box::new(e))));
                } else {
                    debug!("Setting URL worked");
                }
            }

            // then add an internal link to the new file or return an error if this fails
            if let Err(e) = self.add_internal_link(file.deref_mut()) {
                debug!("Error adding internal link");
                return Err(LE::new(LEK::StoreWriteError, Some(Box::new(e))));
            }
        }
        debug!("Ready iterating");
        Ok(())
    }

    /// Add an external link to the implementor object
    fn add_external_link(&mut self, store: &Store, link: Url) -> Result<()> {
        // get external links, add this one, save them
        debug!("Getting links");
        self.get_external_links(store)
            .and_then(|mut links| {
                debug!("Adding link = '{:?}' to links = {:?}", link, links);
                links.push(link);
                debug!("Setting {} links = {:?}", links.len(), links);
                self.set_external_links(store, links)
            })
    }

    /// Remove an external link from the implementor object
    fn remove_external_link(&mut self, store: &Store, link: Url) -> Result<()> {
        // get external links, remove this one, save them
        self.get_external_links(store)
            .and_then(|links| {
                debug!("Removing link = '{:?}' from links = {:?}", link, links);
                let links = links.into_iter()
                    .filter(|l| l.as_str() != link.as_str())
                    .collect();
                self.set_external_links(store, links)
            })
    }

}

<commit_msg>Remove if-else by map()<commit_after>/// External linking is a complex implementation to be able to serve a clean and easy-to-use
/// interface.
///
/// Internally, there are no such things as "external links" (plural). Each Entry in the store can
/// only have _one_ external link.
///
/// This library does the following therefor: It allows you to have several external links with one
/// entry, which are internally one file in the store for each link, linked with "internal
/// linking".
///
/// This helps us greatly with deduplication of URLs.
///

use std::ops::DerefMut;
use std::collections::BTreeMap;

use libimagstore::store::Entry;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;

use error::LinkError as LE;
use error::LinkErrorKind as LEK;
use result::Result;
use internal::InternalLinker;
use module_path::ModuleEntryPath;

use toml::Value;
use url::Url;
use crypto::sha1::Sha1;
use crypto::digest::Digest;

/// "Link" Type, just an abstraction over `FileLockEntry` to have some convenience internally.
pub struct Link<'a> {
    link: FileLockEntry<'a>
}

impl<'a> Link<'a> {

    pub fn new(fle: FileLockEntry<'a>) -> Link<'a> {
        Link { link: fle }
    }

    /// For interal use only. Load an Link from a store id, if this is actually a Link
    fn retrieve(store: &'a Store, id: StoreId) -> Result<Option<Link<'a>>> {
        store.retrieve(id)
            .map(|fle| Link::get_link_uri_from_filelockentry(&fle).map(|_| Link { link: fle }))
            .map_err(|e| LE::new(LEK::StoreReadError, Some(Box::new(e))))
    }

    /// Get a link Url object from a `FileLockEntry`, ignore errors.
    fn get_link_uri_from_filelockentry(file: &FileLockEntry<'a>) -> Option<Url> {
        file.get_header()
            .read("imag.content.uri")
            .ok()
            .and_then(|opt| {
                match opt {
                    Some(Value::String(s)) => Url::parse(&s[..]).ok(),
                    _ => None
                }
            })
    }

    pub fn get_url(&self) -> Result<Option<Url>> {
        let opt = self.link
            .get_header()
            .read("imag.content.uri");

        match opt {
            Ok(Some(Value::String(s))) => {
                Url::parse(&s[..])
                     .map(Some)
                     .map_err(|e| LE::new(LEK::EntryHeaderReadError, Some(Box::new(e))))
            },
            Ok(None) => Ok(None),
            _ => Err(LE::new(LEK::EntryHeaderReadError, None))
        }
    }

}

pub trait ExternalLinker : InternalLinker {

    /// Get the external links from the implementor object
    fn get_external_links(&self, store: &Store) -> Result<Vec<Url>>;

    /// Set the external links for the implementor object
    fn set_external_links(&mut self, store: &Store, links: Vec<Url>) -> Result<()>;

    /// Add an external link to the implementor object
    fn add_external_link(&mut self, store: &Store, link: Url) -> Result<()>;

    /// Remove an external link from the implementor object
    fn remove_external_link(&mut self, store: &Store, link: Url) -> Result<()>;

}

/// Check whether the StoreId starts with `/link/external/`
pub fn is_external_link_storeid(id: &StoreId) -> bool {
    debug!("Checking whether this is a /link/external/*: '{:?}'", id);
    id.starts_with("/link/external/")
}

fn get_external_link_from_file(entry: &FileLockEntry) -> Result<Url> {
    Link::get_link_uri_from_filelockentry(entry) // TODO: Do not hide error by using this function
        .ok_or(LE::new(LEK::StoreReadError, None))
}

/// Implement `ExternalLinker` for `Entry`, hiding the fact that there is no such thing as an external
/// link in an entry, but internal links to other entries which serve as external links, as one
/// entry in the store can only have one external link.
impl ExternalLinker for Entry {

    /// Get the external links from the implementor object
    fn get_external_links(&self, store: &Store) -> Result<Vec<Url>> {
        // Iterate through all internal links and filter for FileLockEntries which live in
        // /link/external/<SHA> -> load these files and get the external link from their headers,
        // put them into the return vector.
        self.get_internal_links()
            .map(|vect| {
                debug!("Getting external links");
                vect.into_iter()
                    .filter(is_external_link_storeid)
                    .map(|id| {
                        debug!("Retrieving entry for id: '{:?}'", id);
                        match store.retrieve(id.clone()) {
                            Ok(f) => get_external_link_from_file(&f),
                            Err(e) => {
                                debug!("Retrieving entry for id: '{:?}' failed", id);
                                Err(LE::new(LEK::StoreReadError, Some(Box::new(e))))
                            }
                        }
                    })
                    .filter_map(|x| x.ok()) // TODO: Do not ignore error here
                    .collect()
            })
            .map_err(|e| LE::new(LEK::StoreReadError, Some(Box::new(e))))
    }

    /// Set the external links for the implementor object
    fn set_external_links(&mut self, store: &Store, links: Vec<Url>) -> Result<()> {
        // Take all the links, generate a SHA sum out of each one, filter out the already existing
        // store entries and store the other URIs in the header of one FileLockEntry each, in
        // the path /link/external/<SHA of the URL>

        debug!("Iterating {} links = {:?}", links.len(), links);
        for link in links { // for all links
            let hash = {
                let mut s = Sha1::new();
                s.input_str(&link.as_str()[..]);
                s.result_str()
            };
            let file_id = ModuleEntryPath::new(format!("external/{}", hash)).into_storeid();

            debug!("Link    = '{:?}'", link);
            debug!("Hash    = '{:?}'", hash);
            debug!("StoreId = '{:?}'", file_id);

            // retrieve the file from the store, which implicitely creates the entry if it does not
            // exist
            let file = store.retrieve(file_id.clone());
            if file.is_err() {
                debug!("Failed to create or retrieve an file for this link '{:?}'", link);
                return Err(LE::new(LEK::StoreWriteError, Some(Box::new(file.unwrap_err()))));
            }
            let mut file = file.unwrap();

            debug!("Generating header content!");
            {
                let mut hdr = file.deref_mut().get_header_mut();

                let mut table = match hdr.read("imag.content") {
                    Ok(Some(Value::Table(table))) => table,
                    Ok(Some(_)) => {
                        warn!("There is a value at 'imag.content' which is not a table.");
                        warn!("Going to override this value");
                        BTreeMap::new()
                    },
                    Ok(None) => BTreeMap::new(),
                    Err(e)   => return Err(LE::new(LEK::StoreWriteError, Some(Box::new(e)))),
                };

                let v = Value::String(link.into_string());

                debug!("setting URL = '{:?}", v);
                table.insert(String::from("url"), v);

                if let Err(e) = hdr.set("imag.content", Value::Table(table)) {
                    return Err(LE::new(LEK::StoreWriteError, Some(Box::new(e))));
                } else {
                    debug!("Setting URL worked");
                }
            }

            // then add an internal link to the new file or return an error if this fails
            if let Err(e) = self.add_internal_link(file.deref_mut()) {
                debug!("Error adding internal link");
                return Err(LE::new(LEK::StoreWriteError, Some(Box::new(e))));
            }
        }
        debug!("Ready iterating");
        Ok(())
    }

    /// Add an external link to the implementor object
    fn add_external_link(&mut self, store: &Store, link: Url) -> Result<()> {
        // get external links, add this one, save them
        debug!("Getting links");
        self.get_external_links(store)
            .and_then(|mut links| {
                debug!("Adding link = '{:?}' to links = {:?}", link, links);
                links.push(link);
                debug!("Setting {} links = {:?}", links.len(), links);
                self.set_external_links(store, links)
            })
    }

    /// Remove an external link from the implementor object
    fn remove_external_link(&mut self, store: &Store, link: Url) -> Result<()> {
        // get external links, remove this one, save them
        self.get_external_links(store)
            .and_then(|links| {
                debug!("Removing link = '{:?}' from links = {:?}", link, links);
                let links = links.into_iter()
                    .filter(|l| l.as_str() != link.as_str())
                    .collect();
                self.set_external_links(store, links)
            })
    }

}

<|endoftext|>


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

use fuzz_store::{fuzz, StatKey, Stats};
use std::io::Write;
use std::io::{stdout, Read};
use std::path::Path;

fn usage(program: &str) {
    println!(
        r#"Usage: {} {{ [<artifact_file>] | <corpus_directory> <bucket_predicate>.. }}

If <artifact_file> is not provided, it is read from standard input.

When <bucket_predicate>.. are provided, only runs matching all predicates are shown. The format of
each <bucket_predicate> is <bucket_key>=<bucket_value>."#,
        program
    );
}

fn debug(data: &[u8]) {
    println!("{:02x?}", data);
    fuzz(data, true, None);
}

/// Bucket predicate.
struct Predicate {
    /// Bucket key.
    key: StatKey,

    /// Bucket value.
    value: usize,
}

impl std::str::FromStr for Predicate {
    type Err = String;

    fn from_str(input: &str) -> Result<Self, Self::Err> {
        let predicate: Vec<&str> = input.split('=').collect();
        if predicate.len() != 2 {
            return Err("Predicate should have exactly one equal sign.".to_string());
        }
        let key = predicate[0]
            .parse()
            .map_err(|_| format!("Predicate key `{}` is not recognized.", predicate[0]))?;
        let value: usize = predicate[1]
            .parse()
            .map_err(|_| format!("Predicate value `{}` is not a number.", predicate[1]))?;
        if value != 0 && !value.is_power_of_two() {
            return Err(format!(
                "Predicate value `{}` is not a bucket.",
                predicate[1]
            ));
        }
        Ok(Predicate { key, value })
    }
}

fn analyze(corpus: &Path, predicates: Vec<Predicate>) {
    let mut stats = Stats::default();
    let mut count = 0;
    let total = std::fs::read_dir(corpus).unwrap().count();
    for entry in std::fs::read_dir(corpus).unwrap() {
        let data = std::fs::read(entry.unwrap().path()).unwrap();
        let mut stat = Stats::default();
        fuzz(&data, false, Some(&mut stat));
        if predicates
            .iter()
            .all(|p| stat.get_count(p.key, p.value).is_some())
        {
            stats.merge(&stat);
        }
        count += 1;
        print!("\u{1b}[K{} / {}\r", count, total);
        stdout().flush().unwrap();
    }
    // NOTE: To avoid reloading the corpus each time we want to check a different filter, we can
    // start an interactive loop here taking filters as input and printing the filtered stats. We
    // would keep all individual stats for each run in a vector.
    print!("{}", stats);
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    // No arguments reads from stdin.
    if args.len() <= 1 {
        let stdin = std::io::stdin();
        let mut data = Vec::new();
        stdin.lock().read_to_end(&mut data).unwrap();
        return debug(&data);
    }
    let path = Path::new(&args[1]);
    // File argument assumes artifact.
    if path.is_file() && args.len() == 2 {
        return debug(&std::fs::read(path).unwrap());
    }
    // Directory argument assumes corpus.
    if path.is_dir() {
        match args[2..].iter().map(|x| x.parse()).collect() {
            Ok(predicates) => return analyze(path, predicates),
            Err(error) => eprintln!("Error: {}", error),
        }
    }
    usage(&args[0]);
}
<|endoftext|>


<commit_before><commit_msg>Rollup merge of #60360 - rasendubi:const-labeled-break, r=Centril<commit_after>// Using labeled break in a while loop has caused an illegal instruction being
// generated, and an ICE later.
//
// See https://github.com/rust-lang/rust/issues/51350 for more information.

const CRASH: () = 'a: while break 'a {};

fn main() {
    println!("{:?}", CRASH);
}
<|endoftext|>


<commit_before><commit_msg>Add a test that causes an ICE currently<commit_after>// Copyright 2012 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.

struct S<'self, T> {
    o: &'self Option<T>
}

fn main() {
    S { o: &None }; //~ ERROR cannot determine a type for this expression: unconstrained type
}
<|endoftext|>


<commit_before><commit_msg>[Rust] static한 변수와 같은 이름을 local에서 사용 못함<commit_after>const a: i32 = 0;
fn main() {
    let a = 0;
}
<|endoftext|>


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

//! A syntax highlighting plugin based on syntect.

extern crate serde;
extern crate syntect;
#[macro_use]
extern crate xi_plugin_lib;

mod stackmap;

use xi_plugin_lib::caching_plugin::{self, PluginCtx};
use xi_plugin_lib::plugin_base::ScopeSpan;
use syntect::parsing::{ParseState, ScopeStack, SyntaxSet, SCOPE_REPO};
use stackmap::{StackMap, LookupResult};

struct PluginState<'a> {
    syntax_set: &'a SyntaxSet,
    stack_idents: StackMap,
    line_num: usize,
    offset: usize,
    parse_state: Option<ParseState>,
    scope_state: ScopeStack,
    spans_start: usize,
    // unflushed spans
    spans: Vec<ScopeSpan>,
    new_scopes: Vec<Vec<String>>,
    syntax_name: String,
}

impl<'a> PluginState<'a> {
    pub fn new(syntax_set: &'a SyntaxSet) -> Self {
        PluginState {
            syntax_set: syntax_set,
            stack_idents: StackMap::default(),
            line_num: 0,
            offset: 0,
            parse_state: None,
            scope_state: ScopeStack::new(),
            spans_start: 0,
            spans: Vec::new(),
            new_scopes: Vec::new(),
            syntax_name: String::from("None"),
        }
    }

    // Return true if there's more to do.
    fn highlight_one_line(&mut self, ctx: &mut PluginCtx) -> bool {
        let line = ctx.get_line(self.line_num);
        if let Err(err) = line {
            print_err!("Error: {:?}", err);
            return false;
        }
        let line = line.unwrap();
        if line.is_none() {
            return false;
        }
        let line = line.unwrap();
        let ops = self.parse_state.as_mut().unwrap().parse_line(&line);
        if self.spans.is_empty() {
            self.spans_start = self.offset;
        }

        let mut prev_cursor = 0;
        let repo = SCOPE_REPO.lock().unwrap();
        for (cursor, batch) in ops {
            if self.scope_state.len() > 0 {
                let scope_ident = self.stack_idents.get_value(self.scope_state.as_slice());
                //print_err!("scope ident: {:?}", scope_ident);
                let scope_ident = match scope_ident {
                    LookupResult::Existing(id) => id,
                    LookupResult::New(id) => {
                        let stack_strings = self.scope_state.as_slice().iter()
                            .map(|slice| repo.to_string(*slice))
                            .collect::<Vec<_>>();
                        self.new_scopes.push(stack_strings);
                        id
                    }
                };

                let start = self.offset - self.spans_start + prev_cursor;
                let end = start + (cursor - prev_cursor);
                let span = ScopeSpan::new(start, end, scope_ident);
                self.spans.push(span);
            }
            prev_cursor = cursor;
            self.scope_state.apply(&batch);
        }

        self.line_num += 1;
        self.offset += line.len();
        true
    }

    fn flush_spans(&mut self, ctx: &mut PluginCtx) {
        if !self.new_scopes.is_empty() {
            ctx.add_scopes(&self.new_scopes);
        }
        if !self.spans.is_empty() {
            ctx.update_spans(self.spans_start, self.offset - self.spans_start,
                             self.spans.as_slice());
        }
    }

    fn do_highlighting(&mut self, mut ctx: PluginCtx) {
        let syntax = match ctx.get_path() {
            Some(ref path) => self.syntax_set.find_syntax_for_file(path).unwrap()
                .unwrap_or_else(|| self.syntax_set.find_syntax_plain_text()),
            None => self.syntax_set.find_syntax_plain_text(),
        };

        if syntax.name != self.syntax_name {
            self.syntax_name = syntax.name.clone();
            print_err!("syntect using {}", syntax.name);
        }

        self.parse_state = Some(ParseState::new(syntax));
        self.scope_state = ScopeStack::new();
        self.spans = Vec::new();
        self.new_scopes = Vec::new();
        self.line_num = 0;
        self.offset = 0;
        ctx.schedule_idle(0);
    }
}

const LINES_PER_RPC: usize = 50;

impl<'a> caching_plugin::Handler for PluginState<'a> {
    fn initialize(&mut self, ctx: PluginCtx, _buf_size: usize) {
        self.do_highlighting(ctx);
    }

    fn update(&mut self, ctx: PluginCtx) {
        self.do_highlighting(ctx);
    }

    fn idle(&mut self, mut ctx: PluginCtx, _token: usize) {
        print_err!("idle task at line {}", self.line_num);
        for _ in 0..LINES_PER_RPC {
            if !self.highlight_one_line(&mut ctx) {
                self.flush_spans(&mut ctx);
                return;
            }
            if ctx.request_is_pending() {
                print_err!("request pending at line {}", self.line_num);
                break;
            }
        }
        self.flush_spans(&mut ctx);
        ctx.schedule_idle(0);
    }
}

fn main() {
    let syntax_set = SyntaxSet::load_defaults_newlines();
    let mut state = PluginState::new(&syntax_set);

    caching_plugin::mainloop(&mut state);
}
<commit_msg>Fix highlighting irregularities<commit_after>// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A syntax highlighting plugin based on syntect.

extern crate serde;
extern crate syntect;
#[macro_use]
extern crate xi_plugin_lib;

mod stackmap;

use xi_plugin_lib::caching_plugin::{self, PluginCtx};
use xi_plugin_lib::plugin_base::ScopeSpan;
use syntect::parsing::{ParseState, ScopeStack, SyntaxSet, SCOPE_REPO};
use stackmap::{StackMap, LookupResult};

struct PluginState<'a> {
    syntax_set: &'a SyntaxSet,
    stack_idents: StackMap,
    line_num: usize,
    offset: usize,
    parse_state: Option<ParseState>,
    scope_state: ScopeStack,
    spans_start: usize,
    // unflushed spans
    spans: Vec<ScopeSpan>,
    new_scopes: Vec<Vec<String>>,
    syntax_name: String,
}

impl<'a> PluginState<'a> {
    pub fn new(syntax_set: &'a SyntaxSet) -> Self {
        PluginState {
            syntax_set: syntax_set,
            stack_idents: StackMap::default(),
            line_num: 0,
            offset: 0,
            parse_state: None,
            scope_state: ScopeStack::new(),
            spans_start: 0,
            spans: Vec::new(),
            new_scopes: Vec::new(),
            syntax_name: String::from("None"),
        }
    }

    // Return true if there's more to do.
    fn highlight_one_line(&mut self, ctx: &mut PluginCtx) -> bool {
        let line = ctx.get_line(self.line_num);
        if let Err(err) = line {
            print_err!("Error: {:?}", err);
            return false;
        }
        let line = line.unwrap();
        if line.is_none() {
            return false;
        }
        let line = line.unwrap();
        let ops = self.parse_state.as_mut().unwrap().parse_line(&line);

        let mut prev_cursor = 0;
        let repo = SCOPE_REPO.lock().unwrap();
        for (cursor, batch) in ops {
            if self.scope_state.len() > 0 {
                let scope_ident = self.stack_idents.get_value(self.scope_state.as_slice());
                let scope_ident = match scope_ident {
                    LookupResult::Existing(id) => id,
                    LookupResult::New(id) => {
                        let stack_strings = self.scope_state.as_slice().iter()
                            .map(|slice| repo.to_string(*slice))
                            .collect::<Vec<_>>();
                        self.new_scopes.push(stack_strings);
                        id
                    }
                };

                let start = self.offset - self.spans_start + prev_cursor;
                let end = start + (cursor - prev_cursor);
                let span = ScopeSpan::new(start, end, scope_ident);
                self.spans.push(span);
            }
            prev_cursor = cursor;
            self.scope_state.apply(&batch);
        }

        self.line_num += 1;
        self.offset += line.len();
        true
    }

    fn flush_spans(&mut self, ctx: &mut PluginCtx) {
        if !self.new_scopes.is_empty() {
            ctx.add_scopes(&self.new_scopes);
            self.new_scopes.clear();
        }
        if !self.spans.is_empty() {
            ctx.update_spans(self.spans_start, self.offset - self.spans_start,
                             self.spans.as_slice());
            self.spans.clear();
        }
        self.spans_start = self.offset;
    }

    fn do_highlighting(&mut self, mut ctx: PluginCtx) {
        let syntax = match ctx.get_path() {
            Some(ref path) => self.syntax_set.find_syntax_for_file(path).unwrap()
                .unwrap_or_else(|| self.syntax_set.find_syntax_plain_text()),
            None => self.syntax_set.find_syntax_plain_text(),
        };

        if syntax.name != self.syntax_name {
            self.syntax_name = syntax.name.clone();
            print_err!("syntect using {}", syntax.name);
        }

        self.parse_state = Some(ParseState::new(syntax));
        self.scope_state = ScopeStack::new();
        self.spans = Vec::new();
        self.new_scopes = Vec::new();
        self.line_num = 0;
        self.offset = 0;
        self.spans_start = 0;
        ctx.schedule_idle(0);
    }
}

const LINES_PER_RPC: usize = 50;

impl<'a> caching_plugin::Handler for PluginState<'a> {
    fn initialize(&mut self, ctx: PluginCtx, _buf_size: usize) {
        self.do_highlighting(ctx);
    }

    fn update(&mut self, ctx: PluginCtx) {
        self.do_highlighting(ctx);
    }

    fn idle(&mut self, mut ctx: PluginCtx, _token: usize) {
        //print_err!("idle task at line {}", self.line_num);
        for _ in 0..LINES_PER_RPC {
            if !self.highlight_one_line(&mut ctx) {
                self.flush_spans(&mut ctx);
                return;
            }
            if ctx.request_is_pending() {
                print_err!("request pending at line {}", self.line_num);
                break;
            }
        }
        self.flush_spans(&mut ctx);
        ctx.schedule_idle(0);
    }
}

fn main() {
    let syntax_set = SyntaxSet::load_defaults_newlines();
    let mut state = PluginState::new(&syntax_set);

    caching_plugin::mainloop(&mut state);
}
<|endoftext|>


<commit_before><commit_msg>new test case demonstrating ability to return ptr to interior of option<commit_after>fn get<T>(opt: &option<T>) -> &T {
    match *opt {
      some(ref v) => v,
      none => fail ~"none"
    }
}

fn main() {
    let mut x = some(23);

    {
        let y = get(&x);
        assert *y == 23;
    }

    x = some(24);

    {
        let y = get(&x);
        assert *y == 24;
    }
}<|endoftext|>


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

/// Code to handle management of a pool's thinpool device.

use std::process::Command;

use devicemapper;
use devicemapper::{Bytes, DM, DataBlocks, DmError, DmResult, LinearDev, MetaBlocks, Sectors,
                   Segment, ThinDev, ThinDevId, ThinPoolDev, ThinPoolStatus};

use super::super::consts::IEC;
use super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::types::PoolUuid;

use super::dmdevice::{FlexRole, ThinDevIdPool, ThinPoolRole, format_flex_name,
                      format_thinpool_name};
use super::serde_structs::{Recordable, ThinPoolDevSave};

pub const DATA_BLOCK_SIZE: Sectors = Sectors(2048);
pub const DATA_LOWATER: DataBlocks = DataBlocks(512);
pub const META_LOWATER: MetaBlocks = MetaBlocks(512);

/// A ThinPool struct contains the thinpool itself, but also the spare
/// segments for its metadata device.
#[derive(Debug)]
pub struct ThinPool {
    thin_pool: ThinPoolDev,
    meta_spare: Vec<Segment>,
    id_gen: ThinDevIdPool,
}

impl ThinPool {
    /// Make a new thin pool.
    pub fn new(pool_uuid: PoolUuid,
               dm: &DM,
               data_block_size: Sectors,
               low_water_mark: DataBlocks,
               spare_segments: Vec<Segment>,
               meta_dev: LinearDev,
               data_dev: LinearDev)
               -> EngineResult<ThinPool> {
        let name = format_thinpool_name(&pool_uuid, ThinPoolRole::Pool);
        let thinpool_dev = try!(ThinPoolDev::new(&name,
                                                 dm,
                                                 try!(data_dev.size()),
                                                 data_block_size,
                                                 low_water_mark,
                                                 meta_dev,
                                                 data_dev));
        Ok(ThinPool {
               thin_pool: thinpool_dev,
               meta_spare: spare_segments,
               id_gen: ThinDevIdPool::new_from_ids(&[]),
           })
    }

    /// Set up an "existing" thin pool.
    /// A thin pool must store the metadata for its thin devices, regardless of
    /// whether it has an existing device node. An existing thin pool device
    /// is a device where the metadata is already stored on its meta device.
    /// If initial setup fails due to a thin_check failure, attempt to fix
    /// the problem by running thin_repair. If failure recurs, return an
    /// error.
    pub fn setup(pool_uuid: PoolUuid,
                 dm: &DM,
                 data_block_size: Sectors,
                 low_water_mark: DataBlocks,
                 thin_ids: &[ThinDevId],
                 spare_segments: Vec<Segment>,
                 meta_dev: LinearDev,
                 data_dev: LinearDev)
                 -> EngineResult<ThinPool> {
        let name = format_thinpool_name(&pool_uuid, ThinPoolRole::Pool);
        let size = try!(data_dev.size());
        match ThinPoolDev::setup(&name,
                                 dm,
                                 size,
                                 data_block_size,
                                 low_water_mark,
                                 meta_dev,
                                 data_dev) {
            Ok(dev) => {
                Ok(ThinPool {
                       thin_pool: dev,
                       meta_spare: spare_segments,
                       id_gen: ThinDevIdPool::new_from_ids(thin_ids),
                   })
            }
            Err(DmError::Dm(devicemapper::ErrorEnum::CheckFailed(meta_dev, data_dev), _)) => {
                let (new_meta_dev, new_spare_segments) =
                    try!(attempt_thin_repair(pool_uuid, dm, meta_dev, spare_segments));
                Ok(ThinPool {
                       thin_pool: try!(ThinPoolDev::setup(&name,
                                                          dm,
                                                          size,
                                                          data_block_size,
                                                          low_water_mark,
                                                          new_meta_dev,
                                                          data_dev)),
                       meta_spare: new_spare_segments,
                       id_gen: ThinDevIdPool::new_from_ids(thin_ids),
                   })
            }
            Err(err) => Err(err.into()),
        }
    }

    /// The status of the thin pool as calculated by DM.
    pub fn thin_pool_status(&self, dm: &DM) -> EngineResult<ThinPoolStatus> {
        Ok(try!(self.thin_pool.status(dm)))
    }

    /// Make a new thin device.
    pub fn make_thin_device(&mut self,
                            dm: &DM,
                            name: &str,
                            size: Option<Sectors>)
                            -> EngineResult<ThinDev> {
        Ok(try!(ThinDev::new(name,
                             dm,
                             &self.thin_pool,
                             try!(self.id_gen.new_id()),
                             size.unwrap_or(Bytes(IEC::Ti).sectors()))))
    }

    /// Setup a previously constructed thin device.
    pub fn setup_thin_device(&self,
                             dm: &DM,
                             name: &str,
                             id: ThinDevId,
                             size: Sectors)
                             -> EngineResult<ThinDev> {
        Ok(try!(ThinDev::setup(name, dm, &self.thin_pool, id, size)))
    }

    /// Tear down the thin pool.
    pub fn teardown(self, dm: &DM) -> DmResult<()> {
        self.thin_pool.teardown(dm)
    }

    /// Get an immutable reference to the sparse segments of the ThinPool.
    pub fn spare_segments(&self) -> &[Segment] {
        &self.meta_spare
    }

    /// The segments belonging to the thin pool meta device.
    pub fn thin_pool_meta_segments(&self) -> &[Segment] {
        self.thin_pool.meta_dev().segments()
    }

    /// The segments belonging to the thin pool data device.
    pub fn thin_pool_data_segments(&self) -> &[Segment] {
        self.thin_pool.data_dev().segments()
    }

    /// Extend the thinpool with new data regions.
    pub fn extend_data(&mut self, dm: &DM, segs: Vec<Segment>) -> EngineResult<()> {
        Ok(try!(self.thin_pool.extend_data(dm, segs)))
    }

    /// The number of physical sectors in use, that is, unavailable for storage
    /// of additional user data, by this pool.
    // This includes all the sectors being held as spares for the meta device,
    // all the sectors allocated to the meta data device, and all the sectors
    // in use on the data device.
    pub fn total_physical_used(&self) -> EngineResult<Sectors> {
        let data_dev_used = match try!(self.thin_pool.status(&try!(DM::new()))) {
            ThinPoolStatus::Good(_, usage) => *usage.used_data * DATA_BLOCK_SIZE,
            _ => {
                let err_msg = "thin pool failed, could not obtain usage";
                return Err(EngineError::Engine(ErrorEnum::Invalid, err_msg.into()));
            }
        };

        let spare_total = self.spare_segments().iter().map(|s| s.length).sum();
        let meta_dev_total = self.thin_pool
            .meta_dev()
            .segments()
            .iter()
            .map(|s| s.length)
            .sum();

        Ok(data_dev_used + spare_total + meta_dev_total)
    }
}

impl Recordable<ThinPoolDevSave> for ThinPool {
    fn record(&self) -> EngineResult<ThinPoolDevSave> {
        Ok(ThinPoolDevSave { data_block_size: self.thin_pool.data_block_size() })
    }
}

/// Attempt a thin repair operation on the meta device.
/// If the operation succeeds, teardown the old meta device,
/// and return the new meta device and the new spare segments.
fn attempt_thin_repair(pool_uuid: PoolUuid,
                       dm: &DM,
                       meta_dev: LinearDev,
                       mut spare_segments: Vec<Segment>)
                       -> EngineResult<(LinearDev, Vec<Segment>)> {
    let mut new_meta_dev = try!(LinearDev::new(&format_flex_name(&pool_uuid,
                                                                 FlexRole::ThinMetaSpare),
                                               dm,
                                               spare_segments.drain(..).collect()));

    if !try!(Command::new("thin_repair")
                 .arg("-i")
                 .arg(&try!(meta_dev.devnode()))
                 .arg("-o")
                 .arg(&try!(new_meta_dev.devnode()))
                 .status())
                .success() {
        return Err(EngineError::Engine(ErrorEnum::Error,
                                       "thin_repair failed, pool unusable".into()));
    }

    let name = meta_dev.name().to_owned();
    let new_spare_segments = meta_dev
        .segments()
        .iter()
        .map(|x| {
                 Segment {
                     start: x.start,
                     length: x.length,
                     device: x.device,
                 }
             })
        .collect();
    try!(meta_dev.teardown(dm));
    try!(new_meta_dev.set_name(dm, &name));

    Ok((new_meta_dev, new_spare_segments))
}
<commit_msg>Allow 8 arguments in ThinPool::setup()<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/.

/// Code to handle management of a pool's thinpool device.

use std::process::Command;

use devicemapper;
use devicemapper::{Bytes, DM, DataBlocks, DmError, DmResult, LinearDev, MetaBlocks, Sectors,
                   Segment, ThinDev, ThinDevId, ThinPoolDev, ThinPoolStatus};

use super::super::consts::IEC;
use super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::types::PoolUuid;

use super::dmdevice::{FlexRole, ThinDevIdPool, ThinPoolRole, format_flex_name,
                      format_thinpool_name};
use super::serde_structs::{Recordable, ThinPoolDevSave};

pub const DATA_BLOCK_SIZE: Sectors = Sectors(2048);
pub const DATA_LOWATER: DataBlocks = DataBlocks(512);
pub const META_LOWATER: MetaBlocks = MetaBlocks(512);

/// A ThinPool struct contains the thinpool itself, but also the spare
/// segments for its metadata device.
#[derive(Debug)]
pub struct ThinPool {
    thin_pool: ThinPoolDev,
    meta_spare: Vec<Segment>,
    id_gen: ThinDevIdPool,
}

impl ThinPool {
    /// Make a new thin pool.
    pub fn new(pool_uuid: PoolUuid,
               dm: &DM,
               data_block_size: Sectors,
               low_water_mark: DataBlocks,
               spare_segments: Vec<Segment>,
               meta_dev: LinearDev,
               data_dev: LinearDev)
               -> EngineResult<ThinPool> {
        let name = format_thinpool_name(&pool_uuid, ThinPoolRole::Pool);
        let thinpool_dev = try!(ThinPoolDev::new(&name,
                                                 dm,
                                                 try!(data_dev.size()),
                                                 data_block_size,
                                                 low_water_mark,
                                                 meta_dev,
                                                 data_dev));
        Ok(ThinPool {
               thin_pool: thinpool_dev,
               meta_spare: spare_segments,
               id_gen: ThinDevIdPool::new_from_ids(&[]),
           })
    }

    /// Set up an "existing" thin pool.
    /// A thin pool must store the metadata for its thin devices, regardless of
    /// whether it has an existing device node. An existing thin pool device
    /// is a device where the metadata is already stored on its meta device.
    /// If initial setup fails due to a thin_check failure, attempt to fix
    /// the problem by running thin_repair. If failure recurs, return an
    /// error.
    #[allow(too_many_arguments)]
    pub fn setup(pool_uuid: PoolUuid,
                 dm: &DM,
                 data_block_size: Sectors,
                 low_water_mark: DataBlocks,
                 thin_ids: &[ThinDevId],
                 spare_segments: Vec<Segment>,
                 meta_dev: LinearDev,
                 data_dev: LinearDev)
                 -> EngineResult<ThinPool> {
        let name = format_thinpool_name(&pool_uuid, ThinPoolRole::Pool);
        let size = try!(data_dev.size());
        match ThinPoolDev::setup(&name,
                                 dm,
                                 size,
                                 data_block_size,
                                 low_water_mark,
                                 meta_dev,
                                 data_dev) {
            Ok(dev) => {
                Ok(ThinPool {
                       thin_pool: dev,
                       meta_spare: spare_segments,
                       id_gen: ThinDevIdPool::new_from_ids(thin_ids),
                   })
            }
            Err(DmError::Dm(devicemapper::ErrorEnum::CheckFailed(meta_dev, data_dev), _)) => {
                let (new_meta_dev, new_spare_segments) =
                    try!(attempt_thin_repair(pool_uuid, dm, meta_dev, spare_segments));
                Ok(ThinPool {
                       thin_pool: try!(ThinPoolDev::setup(&name,
                                                          dm,
                                                          size,
                                                          data_block_size,
                                                          low_water_mark,
                                                          new_meta_dev,
                                                          data_dev)),
                       meta_spare: new_spare_segments,
                       id_gen: ThinDevIdPool::new_from_ids(thin_ids),
                   })
            }
            Err(err) => Err(err.into()),
        }
    }

    /// The status of the thin pool as calculated by DM.
    pub fn thin_pool_status(&self, dm: &DM) -> EngineResult<ThinPoolStatus> {
        Ok(try!(self.thin_pool.status(dm)))
    }

    /// Make a new thin device.
    pub fn make_thin_device(&mut self,
                            dm: &DM,
                            name: &str,
                            size: Option<Sectors>)
                            -> EngineResult<ThinDev> {
        Ok(try!(ThinDev::new(name,
                             dm,
                             &self.thin_pool,
                             try!(self.id_gen.new_id()),
                             size.unwrap_or(Bytes(IEC::Ti).sectors()))))
    }

    /// Setup a previously constructed thin device.
    pub fn setup_thin_device(&self,
                             dm: &DM,
                             name: &str,
                             id: ThinDevId,
                             size: Sectors)
                             -> EngineResult<ThinDev> {
        Ok(try!(ThinDev::setup(name, dm, &self.thin_pool, id, size)))
    }

    /// Tear down the thin pool.
    pub fn teardown(self, dm: &DM) -> DmResult<()> {
        self.thin_pool.teardown(dm)
    }

    /// Get an immutable reference to the sparse segments of the ThinPool.
    pub fn spare_segments(&self) -> &[Segment] {
        &self.meta_spare
    }

    /// The segments belonging to the thin pool meta device.
    pub fn thin_pool_meta_segments(&self) -> &[Segment] {
        self.thin_pool.meta_dev().segments()
    }

    /// The segments belonging to the thin pool data device.
    pub fn thin_pool_data_segments(&self) -> &[Segment] {
        self.thin_pool.data_dev().segments()
    }

    /// Extend the thinpool with new data regions.
    pub fn extend_data(&mut self, dm: &DM, segs: Vec<Segment>) -> EngineResult<()> {
        Ok(try!(self.thin_pool.extend_data(dm, segs)))
    }

    /// The number of physical sectors in use, that is, unavailable for storage
    /// of additional user data, by this pool.
    // This includes all the sectors being held as spares for the meta device,
    // all the sectors allocated to the meta data device, and all the sectors
    // in use on the data device.
    pub fn total_physical_used(&self) -> EngineResult<Sectors> {
        let data_dev_used = match try!(self.thin_pool.status(&try!(DM::new()))) {
            ThinPoolStatus::Good(_, usage) => *usage.used_data * DATA_BLOCK_SIZE,
            _ => {
                let err_msg = "thin pool failed, could not obtain usage";
                return Err(EngineError::Engine(ErrorEnum::Invalid, err_msg.into()));
            }
        };

        let spare_total = self.spare_segments().iter().map(|s| s.length).sum();
        let meta_dev_total = self.thin_pool
            .meta_dev()
            .segments()
            .iter()
            .map(|s| s.length)
            .sum();

        Ok(data_dev_used + spare_total + meta_dev_total)
    }
}

impl Recordable<ThinPoolDevSave> for ThinPool {
    fn record(&self) -> EngineResult<ThinPoolDevSave> {
        Ok(ThinPoolDevSave { data_block_size: self.thin_pool.data_block_size() })
    }
}

/// Attempt a thin repair operation on the meta device.
/// If the operation succeeds, teardown the old meta device,
/// and return the new meta device and the new spare segments.
fn attempt_thin_repair(pool_uuid: PoolUuid,
                       dm: &DM,
                       meta_dev: LinearDev,
                       mut spare_segments: Vec<Segment>)
                       -> EngineResult<(LinearDev, Vec<Segment>)> {
    let mut new_meta_dev = try!(LinearDev::new(&format_flex_name(&pool_uuid,
                                                                 FlexRole::ThinMetaSpare),
                                               dm,
                                               spare_segments.drain(..).collect()));

    if !try!(Command::new("thin_repair")
                 .arg("-i")
                 .arg(&try!(meta_dev.devnode()))
                 .arg("-o")
                 .arg(&try!(new_meta_dev.devnode()))
                 .status())
                .success() {
        return Err(EngineError::Engine(ErrorEnum::Error,
                                       "thin_repair failed, pool unusable".into()));
    }

    let name = meta_dev.name().to_owned();
    let new_spare_segments = meta_dev
        .segments()
        .iter()
        .map(|x| {
                 Segment {
                     start: x.start,
                     length: x.length,
                     device: x.device,
                 }
             })
        .collect();
    try!(meta_dev.teardown(dm));
    try!(new_meta_dev.set_name(dm, &name));

    Ok((new_meta_dev, new_spare_segments))
}
<|endoftext|>