<commit_before>use crate::infer::{InferCtxt, TyCtxtInferExt};
use crate::traits::ObligationCause;
use crate::traits::{self, ConstPatternStructural, TraitEngine};

use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::lang_items::{StructuralPeqTraitLangItem, StructuralTeqTraitLangItem};
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_span::Span;

#[derive(Debug)]
pub enum NonStructuralMatchTy<'tcx> {
    Adt(&'tcx AdtDef),
    Param,
    Dynamic,
    Foreign,
    Opaque,
    Generator,
    Projection,
}

/// This method traverses the structure of `ty`, trying to find an
/// instance of an ADT (i.e. struct or enum) that doesn't implement
/// the structural-match traits, or a generic type parameter
/// (which cannot be determined to be structural-match).
///
/// The "structure of a type" includes all components that would be
/// considered when doing a pattern match on a constant of that
/// type.
///
///  * This means this method descends into fields of structs/enums,
///    and also descends into the inner type `T` of `&T` and `&mut T`
///
///  * The traversal doesn't dereference unsafe pointers (`*const T`,
///    `*mut T`), and it does not visit the type arguments of an
///    instantiated generic like `PhantomData<T>`.
///
/// The reason we do this search is Rust currently require all ADTs
/// reachable from a constant's type to implement the
/// structural-match traits, which essentially say that
/// the implementation of `PartialEq::eq` behaves *equivalently* to a
/// comparison against the unfolded structure.
///
/// For more background on why Rust has this requirement, and issues
/// that arose when the requirement was not enforced completely, see
/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
pub fn search_for_structural_match_violation<'tcx>(
    id: hir::HirId,
    span: Span,
    tcx: TyCtxt<'tcx>,
    ty: Ty<'tcx>,
) -> Option<NonStructuralMatchTy<'tcx>> {
    // FIXME: we should instead pass in an `infcx` from the outside.
    tcx.infer_ctxt().enter(|infcx| {
        let mut search = Search { id, span, infcx, found: None, seen: FxHashSet::default() };
        ty.visit_with(&mut search);
        search.found
    })
}

/// This method returns true if and only if `adt_ty` itself has been marked as
/// eligible for structural-match: namely, if it implements both
/// `StructuralPartialEq` and `StructuralEq` (which are respectively injected by
/// `#[derive(PartialEq)]` and `#[derive(Eq)]`).
///
/// Note that this does *not* recursively check if the substructure of `adt_ty`
/// implements the traits.
pub fn type_marked_structural(
    id: hir::HirId,
    span: Span,
    infcx: &InferCtxt<'_, 'tcx>,
    adt_ty: Ty<'tcx>,
) -> bool {
    let mut fulfillment_cx = traits::FulfillmentContext::new();
    let cause = ObligationCause::new(span, id, ConstPatternStructural);
    // require `#[derive(PartialEq)]`
    let structural_peq_def_id = infcx.tcx.require_lang_item(StructuralPeqTraitLangItem, Some(span));
    fulfillment_cx.register_bound(
        infcx,
        ty::ParamEnv::empty(),
        adt_ty,
        structural_peq_def_id,
        cause,
    );
    // for now, require `#[derive(Eq)]`. (Doing so is a hack to work around
    // the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.)
    let cause = ObligationCause::new(span, id, ConstPatternStructural);
    let structural_teq_def_id = infcx.tcx.require_lang_item(StructuralTeqTraitLangItem, Some(span));
    fulfillment_cx.register_bound(
        infcx,
        ty::ParamEnv::empty(),
        adt_ty,
        structural_teq_def_id,
        cause,
    );

    // We deliberately skip *reporting* fulfillment errors (via
    // `report_fulfillment_errors`), for two reasons:
    //
    // 1. The error messages would mention `std::marker::StructuralPartialEq`
    //    (a trait which is solely meant as an implementation detail
    //    for now), and
    //
    // 2. We are sometimes doing future-incompatibility lints for
    //    now, so we do not want unconditional errors here.
    fulfillment_cx.select_all_or_error(infcx).is_ok()
}

/// This implements the traversal over the structure of a given type to try to
/// find instances of ADTs (specifically structs or enums) that do not implement
/// the structural-match traits (`StructuralPartialEq` and `StructuralEq`).
struct Search<'a, 'tcx> {
    id: hir::HirId,
    span: Span,

    infcx: InferCtxt<'a, 'tcx>,

    /// Records first ADT that does not implement a structural-match trait.
    found: Option<NonStructuralMatchTy<'tcx>>,

    /// Tracks ADTs previously encountered during search, so that
    /// we will not recur on them again.
    seen: FxHashSet<hir::def_id::DefId>,
}

impl Search<'a, 'tcx> {
    fn tcx(&self) -> TyCtxt<'tcx> {
        self.infcx.tcx
    }

    fn type_marked_structural(&self, adt_ty: Ty<'tcx>) -> bool {
        type_marked_structural(self.id, self.span, &self.infcx, adt_ty)
    }
}

impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
    fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
        debug!("Search visiting ty: {:?}", ty);

        let (adt_def, substs) = match ty.kind {
            ty::Adt(adt_def, substs) => (adt_def, substs),
            ty::Param(_) => {
                self.found = Some(NonStructuralMatchTy::Param);
                return true; // Stop visiting.
            }
            ty::Dynamic(..) => {
                self.found = Some(NonStructuralMatchTy::Dynamic);
                return true; // Stop visiting.
            }
            ty::Foreign(_) => {
                self.found = Some(NonStructuralMatchTy::Foreign);
                return true; // Stop visiting
            }
            ty::Opaque(..) => {
                self.found = Some(NonStructuralMatchTy::Opaque);
                return true;
            }
            ty::Projection(..) => {
                self.found = Some(NonStructuralMatchTy::Projection);
                return true;
            }
            ty::Generator(..) | ty::GeneratorWitness(..) => {
                self.found = Some(NonStructuralMatchTy::Generator);
                return true;
            }
            ty::RawPtr(..) => {
                // structural-match ignores substructure of
                // `*const _`/`*mut _`, so skip `super_visit_with`.
                //
                // For example, if you have:
                // ```
                // struct NonStructural;
                // #[derive(PartialEq, Eq)]
                // struct T(*const NonStructural);
                // const C: T = T(std::ptr::null());
                // ```
                //
                // Even though `NonStructural` does not implement `PartialEq`,
                // structural equality on `T` does not recur into the raw
                // pointer. Therefore, one can still use `C` in a pattern.

                // (But still tell caller to continue search.)
                return false;
            }
            ty::FnDef(..) | ty::FnPtr(..) => {
                // Types of formals and return in `fn(_) -> _` are also irrelevant;
                // so we do not recur into them via `super_visit_with`
                //
                // (But still tell caller to continue search.)
                return false;
            }
            ty::Array(_, n)
                if { n.try_eval_usize(self.tcx(), ty::ParamEnv::reveal_all()) == Some(0) } =>
            {
                // rust-lang/rust#62336: ignore type of contents
                // for empty array.
                return false;
            }
            ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => {
                // These primitive types are always structural match.
                //
                // `Never` is kind of special here, but as it is not inhabitable, this should be fine.
                return false;
            }

            ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => {
                ty.super_visit_with(self);
                return false;
            }
            ty::Closure(..) | ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
                bug!("unexpected type during structural-match checking: {:?}", ty);
            }
            ty::Error => {
                self.tcx().sess.delay_span_bug(self.span, "ty::Error in structural-match check");
                // We still want to check other types after encountering an error,
                // as this may still emit relevant errors.
                return false;
            }
        };

        if !self.seen.insert(adt_def.did) {
            debug!("Search already seen adt_def: {:?}", adt_def);
            // let caller continue its search
            return false;
        }

        if !self.type_marked_structural(ty) {
            debug!("Search found ty: {:?}", ty);
            self.found = Some(NonStructuralMatchTy::Adt(&adt_def));
            return true; // Halt visiting!
        }

        // structural-match does not care about the
        // instantiation of the generics in an ADT (it
        // instead looks directly at its fields outside
        // this match), so we skip super_visit_with.
        //
        // (Must not recur on substs for `PhantomData<T>` cf
        // rust-lang/rust#55028 and rust-lang/rust#55837; but also
        // want to skip substs when only uses of generic are
        // behind unsafe pointers `*const T`/`*mut T`.)

        // even though we skip super_visit_with, we must recur on
        // fields of ADT.
        let tcx = self.tcx();
        for field_ty in adt_def.all_fields().map(|field| field.ty(tcx, substs)) {
            if field_ty.visit_with(self) {
                // found an ADT without structural-match; halt visiting!
                assert!(self.found.is_some());
                return true;
            }
        }

        // Even though we do not want to recur on substs, we do
        // want our caller to continue its own search.
        false
    }
}
<commit_msg>comment return sites<commit_after>use crate::infer::{InferCtxt, TyCtxtInferExt};
use crate::traits::ObligationCause;
use crate::traits::{self, ConstPatternStructural, TraitEngine};

use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::lang_items::{StructuralPeqTraitLangItem, StructuralTeqTraitLangItem};
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_span::Span;

#[derive(Debug)]
pub enum NonStructuralMatchTy<'tcx> {
    Adt(&'tcx AdtDef),
    Param,
    Dynamic,
    Foreign,
    Opaque,
    Generator,
    Projection,
}

/// This method traverses the structure of `ty`, trying to find an
/// instance of an ADT (i.e. struct or enum) that doesn't implement
/// the structural-match traits, or a generic type parameter
/// (which cannot be determined to be structural-match).
///
/// The "structure of a type" includes all components that would be
/// considered when doing a pattern match on a constant of that
/// type.
///
///  * This means this method descends into fields of structs/enums,
///    and also descends into the inner type `T` of `&T` and `&mut T`
///
///  * The traversal doesn't dereference unsafe pointers (`*const T`,
///    `*mut T`), and it does not visit the type arguments of an
///    instantiated generic like `PhantomData<T>`.
///
/// The reason we do this search is Rust currently require all ADTs
/// reachable from a constant's type to implement the
/// structural-match traits, which essentially say that
/// the implementation of `PartialEq::eq` behaves *equivalently* to a
/// comparison against the unfolded structure.
///
/// For more background on why Rust has this requirement, and issues
/// that arose when the requirement was not enforced completely, see
/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
pub fn search_for_structural_match_violation<'tcx>(
    id: hir::HirId,
    span: Span,
    tcx: TyCtxt<'tcx>,
    ty: Ty<'tcx>,
) -> Option<NonStructuralMatchTy<'tcx>> {
    // FIXME: we should instead pass in an `infcx` from the outside.
    tcx.infer_ctxt().enter(|infcx| {
        let mut search = Search { id, span, infcx, found: None, seen: FxHashSet::default() };
        ty.visit_with(&mut search);
        search.found
    })
}

/// This method returns true if and only if `adt_ty` itself has been marked as
/// eligible for structural-match: namely, if it implements both
/// `StructuralPartialEq` and `StructuralEq` (which are respectively injected by
/// `#[derive(PartialEq)]` and `#[derive(Eq)]`).
///
/// Note that this does *not* recursively check if the substructure of `adt_ty`
/// implements the traits.
pub fn type_marked_structural(
    id: hir::HirId,
    span: Span,
    infcx: &InferCtxt<'_, 'tcx>,
    adt_ty: Ty<'tcx>,
) -> bool {
    let mut fulfillment_cx = traits::FulfillmentContext::new();
    let cause = ObligationCause::new(span, id, ConstPatternStructural);
    // require `#[derive(PartialEq)]`
    let structural_peq_def_id = infcx.tcx.require_lang_item(StructuralPeqTraitLangItem, Some(span));
    fulfillment_cx.register_bound(
        infcx,
        ty::ParamEnv::empty(),
        adt_ty,
        structural_peq_def_id,
        cause,
    );
    // for now, require `#[derive(Eq)]`. (Doing so is a hack to work around
    // the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.)
    let cause = ObligationCause::new(span, id, ConstPatternStructural);
    let structural_teq_def_id = infcx.tcx.require_lang_item(StructuralTeqTraitLangItem, Some(span));
    fulfillment_cx.register_bound(
        infcx,
        ty::ParamEnv::empty(),
        adt_ty,
        structural_teq_def_id,
        cause,
    );

    // We deliberately skip *reporting* fulfillment errors (via
    // `report_fulfillment_errors`), for two reasons:
    //
    // 1. The error messages would mention `std::marker::StructuralPartialEq`
    //    (a trait which is solely meant as an implementation detail
    //    for now), and
    //
    // 2. We are sometimes doing future-incompatibility lints for
    //    now, so we do not want unconditional errors here.
    fulfillment_cx.select_all_or_error(infcx).is_ok()
}

/// This implements the traversal over the structure of a given type to try to
/// find instances of ADTs (specifically structs or enums) that do not implement
/// the structural-match traits (`StructuralPartialEq` and `StructuralEq`).
struct Search<'a, 'tcx> {
    id: hir::HirId,
    span: Span,

    infcx: InferCtxt<'a, 'tcx>,

    /// Records first ADT that does not implement a structural-match trait.
    found: Option<NonStructuralMatchTy<'tcx>>,

    /// Tracks ADTs previously encountered during search, so that
    /// we will not recur on them again.
    seen: FxHashSet<hir::def_id::DefId>,
}

impl Search<'a, 'tcx> {
    fn tcx(&self) -> TyCtxt<'tcx> {
        self.infcx.tcx
    }

    fn type_marked_structural(&self, adt_ty: Ty<'tcx>) -> bool {
        type_marked_structural(self.id, self.span, &self.infcx, adt_ty)
    }
}

impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
    fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
        debug!("Search visiting ty: {:?}", ty);

        let (adt_def, substs) = match ty.kind {
            ty::Adt(adt_def, substs) => (adt_def, substs),
            ty::Param(_) => {
                self.found = Some(NonStructuralMatchTy::Param);
                return true; // Stop visiting.
            }
            ty::Dynamic(..) => {
                self.found = Some(NonStructuralMatchTy::Dynamic);
                return true; // Stop visiting.
            }
            ty::Foreign(_) => {
                self.found = Some(NonStructuralMatchTy::Foreign);
                return true; // Stop visiting.
            }
            ty::Opaque(..) => {
                self.found = Some(NonStructuralMatchTy::Opaque);
                return true; // Stop visiting.
            }
            ty::Projection(..) => {
                self.found = Some(NonStructuralMatchTy::Projection);
                return true; // Stop visiting.
            }
            ty::Generator(..) | ty::GeneratorWitness(..) => {
                self.found = Some(NonStructuralMatchTy::Generator);
                return true; // Stop visiting.
            }
            ty::RawPtr(..) => {
                // structural-match ignores substructure of
                // `*const _`/`*mut _`, so skip `super_visit_with`.
                //
                // For example, if you have:
                // ```
                // struct NonStructural;
                // #[derive(PartialEq, Eq)]
                // struct T(*const NonStructural);
                // const C: T = T(std::ptr::null());
                // ```
                //
                // Even though `NonStructural` does not implement `PartialEq`,
                // structural equality on `T` does not recur into the raw
                // pointer. Therefore, one can still use `C` in a pattern.

                // (But still tell the caller to continue search.)
                return false;
            }
            ty::FnDef(..) | ty::FnPtr(..) => {
                // Types of formals and return in `fn(_) -> _` are also irrelevant;
                // so we do not recur into them via `super_visit_with`
                //
                // (But still tell the caller to continue search.)
                return false;
            }
            ty::Array(_, n)
                if { n.try_eval_usize(self.tcx(), ty::ParamEnv::reveal_all()) == Some(0) } =>
            {
                // rust-lang/rust#62336: ignore type of contents
                // for empty array.
                //
                // (But still tell the caller to continue search.)
                return false;
            }
            ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => {
                // These primitive types are always structural match.
                //
                // `Never` is kind of special here, but as it is not inhabitable, this should be fine.
                //
                // (But still tell the caller to continue search.)
                return false;
            }

            ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => {
                // First check all contained types and then tell the caller to continue searching.
                ty.super_visit_with(self);
                return false;
            }
            ty::Closure(..) | ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
                bug!("unexpected type during structural-match checking: {:?}", ty);
            }
            ty::Error => {
                self.tcx().sess.delay_span_bug(self.span, "ty::Error in structural-match check");
                // We still want to check other types after encountering an error,
                // as this may still emit relevant errors.
                //
                // So we continue searching here.
                return false;
            }
        };

        if !self.seen.insert(adt_def.did) {
            debug!("Search already seen adt_def: {:?}", adt_def);
            // Let caller continue its search.
            return false;
        }

        if !self.type_marked_structural(ty) {
            debug!("Search found ty: {:?}", ty);
            self.found = Some(NonStructuralMatchTy::Adt(&adt_def));
            return true; // Halt visiting!
        }

        // structural-match does not care about the
        // instantiation of the generics in an ADT (it
        // instead looks directly at its fields outside
        // this match), so we skip super_visit_with.
        //
        // (Must not recur on substs for `PhantomData<T>` cf
        // rust-lang/rust#55028 and rust-lang/rust#55837; but also
        // want to skip substs when only uses of generic are
        // behind unsafe pointers `*const T`/`*mut T`.)

        // even though we skip super_visit_with, we must recur on
        // fields of ADT.
        let tcx = self.tcx();
        for field_ty in adt_def.all_fields().map(|field| field.ty(tcx, substs)) {
            if field_ty.visit_with(self) {
                // found an ADT without structural-match; halt visiting!
                assert!(self.found.is_some());
                return true;
            }
        }

        // Even though we do not want to recur on substs, we do
        // want our caller to continue its own search.
        false
    }
}
<|endoftext|>


<commit_before>//! Parse impl blocks.
#![allow(clippy::or_fun_call)]

use crate::util::{self, span_container::SpanContainer};
use proc_macro2::{Ident, TokenStream};
use quote::quote;
use std::convert::From;
use syn::{spanned::Spanned, PatType};

pub struct ImplBlock {
    pub attrs: util::ObjectAttributes,
    pub target_trait: Option<(String, syn::Path)>,
    pub target_type: Box<syn::Type>,
    pub type_ident: syn::Ident,
    pub generics: syn::Generics,
    // _impl: syn::ItemImpl,
    pub methods: Vec<syn::ImplItemMethod>,
    pub description: Option<String>,
}

impl ImplBlock {
    /// Parse a `fn <NAME>() -> <TYPE>` method declaration found in
    /// objects.
    pub fn parse_method<
        F: Fn(
            &PatType,
            &Ident,
            bool,
        ) -> syn::Result<(TokenStream, util::GraphQLTypeDefinitionFieldArg)>,
    >(
        &self,
        method: &syn::ImplItemMethod,
        is_self_optional: bool,
        f: F,
    ) -> syn::Result<(Vec<TokenStream>, Vec<util::GraphQLTypeDefinitionFieldArg>)> {
        let mut arguments = method.sig.inputs.iter().peekable();

        // Verify `&self` argument.
        match arguments.peek() {
            Some(syn::FnArg::Receiver(rec)) => {
                let _consume = arguments.next();
                if rec.reference.is_none() || rec.mutability.is_some() {
                    return Err(syn::Error::new(
                        rec.span(),
                        "invalid argument: did you mean `&self`?",
                    ));
                }
            }
            _ => {
                if !is_self_optional {
                    return Err(syn::Error::new(
                        method.sig.span(),
                        "expected a `&self` argument",
                    ));
                }
            }
        }

        let mut resolve_parts = Vec::new();
        let mut additional_arguments = Vec::new();

        for arg in arguments {
            match arg {
                syn::FnArg::Receiver(_) => {
                    if !is_self_optional {
                        return Err(syn::Error::new(
                            method.sig.ident.span(),
                            "self receiver must be the first argument",
                        ));
                    }
                }
                syn::FnArg::Typed(captured) => {
                    let (arg_ident, is_mut) = match &*captured.pat {
                        syn::Pat::Ident(ref pat_ident) => {
                            (&pat_ident.ident, pat_ident.mutability.is_some())
                        }
                        _ => {
                            return Err(syn::Error::new(
                                captured.pat.span(),
                                "expected identifier for function argument",
                            ));
                        }
                    };
                    let context_type = self.attrs.context.as_ref();

                    // Check for executor arguments.
                    if util::type_is_identifier_ref(&captured.ty, "Executor") {
                        resolve_parts.push(quote!(let #arg_ident = executor;));
                    }
                    // Make sure executor is specified as a reference.
                    else if util::type_is_identifier(&captured.ty, "Executor") {
                        return Err(syn::Error::new(
                            captured.ty.span(),
                            "to access the Executor, you need to specify the type as a reference.\nDid you mean &Executor?"
                        ));
                    }
                    // Check for context arg.
                    else if context_type
                        .clone()
                        .map(|ctx| util::type_is_ref_of(&captured.ty, ctx))
                        .unwrap_or(false)
                    {
                        resolve_parts.push(quote!( let #arg_ident = executor.context(); ));
                    }
                    // Make sure the user does not specify the Context
                    //  without a reference. (&Context)
                    else if context_type
                        .clone()
                        .map(|ctx| ctx.inner() == &*captured.ty)
                        .unwrap_or(false)
                    {
                        return Err(syn::Error::new(
                            captured.ty.span(),
                            format!("to access the context, you need to specify the type as a reference.\nDid you mean &{}?", quote!(captured.ty)),
                        ));
                    } else {
                        let (tokens, ty) = f(captured, arg_ident, is_mut)?;
                        resolve_parts.push(tokens);
                        additional_arguments.push(ty);
                    }
                }
            }
        }

        Ok((resolve_parts, additional_arguments))
    }

    pub fn parse(attr_tokens: TokenStream, body: TokenStream) -> syn::Result<ImplBlock> {
        let attrs = syn::parse2::<util::ObjectAttributes>(attr_tokens)?;
        let mut _impl = syn::parse2::<syn::ItemImpl>(body)?;

        let target_trait = match _impl.clone().trait_ {
            Some((_, path, _)) => {
                let name = path
                    .segments
                    .iter()
                    .map(|segment| segment.ident.to_string())
                    .collect::<Vec<_>>()
                    .join(".");
                Some((name, path))
            }
            None => None,
        };

        let type_ident = if let Some(ident) = util::name_of_type(&*_impl.self_ty) {
            ident
        } else {
            return Err(syn::Error::new(
                _impl.self_ty.span(),
                "could not determine a name for the impl type",
            ));
        };

        let target_type = _impl.self_ty.clone();

        let description = attrs
            .description
            .clone()
            .or_else(|| util::get_doc_comment(&_impl.attrs.clone()));

        let mut methods = Vec::new();

        for item in _impl.items {
            match item {
                syn::ImplItem::Method(method) => {
                    methods.push(method);
                }
                _ => {
                    return Err(syn::Error::new(
                        item.span(),
                        "only type declarations and methods are allowed",
                    ));
                }
            }
        }

        Ok(Self {
            attrs,
            type_ident,
            target_trait,
            target_type,
            generics: _impl.generics,
            description: description.map(SpanContainer::into_inner),
            methods,
        })
    }
}
<commit_msg>Fix codegen failure tests for the latest nightly Rust<commit_after>//! Parse impl blocks.
#![allow(clippy::or_fun_call)]

use crate::util::{self, span_container::SpanContainer};
use proc_macro2::{Ident, TokenStream};
use quote::quote;
use syn::{spanned::Spanned, PatType};

pub struct ImplBlock {
    pub attrs: util::ObjectAttributes,
    pub target_trait: Option<(String, syn::Path)>,
    pub target_type: Box<syn::Type>,
    pub type_ident: syn::Ident,
    pub generics: syn::Generics,
    // _impl: syn::ItemImpl,
    pub methods: Vec<syn::ImplItemMethod>,
    pub description: Option<String>,
}

impl ImplBlock {
    /// Parse a `fn <NAME>() -> <TYPE>` method declaration found in
    /// objects.
    pub fn parse_method<
        F: Fn(
            &PatType,
            &Ident,
            bool,
        ) -> syn::Result<(TokenStream, util::GraphQLTypeDefinitionFieldArg)>,
    >(
        &self,
        method: &syn::ImplItemMethod,
        is_self_optional: bool,
        f: F,
    ) -> syn::Result<(Vec<TokenStream>, Vec<util::GraphQLTypeDefinitionFieldArg>)> {
        let mut arguments = method.sig.inputs.iter().peekable();

        // Verify `&self` argument.
        match arguments.peek() {
            Some(syn::FnArg::Receiver(rec)) => {
                let _consume = arguments.next();
                if rec.reference.is_none() || rec.mutability.is_some() {
                    return Err(syn::Error::new(
                        rec.span(),
                        "invalid argument: did you mean `&self`?",
                    ));
                }
            }
            _ => {
                if !is_self_optional {
                    return Err(syn::Error::new(
                        method.sig.span(),
                        "expected a `&self` argument",
                    ));
                }
            }
        }

        let mut resolve_parts = Vec::new();
        let mut additional_arguments = Vec::new();

        for arg in arguments {
            match arg {
                syn::FnArg::Receiver(_) => {
                    if !is_self_optional {
                        return Err(syn::Error::new(
                            method.sig.ident.span(),
                            "self receiver must be the first argument",
                        ));
                    }
                }
                syn::FnArg::Typed(captured) => {
                    let (arg_ident, is_mut) = match &*captured.pat {
                        syn::Pat::Ident(ref pat_ident) => {
                            (&pat_ident.ident, pat_ident.mutability.is_some())
                        }
                        _ => {
                            return Err(syn::Error::new(
                                captured.pat.span(),
                                "expected identifier for function argument",
                            ));
                        }
                    };
                    let context_type = self.attrs.context.as_ref();

                    // Check for executor arguments.
                    if util::type_is_identifier_ref(&captured.ty, "Executor") {
                        resolve_parts.push(quote!(let #arg_ident = executor;));
                    }
                    // Make sure executor is specified as a reference.
                    else if util::type_is_identifier(&captured.ty, "Executor") {
                        return Err(syn::Error::new(
                            captured.ty.span(),
                            "to access the Executor, you need to specify the type as a reference.\nDid you mean &Executor?"
                        ));
                    }
                    // Check for context arg.
                    else if context_type
                        .clone()
                        .map(|ctx| util::type_is_ref_of(&captured.ty, ctx))
                        .unwrap_or(false)
                    {
                        resolve_parts.push(quote!( let #arg_ident = executor.context(); ));
                    }
                    // Make sure the user does not specify the Context
                    //  without a reference. (&Context)
                    else if context_type
                        .clone()
                        .map(|ctx| ctx.inner() == &*captured.ty)
                        .unwrap_or(false)
                    {
                        return Err(syn::Error::new(
                            captured.ty.span(),
                            format!("to access the context, you need to specify the type as a reference.\nDid you mean &{}?", quote!(captured.ty)),
                        ));
                    } else {
                        let (tokens, ty) = f(captured, arg_ident, is_mut)?;
                        resolve_parts.push(tokens);
                        additional_arguments.push(ty);
                    }
                }
            }
        }

        Ok((resolve_parts, additional_arguments))
    }

    pub fn parse(attr_tokens: TokenStream, body: TokenStream) -> syn::Result<ImplBlock> {
        let attrs = syn::parse2::<util::ObjectAttributes>(attr_tokens)?;
        let mut _impl = syn::parse2::<syn::ItemImpl>(body)?;

        let target_trait = match _impl.clone().trait_ {
            Some((_, path, _)) => {
                let name = path
                    .segments
                    .iter()
                    .map(|segment| segment.ident.to_string())
                    .collect::<Vec<_>>()
                    .join(".");
                Some((name, path))
            }
            None => None,
        };

        let type_ident = if let Some(ident) = util::name_of_type(&*_impl.self_ty) {
            ident
        } else {
            return Err(syn::Error::new(
                _impl.self_ty.span(),
                "could not determine a name for the impl type",
            ));
        };

        let target_type = _impl.self_ty.clone();

        let description = attrs
            .description
            .clone()
            .or_else(|| util::get_doc_comment(&_impl.attrs.clone()));

        let mut methods = Vec::new();

        for item in _impl.items {
            match item {
                syn::ImplItem::Method(method) => {
                    methods.push(method);
                }
                _ => {
                    return Err(syn::Error::new(
                        item.span(),
                        "only type declarations and methods are allowed",
                    ));
                }
            }
        }

        Ok(Self {
            attrs,
            type_ident,
            target_trait,
            target_type,
            generics: _impl.generics,
            description: description.map(SpanContainer::into_inner),
            methods,
        })
    }
}
<|endoftext|>


<commit_before><commit_msg>Remove unnecessary & in match arms<commit_after><|endoftext|>


<commit_before>#![feature(macro_rules)]

macro_rules! swap {
    ($x:ident, $y:ident) => {
        {
            let tmp = $x;
            $x = $y;
            $y = tmp;
        }
    }
}

fn main() {
    let mut a = 1i;
    let mut b = 2i;

    swap!(a, b);

    println!("a: {} b: {}", a, b);
}
<commit_msg>Allow arbitrary l-values in our Rust swap.<commit_after>#![feature(macro_rules)]

macro_rules! swap {
    ($x:expr, $y:expr) => {
        {
            let tmp = $x;
            $x = $y;
            $y = tmp;
        }
    }
}

fn main() {
    let mut a = 1i;
    let mut b = 2i;

    swap!(a, b);
    println!("a: {} b: {}", a, b);

    let mut c = [3i, 4i];

    swap!(c[0], c[1]);
    println!("c[0]: {} c[1]: {}", c[0], c[1]);
}
<|endoftext|>


<commit_before>use hir::ModuleDef;
use ide_db::helpers::{import_assets::NameToImport, mod_path_to_ast};
use ide_db::items_locator;
use itertools::Itertools;
use syntax::{
    ast::{self, make, AstNode, NameOwner},
    SyntaxKind::{IDENT, WHITESPACE},
};

use crate::{
    assist_context::{AssistBuilder, AssistContext, Assists},
    utils::{
        add_trait_assoc_items_to_impl, filter_assoc_items, generate_trait_impl_text,
        render_snippet, Cursor, DefaultMethods,
    },
    AssistId, AssistKind,
};

// Assist: replace_derive_with_manual_impl
//
// Converts a `derive` impl into a manual one.
//
// ```
// # trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
// #[derive(Deb$0ug, Display)]
// struct S;
// ```
// ->
// ```
// # trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
// #[derive(Display)]
// struct S;
//
// impl Debug for S {
//     fn fmt(&self, f: &mut Formatter) -> Result<()> {
//         ${0:todo!()}
//     }
// }
// ```
pub(crate) fn replace_derive_with_manual_impl(
    acc: &mut Assists,
    ctx: &AssistContext,
) -> Option<()> {
    let attr = ctx.find_node_at_offset::<ast::Attr>()?;
    let (name, args) = attr.as_simple_call()?;
    if name != "derive" {
        return None;
    }

    let trait_token = args.syntax().token_at_offset(ctx.offset()).find(|t| t.kind() == IDENT)?;
    let trait_name = trait_token.text();

    let adt = attr.syntax().parent().and_then(ast::Adt::cast)?;

    let current_module = ctx.sema.scope(adt.syntax()).module()?;
    let current_crate = current_module.krate();

    let found_traits = items_locator::items_with_name(
        &ctx.sema,
        current_crate,
        NameToImport::Exact(trait_name.to_string()),
        items_locator::AssocItemSearch::Exclude,
        Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT),
    )
    .filter_map(|item| match ModuleDef::from(item.as_module_def_id()?) {
        ModuleDef::Trait(trait_) => Some(trait_),
        _ => None,
    })
    .flat_map(|trait_| {
        current_module
            .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_))
            .as_ref()
            .map(mod_path_to_ast)
            .zip(Some(trait_))
    });

    let mut no_traits_found = true;
    for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) {
        add_assist(acc, ctx, &attr, &args, &trait_path, Some(trait_), &adt)?;
    }
    if no_traits_found {
        let trait_path = make::path_unqualified(make::path_segment(make::name_ref(trait_name)));
        add_assist(acc, ctx, &attr, &args, &trait_path, None, &adt)?;
    }
    Some(())
}

fn add_assist(
    acc: &mut Assists,
    ctx: &AssistContext,
    attr: &ast::Attr,
    input: &ast::TokenTree,
    trait_path: &ast::Path,
    trait_: Option<hir::Trait>,
    adt: &ast::Adt,
) -> Option<()> {
    let target = attr.syntax().text_range();
    let annotated_name = adt.name()?;
    let label = format!("Convert to manual `impl {} for {}`", trait_path, annotated_name);
    let trait_name = trait_path.segment().and_then(|seg| seg.name_ref())?;

    acc.add(
        AssistId("replace_derive_with_manual_impl", AssistKind::Refactor),
        label,
        target,
        |builder| {
            let insert_pos = adt.syntax().text_range().end();
            let impl_def_with_items =
                impl_def_from_trait(&ctx.sema, &annotated_name, trait_, trait_path);
            update_attribute(builder, &input, &trait_name, &attr);
            let trait_path = format!("{}", trait_path);
            match (ctx.config.snippet_cap, impl_def_with_items) {
                (None, _) => {
                    builder.insert(insert_pos, generate_trait_impl_text(adt, &trait_path, ""))
                }
                (Some(cap), None) => builder.insert_snippet(
                    cap,
                    insert_pos,
                    generate_trait_impl_text(adt, &trait_path, "    $0"),
                ),
                (Some(cap), Some((impl_def, first_assoc_item))) => {
                    let mut cursor = Cursor::Before(first_assoc_item.syntax());
                    let placeholder;
                    if let ast::AssocItem::Fn(ref func) = first_assoc_item {
                        if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
                        {
                            if m.syntax().text() == "todo!()" {
                                placeholder = m;
                                cursor = Cursor::Replace(placeholder.syntax());
                            }
                        }
                    }

                    builder.insert_snippet(
                        cap,
                        insert_pos,
                        format!("\n\n{}", render_snippet(cap, impl_def.syntax(), cursor)),
                    )
                }
            };
        },
    )
}

fn impl_def_from_trait(
    sema: &hir::Semantics<ide_db::RootDatabase>,
    annotated_name: &ast::Name,
    trait_: Option<hir::Trait>,
    trait_path: &ast::Path,
) -> Option<(ast::Impl, ast::AssocItem)> {
    let trait_ = trait_?;
    let target_scope = sema.scope(annotated_name.syntax());
    let trait_items = filter_assoc_items(sema.db, &trait_.items(sema.db), DefaultMethods::No);
    if trait_items.is_empty() {
        return None;
    }
    let impl_def = make::impl_trait(
        trait_path.clone(),
        make::path_unqualified(make::path_segment(make::name_ref(&annotated_name.text()))),
    );
    let (impl_def, first_assoc_item) =
        add_trait_assoc_items_to_impl(sema, trait_items, trait_, impl_def, target_scope);
    Some((impl_def, first_assoc_item))
}

fn update_attribute(
    builder: &mut AssistBuilder,
    input: &ast::TokenTree,
    trait_name: &ast::NameRef,
    attr: &ast::Attr,
) {
    let trait_name = trait_name.text();
    let new_attr_input = input
        .syntax()
        .descendants_with_tokens()
        .filter(|t| t.kind() == IDENT)
        .filter_map(|t| t.into_token().map(|t| t.text().to_string()))
        .filter(|t| t != &trait_name)
        .collect::<Vec<_>>();
    let has_more_derives = !new_attr_input.is_empty();

    if has_more_derives {
        let new_attr_input = format!("({})", new_attr_input.iter().format(", "));
        builder.replace(input.syntax().text_range(), new_attr_input);
    } else {
        let attr_range = attr.syntax().text_range();
        builder.delete(attr_range);

        if let Some(line_break_range) = attr
            .syntax()
            .next_sibling_or_token()
            .filter(|t| t.kind() == WHITESPACE)
            .map(|t| t.text_range())
        {
            builder.delete(line_break_range);
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn add_custom_impl_debug() {
        check_assist(
            replace_derive_with_manual_impl,
            "
mod fmt {
    pub struct Error;
    pub type Result = Result<(), Error>;
    pub struct Formatter<'a>;
    pub trait Debug {
        fn fmt(&self, f: &mut Formatter<'_>) -> Result;
    }
}

#[derive(Debu$0g)]
struct Foo {
    bar: String,
}
",
            "
mod fmt {
    pub struct Error;
    pub type Result = Result<(), Error>;
    pub struct Formatter<'a>;
    pub trait Debug {
        fn fmt(&self, f: &mut Formatter<'_>) -> Result;
    }
}

struct Foo {
    bar: String,
}

impl fmt::Debug for Foo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        ${0:todo!()}
    }
}
",
        )
    }
    #[test]
    fn add_custom_impl_all() {
        check_assist(
            replace_derive_with_manual_impl,
            "
mod foo {
    pub trait Bar {
        type Qux;
        const Baz: usize = 42;
        const Fez: usize;
        fn foo();
        fn bar() {}
    }
}

#[derive($0Bar)]
struct Foo {
    bar: String,
}
",
            "
mod foo {
    pub trait Bar {
        type Qux;
        const Baz: usize = 42;
        const Fez: usize;
        fn foo();
        fn bar() {}
    }
}

struct Foo {
    bar: String,
}

impl foo::Bar for Foo {
    $0type Qux;

    const Baz: usize = 42;

    const Fez: usize;

    fn foo() {
        todo!()
    }
}
",
        )
    }
    #[test]
    fn add_custom_impl_for_unique_input() {
        check_assist(
            replace_derive_with_manual_impl,
            "
#[derive(Debu$0g)]
struct Foo {
    bar: String,
}
            ",
            "
struct Foo {
    bar: String,
}

impl Debug for Foo {
    $0
}
            ",
        )
    }

    #[test]
    fn add_custom_impl_for_with_visibility_modifier() {
        check_assist(
            replace_derive_with_manual_impl,
            "
#[derive(Debug$0)]
pub struct Foo {
    bar: String,
}
            ",
            "
pub struct Foo {
    bar: String,
}

impl Debug for Foo {
    $0
}
            ",
        )
    }

    #[test]
    fn add_custom_impl_when_multiple_inputs() {
        check_assist(
            replace_derive_with_manual_impl,
            "
#[derive(Display, Debug$0, Serialize)]
struct Foo {}
            ",
            "
#[derive(Display, Serialize)]
struct Foo {}

impl Debug for Foo {
    $0
}
            ",
        )
    }

    #[test]
    fn test_ignore_derive_macro_without_input() {
        check_assist_not_applicable(
            replace_derive_with_manual_impl,
            "
#[derive($0)]
struct Foo {}
            ",
        )
    }

    #[test]
    fn test_ignore_if_cursor_on_param() {
        check_assist_not_applicable(
            replace_derive_with_manual_impl,
            "
#[derive$0(Debug)]
struct Foo {}
            ",
        );

        check_assist_not_applicable(
            replace_derive_with_manual_impl,
            "
#[derive(Debug)$0]
struct Foo {}
            ",
        )
    }

    #[test]
    fn test_ignore_if_not_derive() {
        check_assist_not_applicable(
            replace_derive_with_manual_impl,
            "
#[allow(non_camel_$0case_types)]
struct Foo {}
            ",
        )
    }
}
<commit_msg>Fix panic in `replace_derive_with_manual_impl`<commit_after>use hir::ModuleDef;
use ide_db::helpers::{import_assets::NameToImport, mod_path_to_ast};
use ide_db::items_locator;
use itertools::Itertools;
use syntax::{
    ast::{self, make, AstNode, NameOwner},
    SyntaxKind::{IDENT, WHITESPACE},
};

use crate::{
    assist_context::{AssistBuilder, AssistContext, Assists},
    utils::{
        add_trait_assoc_items_to_impl, filter_assoc_items, generate_trait_impl_text,
        render_snippet, Cursor, DefaultMethods,
    },
    AssistId, AssistKind,
};

// Assist: replace_derive_with_manual_impl
//
// Converts a `derive` impl into a manual one.
//
// ```
// # trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
// #[derive(Deb$0ug, Display)]
// struct S;
// ```
// ->
// ```
// # trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
// #[derive(Display)]
// struct S;
//
// impl Debug for S {
//     fn fmt(&self, f: &mut Formatter) -> Result<()> {
//         ${0:todo!()}
//     }
// }
// ```
pub(crate) fn replace_derive_with_manual_impl(
    acc: &mut Assists,
    ctx: &AssistContext,
) -> Option<()> {
    let attr = ctx.find_node_at_offset::<ast::Attr>()?;
    let (name, args) = attr.as_simple_call()?;
    if name != "derive" {
        return None;
    }

    if !args.syntax().text_range().contains(ctx.offset()) {
        cov_mark::hit!(outside_of_attr_args);
        return None;
    }

    let trait_token = args.syntax().token_at_offset(ctx.offset()).find(|t| t.kind() == IDENT)?;
    let trait_name = trait_token.text();

    let adt = attr.syntax().parent().and_then(ast::Adt::cast)?;

    let current_module = ctx.sema.scope(adt.syntax()).module()?;
    let current_crate = current_module.krate();

    let found_traits = items_locator::items_with_name(
        &ctx.sema,
        current_crate,
        NameToImport::Exact(trait_name.to_string()),
        items_locator::AssocItemSearch::Exclude,
        Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT),
    )
    .filter_map(|item| match ModuleDef::from(item.as_module_def_id()?) {
        ModuleDef::Trait(trait_) => Some(trait_),
        _ => None,
    })
    .flat_map(|trait_| {
        current_module
            .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_))
            .as_ref()
            .map(mod_path_to_ast)
            .zip(Some(trait_))
    });

    let mut no_traits_found = true;
    for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) {
        add_assist(acc, ctx, &attr, &args, &trait_path, Some(trait_), &adt)?;
    }
    if no_traits_found {
        let trait_path = make::path_unqualified(make::path_segment(make::name_ref(trait_name)));
        add_assist(acc, ctx, &attr, &args, &trait_path, None, &adt)?;
    }
    Some(())
}

fn add_assist(
    acc: &mut Assists,
    ctx: &AssistContext,
    attr: &ast::Attr,
    input: &ast::TokenTree,
    trait_path: &ast::Path,
    trait_: Option<hir::Trait>,
    adt: &ast::Adt,
) -> Option<()> {
    let target = attr.syntax().text_range();
    let annotated_name = adt.name()?;
    let label = format!("Convert to manual `impl {} for {}`", trait_path, annotated_name);
    let trait_name = trait_path.segment().and_then(|seg| seg.name_ref())?;

    acc.add(
        AssistId("replace_derive_with_manual_impl", AssistKind::Refactor),
        label,
        target,
        |builder| {
            let insert_pos = adt.syntax().text_range().end();
            let impl_def_with_items =
                impl_def_from_trait(&ctx.sema, &annotated_name, trait_, trait_path);
            update_attribute(builder, &input, &trait_name, &attr);
            let trait_path = format!("{}", trait_path);
            match (ctx.config.snippet_cap, impl_def_with_items) {
                (None, _) => {
                    builder.insert(insert_pos, generate_trait_impl_text(adt, &trait_path, ""))
                }
                (Some(cap), None) => builder.insert_snippet(
                    cap,
                    insert_pos,
                    generate_trait_impl_text(adt, &trait_path, "    $0"),
                ),
                (Some(cap), Some((impl_def, first_assoc_item))) => {
                    let mut cursor = Cursor::Before(first_assoc_item.syntax());
                    let placeholder;
                    if let ast::AssocItem::Fn(ref func) = first_assoc_item {
                        if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
                        {
                            if m.syntax().text() == "todo!()" {
                                placeholder = m;
                                cursor = Cursor::Replace(placeholder.syntax());
                            }
                        }
                    }

                    builder.insert_snippet(
                        cap,
                        insert_pos,
                        format!("\n\n{}", render_snippet(cap, impl_def.syntax(), cursor)),
                    )
                }
            };
        },
    )
}

fn impl_def_from_trait(
    sema: &hir::Semantics<ide_db::RootDatabase>,
    annotated_name: &ast::Name,
    trait_: Option<hir::Trait>,
    trait_path: &ast::Path,
) -> Option<(ast::Impl, ast::AssocItem)> {
    let trait_ = trait_?;
    let target_scope = sema.scope(annotated_name.syntax());
    let trait_items = filter_assoc_items(sema.db, &trait_.items(sema.db), DefaultMethods::No);
    if trait_items.is_empty() {
        return None;
    }
    let impl_def = make::impl_trait(
        trait_path.clone(),
        make::path_unqualified(make::path_segment(make::name_ref(&annotated_name.text()))),
    );
    let (impl_def, first_assoc_item) =
        add_trait_assoc_items_to_impl(sema, trait_items, trait_, impl_def, target_scope);
    Some((impl_def, first_assoc_item))
}

fn update_attribute(
    builder: &mut AssistBuilder,
    input: &ast::TokenTree,
    trait_name: &ast::NameRef,
    attr: &ast::Attr,
) {
    let trait_name = trait_name.text();
    let new_attr_input = input
        .syntax()
        .descendants_with_tokens()
        .filter(|t| t.kind() == IDENT)
        .filter_map(|t| t.into_token().map(|t| t.text().to_string()))
        .filter(|t| t != &trait_name)
        .collect::<Vec<_>>();
    let has_more_derives = !new_attr_input.is_empty();

    if has_more_derives {
        let new_attr_input = format!("({})", new_attr_input.iter().format(", "));
        builder.replace(input.syntax().text_range(), new_attr_input);
    } else {
        let attr_range = attr.syntax().text_range();
        builder.delete(attr_range);

        if let Some(line_break_range) = attr
            .syntax()
            .next_sibling_or_token()
            .filter(|t| t.kind() == WHITESPACE)
            .map(|t| t.text_range())
        {
            builder.delete(line_break_range);
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn add_custom_impl_debug() {
        check_assist(
            replace_derive_with_manual_impl,
            "
mod fmt {
    pub struct Error;
    pub type Result = Result<(), Error>;
    pub struct Formatter<'a>;
    pub trait Debug {
        fn fmt(&self, f: &mut Formatter<'_>) -> Result;
    }
}

#[derive(Debu$0g)]
struct Foo {
    bar: String,
}
",
            "
mod fmt {
    pub struct Error;
    pub type Result = Result<(), Error>;
    pub struct Formatter<'a>;
    pub trait Debug {
        fn fmt(&self, f: &mut Formatter<'_>) -> Result;
    }
}

struct Foo {
    bar: String,
}

impl fmt::Debug for Foo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        ${0:todo!()}
    }
}
",
        )
    }
    #[test]
    fn add_custom_impl_all() {
        check_assist(
            replace_derive_with_manual_impl,
            "
mod foo {
    pub trait Bar {
        type Qux;
        const Baz: usize = 42;
        const Fez: usize;
        fn foo();
        fn bar() {}
    }
}

#[derive($0Bar)]
struct Foo {
    bar: String,
}
",
            "
mod foo {
    pub trait Bar {
        type Qux;
        const Baz: usize = 42;
        const Fez: usize;
        fn foo();
        fn bar() {}
    }
}

struct Foo {
    bar: String,
}

impl foo::Bar for Foo {
    $0type Qux;

    const Baz: usize = 42;

    const Fez: usize;

    fn foo() {
        todo!()
    }
}
",
        )
    }
    #[test]
    fn add_custom_impl_for_unique_input() {
        check_assist(
            replace_derive_with_manual_impl,
            "
#[derive(Debu$0g)]
struct Foo {
    bar: String,
}
            ",
            "
struct Foo {
    bar: String,
}

impl Debug for Foo {
    $0
}
            ",
        )
    }

    #[test]
    fn add_custom_impl_for_with_visibility_modifier() {
        check_assist(
            replace_derive_with_manual_impl,
            "
#[derive(Debug$0)]
pub struct Foo {
    bar: String,
}
            ",
            "
pub struct Foo {
    bar: String,
}

impl Debug for Foo {
    $0
}
            ",
        )
    }

    #[test]
    fn add_custom_impl_when_multiple_inputs() {
        check_assist(
            replace_derive_with_manual_impl,
            "
#[derive(Display, Debug$0, Serialize)]
struct Foo {}
            ",
            "
#[derive(Display, Serialize)]
struct Foo {}

impl Debug for Foo {
    $0
}
            ",
        )
    }

    #[test]
    fn test_ignore_derive_macro_without_input() {
        check_assist_not_applicable(
            replace_derive_with_manual_impl,
            "
#[derive($0)]
struct Foo {}
            ",
        )
    }

    #[test]
    fn test_ignore_if_cursor_on_param() {
        check_assist_not_applicable(
            replace_derive_with_manual_impl,
            "
#[derive$0(Debug)]
struct Foo {}
            ",
        );

        check_assist_not_applicable(
            replace_derive_with_manual_impl,
            "
#[derive(Debug)$0]
struct Foo {}
            ",
        )
    }

    #[test]
    fn test_ignore_if_not_derive() {
        check_assist_not_applicable(
            replace_derive_with_manual_impl,
            "
#[allow(non_camel_$0case_types)]
struct Foo {}
            ",
        )
    }

    #[test]
    fn works_at_start_of_file() {
        cov_mark::check!(outside_of_attr_args);
        check_assist_not_applicable(
            replace_derive_with_manual_impl,
            r#"
$0#[derive(Debug)]
struct S;
            "#,
        );
    }
}
<|endoftext|>


<commit_before><commit_msg>One more (useless test)<commit_after><|endoftext|>


<commit_before>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use cpu::DecodeRegister;
use cpu::common_defs::address_mode::AddressMode;
use cpu::common_defs::opcode_class::OpcodeClass;
use memory::Memory;
use std::collections::HashMap;

pub struct CpuExecutor {
    op_table: HashMap<u8,OpcodeExecInfo>,
}

impl CpuExecutor {

	/// Construct a new CpuExecutor.
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        // Construct the HashMap and copy it over to CpuExecutor's constructor.
        let mut op_table_temp: HashMap<u8, OpcodeExecInfo> = HashMap::new();
        for oc in opcodes {
            if op_table_temp.contains_key(&oc.opcode) {
                println!("Encountered duplicate opcode: {:#x}", oc.opcode);
                println!("Replacing previous opcode, which was {{ opcode: {:#x}, len: {}, cycles: {}, page_cycles: {} }}", oc.opcode, oc.len, oc.cycles, oc.page_cycles);
            }
            op_table_temp.insert(oc.opcode, oc);
        }

        CpuExecutor {
            op_table: op_table_temp,
        }
    }

	/// Reset the given cpu_state.
    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    /// Execute a single instruction in the given memory and cpu_state context.
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        self.fetch_and_decode(cpu_state,mem);
        let new_cpu_state = self.execute(cpu_state,mem);
        // Perform logging, recording here...
        *cpu_state = new_cpu_state
    }

	/// Fetch the next instruction and perform address resolution.
    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.decode_register = self.decode(cpu_state,mem);
        cpu_state.pc = cpu_state.pc + cpu_state.decode_register.info.len as u16;
    }

    /// Perform address resolution, returning the info in a DecodeRegister.
    fn decode(self: &CpuExecutor, cpu_state: &CpuState, mem: &Memory) -> DecodeRegister {
        let mut dr = DecodeRegister {
            info : self.op_table[&cpu_state.instruction_register].clone(),
            ..Default::default()
        };
        match dr.info.address_mode {
            // no explicit addresses for the following modes
            AddressMode::Accumulator  => { },
            AddressMode::Implied      => { },

            // explicit addresses from here on out
            AddressMode::Absolute => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteX       => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap() + cpu_state.x as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteY       => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap() + cpu_state.y as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Immediate       => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Indirect        => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
            },
            AddressMode::IndexedIndirect => {
                dr.addr_intermediate = Some( (mem.read8(cpu_state.pc+1).unwrap() + cpu_state.x) as u16);
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap())
            },
            AddressMode::IndirectIndexed => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some(dr.addr_intermediate.unwrap() + cpu_state.y as u16);
            },
            AddressMode::Relative        => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPage        => {
                dr.addr_final  = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageX       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() + cpu_state.x) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageY       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() + cpu_state.y) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            _ => panic!("unrecognized addressing mode while decoding instruction_register!")
        }

        return dr;
    }

    /// Perform the current instruction, returning the CpuState after execution.
    pub fn execute(self: &CpuExecutor, mut cpu_state: &CpuState, mut mem:&Memory) -> CpuState {

    	// The state of the CPU after executing the current instruction.
    	let mut new_cpu_state = cpu_state.clone();

    	// Figure out which opcode is being executed.
    	let ref decode_register = cpu_state.decode_register;

    	match decode_register.info.opcode_class {

    		// ASL (Arithmetic Shift Left)
    		OpcodeClass::ASL => {

				// Shift accumulator to the left.
				new_cpu_state.a = cpu_state.a << 1;
				// Carry flag gets set to the most significant bit.
				new_cpu_state.C = (128 & cpu_state.a) > 0;
				// Set zero flag if result is 0.
    			if new_cpu_state.a == 0 { new_cpu_state.Z = true }

    		},

    		// LDA (Load Accumulator)
    		OpcodeClass::LDA => {
    			new_cpu_state.a = decode_register.value_final.unwrap()
    		},

    		// LDX (Load X)
    		OpcodeClass::LDX => {
    			new_cpu_state.x = decode_register.value_final.unwrap()
    		},

    		// LDY (Load Y)
    		OpcodeClass::LDY => {
    			new_cpu_state.y = decode_register.value_final.unwrap()
    		},

    		// LSR (Logical Shift Right)
    		OpcodeClass::LSR => {

    			// Shift accumulator to the right.
    			new_cpu_state.a = cpu_state.a >> 1;
    			// Carry flag gets set to the least significant bit.
    			new_cpu_state.C = 1 & cpu_state.a > 0;
    			// Set zero flag if result is 0.
    			if new_cpu_state.a == 0 { new_cpu_state.Z = true }

    		},

    		// NOP (No Operation)
    		OpcodeClass::NOP => {},

    		// Default: not sure what this opcode is.
			_ => panic!("Unrecognised opcode class: {:?}", decode_register.info.opcode_class)

    	}

    	// Expression returned is the updated cpu_state.
    	new_cpu_state
    }

}

<commit_msg>indexed addressing modes should wrap around properly now<commit_after>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use cpu::DecodeRegister;
use cpu::common_defs::address_mode::AddressMode;
use cpu::common_defs::opcode_class::OpcodeClass;
use memory::Memory;
use std::collections::HashMap;

pub struct CpuExecutor {
    op_table: HashMap<u8,OpcodeExecInfo>,
}

impl CpuExecutor {

	/// Construct a new CpuExecutor.
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        // Construct the HashMap and copy it over to CpuExecutor's constructor.
        let mut op_table_temp: HashMap<u8, OpcodeExecInfo> = HashMap::new();
        for oc in opcodes {
            if op_table_temp.contains_key(&oc.opcode) {
                println!("Encountered duplicate opcode: {:#x}", oc.opcode);
                println!("Replacing previous opcode, which was {{ opcode: {:#x}, len: {}, cycles: {}, page_cycles: {} }}", oc.opcode, oc.len, oc.cycles, oc.page_cycles);
            }
            op_table_temp.insert(oc.opcode, oc);
        }

        CpuExecutor {
            op_table: op_table_temp,
        }
    }

	/// Reset the given cpu_state.
    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    /// Execute a single instruction in the given memory and cpu_state context.
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        self.fetch_and_decode(cpu_state,mem);
        let new_cpu_state = self.execute(cpu_state,mem);
        // Perform logging, recording here...
        *cpu_state = new_cpu_state
    }

	/// Fetch the next instruction and perform address resolution.
    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.decode_register = self.decode(cpu_state,mem);
        cpu_state.pc = cpu_state.pc + cpu_state.decode_register.info.len as u16;
    }

    /// Perform address resolution, returning the info in a DecodeRegister.
    fn decode(self: &CpuExecutor, cpu_state: &CpuState, mem: &Memory) -> DecodeRegister {
        let mut dr = DecodeRegister {
            info : self.op_table[&cpu_state.instruction_register].clone(),
            ..Default::default()
        };
        match dr.info.address_mode {
            // no explicit addresses for the following modes
            AddressMode::Accumulator  => { },
            AddressMode::Implied      => { },

            // explicit addresses from here on out
            AddressMode::Absolute => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteX       => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap() + cpu_state.x as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteY       => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap() + cpu_state.y as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Immediate       => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Indirect        => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
            },
            AddressMode::IndexedIndirect => {
                dr.addr_intermediate = Some( ((mem.read8(cpu_state.pc+1).unwrap() as u32 + cpu_state.x as u32) % 65536 ) as u16);
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap())
            },
            AddressMode::IndirectIndexed => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some( ((dr.addr_intermediate.unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
            },
            AddressMode::Relative        => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPage        => {
                dr.addr_final  = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageX       => {
                dr.addr_final  = Some( ((mem.read8(cpu_state.pc+1).unwrap() + cpu_state.x) % 256) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageY       => {
                dr.addr_final  = Some( ((mem.read8(cpu_state.pc+1).unwrap() + cpu_state.y) % 256) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            _ => panic!("unrecognized addressing mode while decoding instruction_register!")
        }

        return dr;
    }

    /// Perform the current instruction, returning the CpuState after execution.
    pub fn execute(self: &CpuExecutor, mut cpu_state: &CpuState, mut mem:&Memory) -> CpuState {

    	// The state of the CPU after executing the current instruction.
    	let mut new_cpu_state = cpu_state.clone();

    	// Figure out which opcode is being executed.
    	let ref decode_register = cpu_state.decode_register;

    	match decode_register.info.opcode_class {

    		// ASL (Arithmetic Shift Left)
    		OpcodeClass::ASL => {

				// Shift accumulator to the left.
				new_cpu_state.a = cpu_state.a << 1;
				// Carry flag gets set to the most significant bit.
				new_cpu_state.C = (128 & cpu_state.a) > 0;
				// Set zero flag if result is 0.
    			if new_cpu_state.a == 0 { new_cpu_state.Z = true }

    		},

    		// LDA (Load Accumulator)
    		OpcodeClass::LDA => {
    			new_cpu_state.a = decode_register.value_final.unwrap()
    		},

    		// LDX (Load X)
    		OpcodeClass::LDX => {
    			new_cpu_state.x = decode_register.value_final.unwrap()
    		},

    		// LDY (Load Y)
    		OpcodeClass::LDY => {
    			new_cpu_state.y = decode_register.value_final.unwrap()
    		},

    		// LSR (Logical Shift Right)
    		OpcodeClass::LSR => {

    			// Shift accumulator to the right.
    			new_cpu_state.a = cpu_state.a >> 1;
    			// Carry flag gets set to the least significant bit.
    			new_cpu_state.C = 1 & cpu_state.a > 0;
    			// Set zero flag if result is 0.
    			if new_cpu_state.a == 0 { new_cpu_state.Z = true }

    		},

    		// NOP (No Operation)
    		OpcodeClass::NOP => {},

    		// Default: not sure what this opcode is.
			_ => panic!("Unrecognised opcode class: {:?}", decode_register.info.opcode_class)

    	}

    	// Expression returned is the updated cpu_state.
    	new_cpu_state
    }

}

<|endoftext|>


<commit_before>// Copyright 2015 click2stream, Inc.
//
// 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.

//! Common Arrow Protocol definitions.

pub mod control;
pub mod svc_table;

pub mod scan_report;

pub use self::control::ACK_NO_ERROR;
pub use self::control::ACK_UNSUPPORTED_PROTOCOL_VERSION;
pub use self::control::ACK_UNAUTHORIZED;
pub use self::control::ACK_UNSUPPORTED_METHOD;
pub use self::control::ACK_INTERNAL_SERVER_ERROR;

pub use self::control::ControlMessage;
pub use self::control::ControlMessageHeader;
pub use self::control::ControlMessageBody;
pub use self::control::ControlMessageParser;
pub use self::control::ControlMessageType;

pub use self::control::EmptyBody;

pub use self::control::RegisterMessage;
pub use self::control::RegisterMessageHeader;

pub use self::control::HupMessage;

pub use self::control::StatusMessage;

pub use self::svc_table::Service;
pub use self::svc_table::ServiceTable;

pub use self::scan_report::HostInfo;
pub use self::scan_report::ScanReport;
pub use self::scan_report::ScanReportMessage;
pub use self::scan_report::HINFO_FLAG_ARP;
pub use self::scan_report::HINFO_FLAG_ICMP;

use std::io;
use std::mem;

use std::io::Write;

use utils;

use utils::Serialize;
use net::arrow::error::{Result, ArrowError};

const ARROW_PROTOCOL_VERSION: u8 = 1;

/// Common trait for Arrow Message payload types.
pub trait ArrowMessageBody : Serialize {
    /// Get body size in bytes.
    fn len(&self) -> usize;
}

/// Arrow Message header.
#[derive(Debug, Copy, Clone)]
#[repr(packed)]
pub struct ArrowMessageHeader {
    /// Arrow Protocol major version.
    pub version: u8,
    /// Service ID.
    pub service: u16,
    /// Session ID (note: the upper 8 bits are reserved).
    pub session: u32,
    /// Payload size.
    size:        u32,
}

impl ArrowMessageHeader {
    /// Create a new Arrow Message header with a given service ID, session ID
    /// and payload size.
    fn new(service: u16, session: u32, size: u32) -> ArrowMessageHeader {
        ArrowMessageHeader {
            version: ARROW_PROTOCOL_VERSION,
            service: service,
            session: session & ((1 << 24) - 1),
            size:    size
        }
    }

    /// Deserialize an Arrow Message header.
    fn from_bytes(slice: &[u8]) -> Result<ArrowMessageHeader> {
        assert_eq!(slice.len(), mem::size_of::<ArrowMessageHeader>());
        let ptr    = slice.as_ptr() as *const ArrowMessageHeader;
        let header = unsafe { &*ptr };

        let res = ArrowMessageHeader {
            version: header.version,
            service: u16::from_be(header.service),
            session: u32::from_be(header.session) & ((1 << 24) - 1),
            size:    u32::from_be(header.size)
        };

        if res.version == ARROW_PROTOCOL_VERSION {
            Ok(res)
        } else {
            Err(ArrowError::unsupported_protocol_version("unsupported Arrow Protocol version"))
        }
    }
}

impl Serialize for ArrowMessageHeader {
    fn serialize<W: Write>(&self, w: &mut W) -> io::Result<()> {
        let be_header = ArrowMessageHeader {
            version: self.version,
            service: self.service.to_be(),
            session: self.session.to_be(),
            size:    self.size.to_be()
        };

        w.write_all(utils::as_bytes(&be_header))
    }
}

/// Arrow Message envelope.
#[derive(Debug, Clone)]
pub struct ArrowMessage<B: ArrowMessageBody> {
    /// Message header.
    header: ArrowMessageHeader,
    /// Payload.
    body:   B,
}

impl<B: ArrowMessageBody> ArrowMessage<B> {
    /// Create a new Arrow Message with a given service ID, session ID and
    /// payload.
    pub fn new(service: u16, session: u32, body: B) -> ArrowMessage<B> {
        ArrowMessage {
            header: ArrowMessageHeader::new(service, session, 0),
            body:   body
        }
    }

    /// Get message header.
    pub fn header(&self) -> &ArrowMessageHeader {
        &self.header
    }
}

impl<B: ArrowMessageBody> Serialize for ArrowMessage<B> {
    fn serialize<W: Write>(&self, w: &mut W) -> io::Result<()> {
        let header = ArrowMessageHeader::new(
            self.header.service,
            self.header.session,
            self.body.len() as u32);

        try!(header.serialize(w));

        self.body.serialize(w)
    }
}

/// Arrow Message parser.
///
/// This structure allows to read Arrow Messages from continuous streams.
pub struct ArrowMessageParser {
    header:   Option<ArrowMessageHeader>,
    buffer:   Vec<u8>,
    expected: usize,
}

impl ArrowMessageParser {
    /// Create a new Arrow Message parser.
    pub fn new() -> ArrowMessageParser {
        ArrowMessageParser {
            header:   None,
            buffer:   Vec::new(),
            expected: 0
        }
    }

    /// Check if the last message is complete.
    pub fn is_complete(&self) -> bool {
        self.header.is_some() && self.expected == 0
    }

    /// Process a new chunk of data and return the number of bytes used.
    pub fn add(&mut self, data: &[u8]) -> Result<usize> {
        let mut consumed = 0;

        if self.header.is_none() {
            consumed += try!(self.read_header(data));
            if let Some(header) = self.header {
                self.expected = header.size as usize;
            }
        }

        if self.header.is_some() {
            consumed += self.read_body(&data[consumed..]);
        }

        Ok(consumed)
    }

    /// Clear the last message and prepare the parser for a new one.
    pub fn clear(&mut self) {
        self.buffer.clear();

        self.expected = 0;
        self.header   = None;
    }

    /// Get last message header.
    pub fn header(&self) -> Option<&ArrowMessageHeader> {
        match self.header {
            Some(ref header) => Some(header),
            None => None
        }
    }

    /// Get last message body.
    pub fn body(&self) -> Option<&[u8]> {
        let header_size = mem::size_of::<ArrowMessageHeader>();
        if self.is_complete() {
            Some(&self.buffer[header_size..])
        } else {
            None
        }
    }

    /// Read header chunk.
    fn read_header(&mut self, data: &[u8]) -> Result<usize> {
        let size         = mem::size_of::<ArrowMessageHeader>();
        let mut consumed = size - self.buffer.len();

        if consumed > data.len() {
            consumed = data.len();
        }

        let data = &data[..consumed];

        self.buffer.extend(data.iter());

        if size == self.buffer.len() {
            self.header = Some(try!(
                ArrowMessageHeader::from_bytes(&self.buffer)));
        }

        Ok(consumed)
    }

    /// Read body chunk.
    fn read_body(&mut self, data: &[u8]) -> usize {
        let mut consumed = self.expected;

        if consumed > data.len() {
            consumed = data.len();
        }

        let data = &data[..consumed];

        self.buffer.extend(data.iter());
        self.expected -= consumed;

        consumed
    }
}

impl ArrowMessageBody for Vec<u8> {
    fn len(&self) -> usize {
        Vec::<u8>::len(self)
    }
}

impl<'a> ArrowMessageBody for &'a [u8] {
    fn len(&self) -> usize {
        <[u8]>::len(self)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use utils::Serialize;
    use net::utils::WriteBuffer;

    #[test]
    fn test_message_serialization() {
        let msg_data = [0x00,                    // version
                        0x10, 0x22,              // svc_id
                        0x00, 0x34, 0x56, 0x78,  // session_id
                        0x00, 0x00, 0x00, 0x02,  // body_size
                        0xab, 0xcd];             // body

        let message = ArrowMessage::new(0x1022, 0x12345678, vec![0xab, 0xcd]);

        let mut buf = WriteBuffer::new(0);

        message.serialize(&mut buf).unwrap();

        assert_eq!(&msg_data, buf.as_bytes());
    }

    #[test]
    fn test_message_deserialization() {
        let mut parser = ArrowMessageParser::new();
        let msg        = [0x00,                    // version
                          0x10, 0x22,              // svc_id
                          0x12, 0x34, 0x56, 0x78,  // session_id
                          0x00, 0x00, 0x00, 0x02,  // body_size
                          0xab, 0xcd];             // body

        assert_eq!(parser.is_complete(), false);
        assert!(parser.header().is_none());
        assert!(parser.body().is_none());

        assert_eq!(parser.add(&msg).unwrap(), msg.len());

        assert_eq!(parser.is_complete(), true);
        assert!(parser.header().is_some());
        assert!(parser.body().is_some());

        {
            let header = parser.header().unwrap();

            assert_eq!(header.version, 0);
            assert_eq!(header.service, 0x1022);
            assert_eq!(header.session, 0x00345678);
        }

        {
            let body = parser.body().unwrap();

            assert_eq!(body, &[0xab, 0xcd]);
        }

        assert_eq!(parser.add(&msg).unwrap(), 0);

        parser.clear();

        assert_eq!(parser.is_complete(), false);
        assert!(parser.header().is_none());
        assert!(parser.body().is_none());

        assert_eq!(parser.add(&msg[..11]).unwrap(), 11);

        assert_eq!(parser.is_complete(), false);
        assert!(parser.header().is_some());
        assert!(parser.body().is_none());

        assert_eq!(parser.add(&msg[11..]).unwrap(), 2);

        assert_eq!(parser.is_complete(), true);
        assert!(parser.header().is_some());
        assert!(parser.body().is_some());
    }
}
<commit_msg>fixed protocol version in (de)serialization tests<commit_after>// Copyright 2015 click2stream, Inc.
//
// 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.

//! Common Arrow Protocol definitions.

pub mod control;
pub mod svc_table;

pub mod scan_report;

pub use self::control::ACK_NO_ERROR;
pub use self::control::ACK_UNSUPPORTED_PROTOCOL_VERSION;
pub use self::control::ACK_UNAUTHORIZED;
pub use self::control::ACK_UNSUPPORTED_METHOD;
pub use self::control::ACK_INTERNAL_SERVER_ERROR;

pub use self::control::ControlMessage;
pub use self::control::ControlMessageHeader;
pub use self::control::ControlMessageBody;
pub use self::control::ControlMessageParser;
pub use self::control::ControlMessageType;

pub use self::control::EmptyBody;

pub use self::control::RegisterMessage;
pub use self::control::RegisterMessageHeader;

pub use self::control::HupMessage;

pub use self::control::StatusMessage;

pub use self::svc_table::Service;
pub use self::svc_table::ServiceTable;

pub use self::scan_report::HostInfo;
pub use self::scan_report::ScanReport;
pub use self::scan_report::ScanReportMessage;
pub use self::scan_report::HINFO_FLAG_ARP;
pub use self::scan_report::HINFO_FLAG_ICMP;

use std::io;
use std::mem;

use std::io::Write;

use utils;

use utils::Serialize;
use net::arrow::error::{Result, ArrowError};

const ARROW_PROTOCOL_VERSION: u8 = 1;

/// Common trait for Arrow Message payload types.
pub trait ArrowMessageBody : Serialize {
    /// Get body size in bytes.
    fn len(&self) -> usize;
}

/// Arrow Message header.
#[derive(Debug, Copy, Clone)]
#[repr(packed)]
pub struct ArrowMessageHeader {
    /// Arrow Protocol major version.
    pub version: u8,
    /// Service ID.
    pub service: u16,
    /// Session ID (note: the upper 8 bits are reserved).
    pub session: u32,
    /// Payload size.
    size:        u32,
}

impl ArrowMessageHeader {
    /// Create a new Arrow Message header with a given service ID, session ID
    /// and payload size.
    fn new(service: u16, session: u32, size: u32) -> ArrowMessageHeader {
        ArrowMessageHeader {
            version: ARROW_PROTOCOL_VERSION,
            service: service,
            session: session & ((1 << 24) - 1),
            size:    size
        }
    }

    /// Deserialize an Arrow Message header.
    fn from_bytes(slice: &[u8]) -> Result<ArrowMessageHeader> {
        assert_eq!(slice.len(), mem::size_of::<ArrowMessageHeader>());
        let ptr    = slice.as_ptr() as *const ArrowMessageHeader;
        let header = unsafe { &*ptr };

        let res = ArrowMessageHeader {
            version: header.version,
            service: u16::from_be(header.service),
            session: u32::from_be(header.session) & ((1 << 24) - 1),
            size:    u32::from_be(header.size)
        };

        if res.version == ARROW_PROTOCOL_VERSION {
            Ok(res)
        } else {
            Err(ArrowError::unsupported_protocol_version("unsupported Arrow Protocol version"))
        }
    }
}

impl Serialize for ArrowMessageHeader {
    fn serialize<W: Write>(&self, w: &mut W) -> io::Result<()> {
        let be_header = ArrowMessageHeader {
            version: self.version,
            service: self.service.to_be(),
            session: self.session.to_be(),
            size:    self.size.to_be()
        };

        w.write_all(utils::as_bytes(&be_header))
    }
}

/// Arrow Message envelope.
#[derive(Debug, Clone)]
pub struct ArrowMessage<B: ArrowMessageBody> {
    /// Message header.
    header: ArrowMessageHeader,
    /// Payload.
    body:   B,
}

impl<B: ArrowMessageBody> ArrowMessage<B> {
    /// Create a new Arrow Message with a given service ID, session ID and
    /// payload.
    pub fn new(service: u16, session: u32, body: B) -> ArrowMessage<B> {
        ArrowMessage {
            header: ArrowMessageHeader::new(service, session, 0),
            body:   body
        }
    }

    /// Get message header.
    pub fn header(&self) -> &ArrowMessageHeader {
        &self.header
    }
}

impl<B: ArrowMessageBody> Serialize for ArrowMessage<B> {
    fn serialize<W: Write>(&self, w: &mut W) -> io::Result<()> {
        let header = ArrowMessageHeader::new(
            self.header.service,
            self.header.session,
            self.body.len() as u32);

        try!(header.serialize(w));

        self.body.serialize(w)
    }
}

/// Arrow Message parser.
///
/// This structure allows to read Arrow Messages from continuous streams.
pub struct ArrowMessageParser {
    header:   Option<ArrowMessageHeader>,
    buffer:   Vec<u8>,
    expected: usize,
}

impl ArrowMessageParser {
    /// Create a new Arrow Message parser.
    pub fn new() -> ArrowMessageParser {
        ArrowMessageParser {
            header:   None,
            buffer:   Vec::new(),
            expected: 0
        }
    }

    /// Check if the last message is complete.
    pub fn is_complete(&self) -> bool {
        self.header.is_some() && self.expected == 0
    }

    /// Process a new chunk of data and return the number of bytes used.
    pub fn add(&mut self, data: &[u8]) -> Result<usize> {
        let mut consumed = 0;

        if self.header.is_none() {
            consumed += try!(self.read_header(data));
            if let Some(header) = self.header {
                self.expected = header.size as usize;
            }
        }

        if self.header.is_some() {
            consumed += self.read_body(&data[consumed..]);
        }

        Ok(consumed)
    }

    /// Clear the last message and prepare the parser for a new one.
    pub fn clear(&mut self) {
        self.buffer.clear();

        self.expected = 0;
        self.header   = None;
    }

    /// Get last message header.
    pub fn header(&self) -> Option<&ArrowMessageHeader> {
        match self.header {
            Some(ref header) => Some(header),
            None => None
        }
    }

    /// Get last message body.
    pub fn body(&self) -> Option<&[u8]> {
        let header_size = mem::size_of::<ArrowMessageHeader>();
        if self.is_complete() {
            Some(&self.buffer[header_size..])
        } else {
            None
        }
    }

    /// Read header chunk.
    fn read_header(&mut self, data: &[u8]) -> Result<usize> {
        let size         = mem::size_of::<ArrowMessageHeader>();
        let mut consumed = size - self.buffer.len();

        if consumed > data.len() {
            consumed = data.len();
        }

        let data = &data[..consumed];

        self.buffer.extend(data.iter());

        if size == self.buffer.len() {
            self.header = Some(try!(
                ArrowMessageHeader::from_bytes(&self.buffer)));
        }

        Ok(consumed)
    }

    /// Read body chunk.
    fn read_body(&mut self, data: &[u8]) -> usize {
        let mut consumed = self.expected;

        if consumed > data.len() {
            consumed = data.len();
        }

        let data = &data[..consumed];

        self.buffer.extend(data.iter());
        self.expected -= consumed;

        consumed
    }
}

impl ArrowMessageBody for Vec<u8> {
    fn len(&self) -> usize {
        Vec::<u8>::len(self)
    }
}

impl<'a> ArrowMessageBody for &'a [u8] {
    fn len(&self) -> usize {
        <[u8]>::len(self)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use utils::Serialize;
    use net::utils::WriteBuffer;

    #[test]
    fn test_message_serialization() {
        let msg_data = [0x01,                    // version
                        0x10, 0x22,              // svc_id
                        0x00, 0x34, 0x56, 0x78,  // session_id
                        0x00, 0x00, 0x00, 0x02,  // body_size
                        0xab, 0xcd];             // body

        let message = ArrowMessage::new(0x1022, 0x12345678, vec![0xab, 0xcd]);

        let mut buf = WriteBuffer::new(0);

        message.serialize(&mut buf).unwrap();

        assert_eq!(&msg_data, buf.as_bytes());
    }

    #[test]
    fn test_message_deserialization() {
        let mut parser = ArrowMessageParser::new();
        let msg        = [0x01,                    // version
                          0x10, 0x22,              // svc_id
                          0x12, 0x34, 0x56, 0x78,  // session_id
                          0x00, 0x00, 0x00, 0x02,  // body_size
                          0xab, 0xcd];             // body

        assert_eq!(parser.is_complete(), false);
        assert!(parser.header().is_none());
        assert!(parser.body().is_none());

        assert_eq!(parser.add(&msg).unwrap(), msg.len());

        assert_eq!(parser.is_complete(), true);
        assert!(parser.header().is_some());
        assert!(parser.body().is_some());

        {
            let header = parser.header().unwrap();

            assert_eq!(header.version, 1);
            assert_eq!(header.service, 0x1022);
            assert_eq!(header.session, 0x00345678);
        }

        {
            let body = parser.body().unwrap();

            assert_eq!(body, &[0xab, 0xcd]);
        }

        assert_eq!(parser.add(&msg).unwrap(), 0);

        parser.clear();

        assert_eq!(parser.is_complete(), false);
        assert!(parser.header().is_none());
        assert!(parser.body().is_none());

        assert_eq!(parser.add(&msg[..11]).unwrap(), 11);

        assert_eq!(parser.is_complete(), false);
        assert!(parser.header().is_some());
        assert!(parser.body().is_none());

        assert_eq!(parser.add(&msg[11..]).unwrap(), 2);

        assert_eq!(parser.is_complete(), true);
        assert!(parser.header().is_some());
        assert!(parser.body().is_some());
    }
}
<|endoftext|>


<commit_before>/// Used to run some code when a value goes out of scope.
/// This is sometimes called a 'destructor'.
///
/// When a value goes out of scope, it will have its `drop` method called if
/// its type implements `Drop`. Then, any fields the value contains will also
/// be dropped recursively.
///
/// Because of this recursive dropping, you do not need to implement this trait
/// unless your type needs its own destructor logic.
///
/// Refer to [the chapter on `Drop` in *The Rust Programming Language*][book]
/// for some more elaboration.
///
/// [book]: ../../book/ch15-03-drop.html
///
/// # Examples
///
/// ## Implementing `Drop`
///
/// The `drop` method is called when `_x` goes out of scope, and therefore
/// `main` prints `Dropping!`.
///
/// ```
/// struct HasDrop;
///
/// impl Drop for HasDrop {
///     fn drop(&mut self) {
///         println!("Dropping!");
///     }
/// }
///
/// fn main() {
///     let _x = HasDrop;
/// }
/// ```
///
/// ## Dropping is done recursively
///
/// When `outer` goes out of scope, the `drop` method will be called first for
/// `Outer`, then for `Inner`. Therefore, `main` prints `Dropping Outer!` and
/// then `Dropping Inner!`.
///
/// ```
/// struct Inner;
/// struct Outer(Inner);
///
/// impl Drop for Inner {
///     fn drop(&mut self) {
///         println!("Dropping Inner!");
///     }
/// }
///
/// impl Drop for Outer {
///     fn drop(&mut self) {
///         println!("Dropping Outer!");
///     }
/// }
///
/// fn main() {
///     let _x = Outer(Inner);
/// }
/// ```
///
/// ## Variables are dropped in reverse order of declaration
///
/// `_first` is declared first and `_second` is declared second, so `main` will
/// print `Declared second!` and then `Declared first!`.
///
/// ```
/// struct PrintOnDrop(&'static str);
///
/// impl Drop for PrintOnDrop {
///     fn drop(&mut self) {
///         println!("{}", self.0);
///     }
/// }
///
/// fn main() {
///     let _first = PrintOnDrop("Declared first!");
///     let _second = PrintOnDrop("Declared second!");
/// }
/// ```
#[lang = "drop"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Drop {
    /// Executes the destructor for this type.
    ///
    /// This method is called implicitly when the value goes out of scope,
    /// and cannot be called explicitly (this is compiler error [E0040]).
    /// However, the [`std::mem::drop`] function in the prelude can be
    /// used to call the argument's `Drop` implementation.
    ///
    /// When this method has been called, `self` has not yet been deallocated.
    /// That only happens after the method is over.
    /// If this wasn't the case, `self` would be a dangling reference.
    ///
    /// # Panics
    ///
    /// Given that a [`panic!`] will call `drop` as it unwinds, any [`panic!`]
    /// in a `drop` implementation will likely abort.
    ///
    /// [E0040]: ../../error-index.html#E0040
    /// [`panic!`]: ../macro.panic.html
    /// [`std::mem::drop`]: ../../std/mem/fn.drop.html
    #[stable(feature = "rust1", since = "1.0.0")]
    fn drop(&mut self);
}
<commit_msg>Document that calling Drop, even after it panics, is UB<commit_after>/// Used to run some code when a value goes out of scope.
/// This is sometimes called a 'destructor'.
///
/// When a value goes out of scope, it will have its `drop` method called if
/// its type implements `Drop`. Then, any fields the value contains will also
/// be dropped recursively.
///
/// Because of this recursive dropping, you do not need to implement this trait
/// unless your type needs its own destructor logic.
///
/// Refer to [the chapter on `Drop` in *The Rust Programming Language*][book]
/// for some more elaboration.
///
/// [book]: ../../book/ch15-03-drop.html
///
/// # Examples
///
/// ## Implementing `Drop`
///
/// The `drop` method is called when `_x` goes out of scope, and therefore
/// `main` prints `Dropping!`.
///
/// ```
/// struct HasDrop;
///
/// impl Drop for HasDrop {
///     fn drop(&mut self) {
///         println!("Dropping!");
///     }
/// }
///
/// fn main() {
///     let _x = HasDrop;
/// }
/// ```
///
/// ## Dropping is done recursively
///
/// When `outer` goes out of scope, the `drop` method will be called first for
/// `Outer`, then for `Inner`. Therefore, `main` prints `Dropping Outer!` and
/// then `Dropping Inner!`.
///
/// ```
/// struct Inner;
/// struct Outer(Inner);
///
/// impl Drop for Inner {
///     fn drop(&mut self) {
///         println!("Dropping Inner!");
///     }
/// }
///
/// impl Drop for Outer {
///     fn drop(&mut self) {
///         println!("Dropping Outer!");
///     }
/// }
///
/// fn main() {
///     let _x = Outer(Inner);
/// }
/// ```
///
/// ## Variables are dropped in reverse order of declaration
///
/// `_first` is declared first and `_second` is declared second, so `main` will
/// print `Declared second!` and then `Declared first!`.
///
/// ```
/// struct PrintOnDrop(&'static str);
///
/// impl Drop for PrintOnDrop {
///     fn drop(&mut self) {
///         println!("{}", self.0);
///     }
/// }
///
/// fn main() {
///     let _first = PrintOnDrop("Declared first!");
///     let _second = PrintOnDrop("Declared second!");
/// }
/// ```
#[lang = "drop"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Drop {
    /// Executes the destructor for this type.
    ///
    /// This method is called implicitly when the value goes out of scope,
    /// and cannot be called explicitly (this is compiler error [E0040]).
    /// However, the [`std::mem::drop`] function in the prelude can be
    /// used to call the argument's `Drop` implementation.
    ///
    /// When this method has been called, `self` has not yet been deallocated.
    /// That only happens after the method is over.
    /// If this wasn't the case, `self` would be a dangling reference.
    ///
    /// # Panics
    ///
    /// Given that a [`panic!`] will call `drop` as it unwinds, any [`panic!`]
    /// in a `drop` implementation will likely abort.
    ///
    /// Note that even if this panics, the value is considered to be dropped;
    /// you must not cause `drop` to be called again. This is normally automatically
    /// handled by the compiler, but when using unsafe code, can sometimes occur
    /// unintentionally, particularly when using [`std::ptr::drop_in_place`].
    ///
    /// [E0040]: ../../error-index.html#E0040
    /// [`panic!`]: ../macro.panic.html
    /// [`std::mem::drop`]: ../../std/mem/fn.drop.html
    /// [`std::ptr::drop_in_place`]: ../../std/ptr/fn.drop_in_place.html
    #[stable(feature = "rust1", since = "1.0.0")]
    fn drop(&mut self);
}
<|endoftext|>