<commit_before>use hir::def_id::DefId;
use infer::error_reporting::nice_region_error::NiceRegionError;
use infer::lexical_region_resolve::RegionResolutionError;
use infer::ValuePairs;
use infer::{SubregionOrigin, TypeTrace};
use traits::{ObligationCause, ObligationCauseCode};
use ty;
use ty::error::ExpectedFound;
use ty::subst::Substs;
use util::common::ErrorReported;
use util::ppaux::RegionHighlightMode;

impl NiceRegionError<'me, 'gcx, 'tcx> {
    /// When given a `ConcreteFailure` for a function with arguments containing a named region and
    /// an anonymous region, emit an descriptive diagnostic error.
    pub(super) fn try_report_placeholder_conflict(&self) -> Option<ErrorReported> {
        match &self.error {
            ///////////////////////////////////////////////////////////////////////////
            // NB. The ordering of cases in this match is very
            // sensitive, because we are often matching against
            // specific cases and then using an `_` to match all
            // others.

            ///////////////////////////////////////////////////////////////////////////
            // Check for errors from comparing trait failures -- first
            // with two placeholders, then with one.
            Some(RegionResolutionError::SubSupConflict(
                vid,
                _,
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sub_placeholder @ ty::RePlaceholder(_),
                _,
                sup_placeholder @ ty::RePlaceholder(_),
            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
                Some(self.tcx().mk_region(ty::ReVar(*vid))),
                cause,
                Some(sub_placeholder),
                Some(sup_placeholder),
                expected.def_id,
                expected.substs,
                found.substs,
            )),

            Some(RegionResolutionError::SubSupConflict(
                vid,
                _,
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sub_placeholder @ ty::RePlaceholder(_),
                _,
                _,
            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
                Some(self.tcx().mk_region(ty::ReVar(*vid))),
                cause,
                Some(sub_placeholder),
                None,
                expected.def_id,
                expected.substs,
                found.substs,
            )),

            Some(RegionResolutionError::SubSupConflict(
                vid,
                _,
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                _,
                _,
                sup_placeholder @ ty::RePlaceholder(_),
            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
                Some(self.tcx().mk_region(ty::ReVar(*vid))),
                cause,
                None,
                Some(*sup_placeholder),
                expected.def_id,
                expected.substs,
                found.substs,
            )),

            Some(RegionResolutionError::SubSupConflict(
                vid,
                _,
                _,
                _,
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sup_placeholder @ ty::RePlaceholder(_),
            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
                Some(self.tcx().mk_region(ty::ReVar(*vid))),
                cause,
                None,
                Some(*sup_placeholder),
                expected.def_id,
                expected.substs,
                found.substs,
            )),

            Some(RegionResolutionError::ConcreteFailure(
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sub_region @ ty::RePlaceholder(_),
                sup_region @ ty::RePlaceholder(_),
            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
                None,
                cause,
                Some(*sub_region),
                Some(*sup_region),
                expected.def_id,
                expected.substs,
                found.substs,
            )),

            Some(RegionResolutionError::ConcreteFailure(
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sub_region @ ty::RePlaceholder(_),
                sup_region,
            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
                Some(sup_region),
                cause,
                Some(*sub_region),
                None,
                expected.def_id,
                expected.substs,
                found.substs,
            )),

            Some(RegionResolutionError::ConcreteFailure(
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sub_region,
                sup_region @ ty::RePlaceholder(_),
            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
                Some(sub_region),
                cause,
                None,
                Some(*sup_region),
                expected.def_id,
                expected.substs,
                found.substs,
            )),

            _ => None,
        }
    }

    // error[E0308]: implementation of `Foo` does not apply to enough lifetimes
    //   --> /home/nmatsakis/tmp/foo.rs:12:5
    //    |
    // 12 |     all::<&'static u32>();
    //    |     ^^^^^^^^^^^^^^^^^^^ lifetime mismatch
    //    |
    //    = note: Due to a where-clause on the function `all`,
    //    = note: `T` must implement `...` for any two lifetimes `'1` and `'2`.
    //    = note: However, the type `T` only implements `...` for some specific lifetime `'2`.
    fn try_report_placeholders_trait(
        &self,
        vid: Option<ty::Region<'tcx>>,
        cause: &ObligationCause<'tcx>,
        sub_placeholder: Option<ty::Region<'tcx>>,
        sup_placeholder: Option<ty::Region<'tcx>>,
        trait_def_id: DefId,
        expected_substs: &'tcx Substs<'tcx>,
        actual_substs: &'tcx Substs<'tcx>,
    ) -> ErrorReported {
        debug!(
            "try_report_placeholders_trait(\
             vid={:?}, \
             sub_placeholder={:?}, \
             sup_placeholder={:?}, \
             trait_def_id={:?}, \
             expected_substs={:?}, \
             actual_substs={:?})",
            vid, sub_placeholder, sup_placeholder, trait_def_id, expected_substs, actual_substs
        );

        let mut err = self.tcx().sess.struct_span_err(
            cause.span(&self.tcx()),
            &format!(
                "implementation of `{}` is not general enough",
                self.tcx().item_path_str(trait_def_id),
            ),
        );

        match cause.code {
            ObligationCauseCode::ItemObligation(def_id) => {
                err.note(&format!(
                    "Due to a where-clause on `{}`,",
                    self.tcx().item_path_str(def_id),
                ));
            }
            _ => (),
        }

        let expected_trait_ref = self.infcx.resolve_type_vars_if_possible(&ty::TraitRef {
            def_id: trait_def_id,
            substs: expected_substs,
        });
        let actual_trait_ref = self.infcx.resolve_type_vars_if_possible(&ty::TraitRef {
            def_id: trait_def_id,
            substs: actual_substs,
        });

        // Search the expected and actual trait references to see (a)
        // whether the sub/sup placeholders appear in them (sometimes
        // you have a trait ref like `T: Foo<fn(&u8)>`, where the
        // placeholder was created as part of an inner type) and (b)
        // whether the inference variable appears. In each case,
        // assign a counter value in each case if so.
        let mut counter = 0;
        let mut has_sub = None;
        let mut has_sup = None;

        let mut actual_has_vid = None;
        let mut expected_has_vid = None;

        self.tcx().for_each_free_region(&expected_trait_ref, |r| {
            if Some(r) == sub_placeholder && has_sub.is_none() {
                has_sub = Some(counter);
                counter += 1;
            } else if Some(r) == sup_placeholder && has_sup.is_none() {
                has_sup = Some(counter);
                counter += 1;
            }

            if Some(r) == vid && expected_has_vid.is_none() {
                expected_has_vid = Some(counter);
                counter += 1;
            }
        });

        self.tcx().for_each_free_region(&actual_trait_ref, |r| {
            if Some(r) == vid && actual_has_vid.is_none() {
                actual_has_vid = Some(counter);
                counter += 1;
            }
        });

        let actual_self_ty_has_vid = self
            .tcx()
            .any_free_region_meets(&actual_trait_ref.self_ty(), |r| Some(r) == vid);

        let expected_self_ty_has_vid = self
            .tcx()
            .any_free_region_meets(&expected_trait_ref.self_ty(), |r| Some(r) == vid);

        let self_ty_has_vid = actual_self_ty_has_vid || expected_self_ty_has_vid;

        debug!(
            "try_report_placeholders_trait: actual_has_vid={:?}",
            actual_has_vid
        );
        debug!(
            "try_report_placeholders_trait: expected_has_vid={:?}",
            expected_has_vid
        );
        debug!("try_report_placeholders_trait: has_sub={:?}", has_sub);
        debug!("try_report_placeholders_trait: has_sup={:?}", has_sup);
        debug!(
            "try_report_placeholders_trait: actual_self_ty_has_vid={:?}",
            actual_self_ty_has_vid
        );
        debug!(
            "try_report_placeholders_trait: expected_self_ty_has_vid={:?}",
            expected_self_ty_has_vid
        );

        // The weird thing here with the `maybe_highlighting_region` calls and the
        // the match inside is meant to be like this:
        //
        // - The match checks whether the given things (placeholders, etc) appear
        //   in the types are about to print
        // - Meanwhile, the `maybe_highlighting_region` calls set up
        //   highlights so that, if they do appear, we will replace
        //   them `'0` and whatever.  (This replacement takes place
        //   inside the closure given to `maybe_highlighting_region`.)
        //
        // There is some duplication between the calls -- i.e., the
        // `maybe_highlighting_region` checks if (e.g.) `has_sub` is
        // None, an then we check again inside the closure, but this
        // setup sort of minimized the number of calls and so form.

        RegionHighlightMode::maybe_highlighting_region(sub_placeholder, has_sub, || {
            RegionHighlightMode::maybe_highlighting_region(sup_placeholder, has_sup, || {
                match (has_sub, has_sup) {
                    (Some(n1), Some(n2)) => {
                        if self_ty_has_vid {
                            err.note(&format!(
                                "`{}` would have to be implemented for the type `{}`, \
                                 for any two lifetimes `'{}` and `'{}`",
                                expected_trait_ref,
                                expected_trait_ref.self_ty(),
                                std::cmp::min(n1, n2),
                                std::cmp::max(n1, n2),
                            ));
                        } else {
                            err.note(&format!(
                                "`{}` must implement `{}`, \
                                 for any two lifetimes `'{}` and `'{}`",
                                expected_trait_ref.self_ty(),
                                expected_trait_ref,
                                std::cmp::min(n1, n2),
                                std::cmp::max(n1, n2),
                            ));
                        }
                    }
                    (Some(n), _) | (_, Some(n)) => {
                        if self_ty_has_vid {
                            err.note(&format!(
                                "`{}` would have to be implemented for the type `{}`, \
                                 for any lifetime `'{}`",
                                expected_trait_ref,
                                expected_trait_ref.self_ty(),
                                n,
                            ));
                        } else {
                            err.note(&format!(
                                "`{}` must implement `{}`, for any lifetime `'{}`",
                                expected_trait_ref.self_ty(),
                                expected_trait_ref,
                                n,
                            ));
                        }
                    }
                    (None, None) => RegionHighlightMode::maybe_highlighting_region(
                        vid,
                        expected_has_vid,
                        || {
                            if let Some(n) = expected_has_vid {
                                err.note(&format!(
                                    "`{}` would have to be implemented for the type `{}`, \
                                     for some specific lifetime `'{}`",
                                    expected_trait_ref,
                                    expected_trait_ref.self_ty(),
                                    n,
                                ));
                            } else {
                                if self_ty_has_vid {
                                    err.note(&format!(
                                        "`{}` would have to be implemented for the type `{}`",
                                        expected_trait_ref,
                                        expected_trait_ref.self_ty(),
                                    ));
                                } else {
                                    err.note(&format!(
                                        "`{}` must implement `{}`",
                                        expected_trait_ref.self_ty(),
                                        expected_trait_ref,
                                    ));
                                }
                            }
                        },
                    ),
                }
            })
        });

        RegionHighlightMode::maybe_highlighting_region(
            vid,
            actual_has_vid,
            || match actual_has_vid {
                Some(n) => {
                    if self_ty_has_vid {
                        err.note(&format!(
                            "but `{}` is actually implemented for the type `{}`, \
                             for the specific lifetime `'{}`",
                            actual_trait_ref,
                            actual_trait_ref.self_ty(),
                            n
                        ));
                    } else {
                        err.note(&format!(
                            "but `{}` actually implements `{}`, for some lifetime `'{}`",
                            actual_trait_ref.self_ty(),
                            actual_trait_ref,
                            n
                        ));
                    }
                }

                _ => {
                    err.note(&format!(
                        "but `{}` is actually implemented for the type `{}`",
                        actual_trait_ref,
                        actual_trait_ref.self_ty(),
                    ));
                }
            },
        );

        err.emit();
        ErrorReported
    }
}
<commit_msg>Extract the notes explaining the placeholder region errors to a helper fn<commit_after>use errors::DiagnosticBuilder;
use hir::def_id::DefId;
use infer::error_reporting::nice_region_error::NiceRegionError;
use infer::lexical_region_resolve::RegionResolutionError;
use infer::ValuePairs;
use infer::{SubregionOrigin, TypeTrace};
use traits::{ObligationCause, ObligationCauseCode};
use ty;
use ty::error::ExpectedFound;
use ty::subst::Substs;
use util::common::ErrorReported;
use util::ppaux::RegionHighlightMode;

impl NiceRegionError<'me, 'gcx, 'tcx> {
    /// When given a `ConcreteFailure` for a function with arguments containing a named region and
    /// an anonymous region, emit an descriptive diagnostic error.
    pub(super) fn try_report_placeholder_conflict(&self) -> Option<ErrorReported> {
        match &self.error {
            ///////////////////////////////////////////////////////////////////////////
            // NB. The ordering of cases in this match is very
            // sensitive, because we are often matching against
            // specific cases and then using an `_` to match all
            // others.

            ///////////////////////////////////////////////////////////////////////////
            // Check for errors from comparing trait failures -- first
            // with two placeholders, then with one.
            Some(RegionResolutionError::SubSupConflict(
                vid,
                _,
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sub_placeholder @ ty::RePlaceholder(_),
                _,
                sup_placeholder @ ty::RePlaceholder(_),
            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
                Some(self.tcx().mk_region(ty::ReVar(*vid))),
                cause,
                Some(sub_placeholder),
                Some(sup_placeholder),
                expected.def_id,
                expected.substs,
                found.substs,
            )),

            Some(RegionResolutionError::SubSupConflict(
                vid,
                _,
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sub_placeholder @ ty::RePlaceholder(_),
                _,
                _,
            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
                Some(self.tcx().mk_region(ty::ReVar(*vid))),
                cause,
                Some(sub_placeholder),
                None,
                expected.def_id,
                expected.substs,
                found.substs,
            )),

            Some(RegionResolutionError::SubSupConflict(
                vid,
                _,
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                _,
                _,
                sup_placeholder @ ty::RePlaceholder(_),
            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
                Some(self.tcx().mk_region(ty::ReVar(*vid))),
                cause,
                None,
                Some(*sup_placeholder),
                expected.def_id,
                expected.substs,
                found.substs,
            )),

            Some(RegionResolutionError::SubSupConflict(
                vid,
                _,
                _,
                _,
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sup_placeholder @ ty::RePlaceholder(_),
            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
                Some(self.tcx().mk_region(ty::ReVar(*vid))),
                cause,
                None,
                Some(*sup_placeholder),
                expected.def_id,
                expected.substs,
                found.substs,
            )),

            Some(RegionResolutionError::ConcreteFailure(
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sub_region @ ty::RePlaceholder(_),
                sup_region @ ty::RePlaceholder(_),
            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
                None,
                cause,
                Some(*sub_region),
                Some(*sup_region),
                expected.def_id,
                expected.substs,
                found.substs,
            )),

            Some(RegionResolutionError::ConcreteFailure(
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sub_region @ ty::RePlaceholder(_),
                sup_region,
            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
                Some(sup_region),
                cause,
                Some(*sub_region),
                None,
                expected.def_id,
                expected.substs,
                found.substs,
            )),

            Some(RegionResolutionError::ConcreteFailure(
                SubregionOrigin::Subtype(TypeTrace {
                    cause,
                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
                }),
                sub_region,
                sup_region @ ty::RePlaceholder(_),
            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
                Some(sub_region),
                cause,
                None,
                Some(*sup_region),
                expected.def_id,
                expected.substs,
                found.substs,
            )),

            _ => None,
        }
    }

    // error[E0308]: implementation of `Foo` does not apply to enough lifetimes
    //   --> /home/nmatsakis/tmp/foo.rs:12:5
    //    |
    // 12 |     all::<&'static u32>();
    //    |     ^^^^^^^^^^^^^^^^^^^ lifetime mismatch
    //    |
    //    = note: Due to a where-clause on the function `all`,
    //    = note: `T` must implement `...` for any two lifetimes `'1` and `'2`.
    //    = note: However, the type `T` only implements `...` for some specific lifetime `'2`.
    fn try_report_placeholders_trait(
        &self,
        vid: Option<ty::Region<'tcx>>,
        cause: &ObligationCause<'tcx>,
        sub_placeholder: Option<ty::Region<'tcx>>,
        sup_placeholder: Option<ty::Region<'tcx>>,
        trait_def_id: DefId,
        expected_substs: &'tcx Substs<'tcx>,
        actual_substs: &'tcx Substs<'tcx>,
    ) -> ErrorReported {
        debug!(
            "try_report_placeholders_trait(\
             vid={:?}, \
             sub_placeholder={:?}, \
             sup_placeholder={:?}, \
             trait_def_id={:?}, \
             expected_substs={:?}, \
             actual_substs={:?})",
            vid, sub_placeholder, sup_placeholder, trait_def_id, expected_substs, actual_substs
        );

        let mut err = self.tcx().sess.struct_span_err(
            cause.span(&self.tcx()),
            &format!(
                "implementation of `{}` is not general enough",
                self.tcx().item_path_str(trait_def_id),
            ),
        );

        match cause.code {
            ObligationCauseCode::ItemObligation(def_id) => {
                err.note(&format!(
                    "Due to a where-clause on `{}`,",
                    self.tcx().item_path_str(def_id),
                ));
            }
            _ => (),
        }

        let expected_trait_ref = self.infcx.resolve_type_vars_if_possible(&ty::TraitRef {
            def_id: trait_def_id,
            substs: expected_substs,
        });
        let actual_trait_ref = self.infcx.resolve_type_vars_if_possible(&ty::TraitRef {
            def_id: trait_def_id,
            substs: actual_substs,
        });

        // Search the expected and actual trait references to see (a)
        // whether the sub/sup placeholders appear in them (sometimes
        // you have a trait ref like `T: Foo<fn(&u8)>`, where the
        // placeholder was created as part of an inner type) and (b)
        // whether the inference variable appears. In each case,
        // assign a counter value in each case if so.
        let mut counter = 0;
        let mut has_sub = None;
        let mut has_sup = None;

        let mut actual_has_vid = None;
        let mut expected_has_vid = None;

        self.tcx().for_each_free_region(&expected_trait_ref, |r| {
            if Some(r) == sub_placeholder && has_sub.is_none() {
                has_sub = Some(counter);
                counter += 1;
            } else if Some(r) == sup_placeholder && has_sup.is_none() {
                has_sup = Some(counter);
                counter += 1;
            }

            if Some(r) == vid && expected_has_vid.is_none() {
                expected_has_vid = Some(counter);
                counter += 1;
            }
        });

        self.tcx().for_each_free_region(&actual_trait_ref, |r| {
            if Some(r) == vid && actual_has_vid.is_none() {
                actual_has_vid = Some(counter);
                counter += 1;
            }
        });

        let actual_self_ty_has_vid = self
            .tcx()
            .any_free_region_meets(&actual_trait_ref.self_ty(), |r| Some(r) == vid);

        let expected_self_ty_has_vid = self
            .tcx()
            .any_free_region_meets(&expected_trait_ref.self_ty(), |r| Some(r) == vid);

        let any_self_ty_has_vid = actual_self_ty_has_vid || expected_self_ty_has_vid;

        debug!(
            "try_report_placeholders_trait: actual_has_vid={:?}",
            actual_has_vid
        );
        debug!(
            "try_report_placeholders_trait: expected_has_vid={:?}",
            expected_has_vid
        );
        debug!("try_report_placeholders_trait: has_sub={:?}", has_sub);
        debug!("try_report_placeholders_trait: has_sup={:?}", has_sup);
        debug!(
            "try_report_placeholders_trait: actual_self_ty_has_vid={:?}",
            actual_self_ty_has_vid
        );
        debug!(
            "try_report_placeholders_trait: expected_self_ty_has_vid={:?}",
            expected_self_ty_has_vid
        );

        self.explain_actual_impl_that_was_found(
            &mut err,
            sub_placeholder,
            sup_placeholder,
            has_sub,
            has_sup,
            expected_trait_ref,
            actual_trait_ref,
            vid,
            expected_has_vid,
            actual_has_vid,
            any_self_ty_has_vid,
        );

        err.emit();
        ErrorReported
    }

    /// Add notes with details about the expected and actual trait refs, with attention to cases
    /// when placeholder regions are involved: either the trait or the self type containing
    /// them needs to be mentioned the closest to the placeholders.
    /// This makes the error messages read better, however at the cost of some complexity
    /// due to the number of combinations we have to deal with.
    fn explain_actual_impl_that_was_found(
        &self,
        err: &mut DiagnosticBuilder<'_>,
        sub_placeholder: Option<ty::Region<'tcx>>,
        sup_placeholder: Option<ty::Region<'tcx>>,
        has_sub: Option<usize>,
        has_sup: Option<usize>,
        expected_trait_ref: ty::TraitRef<'_>,
        actual_trait_ref: ty::TraitRef<'_>,
        vid: Option<ty::Region<'tcx>>,
        expected_has_vid: Option<usize>,
        actual_has_vid: Option<usize>,
        any_self_ty_has_vid: bool,
    ) {
        // The weird thing here with the `maybe_highlighting_region` calls and the
        // the match inside is meant to be like this:
        //
        // - The match checks whether the given things (placeholders, etc) appear
        //   in the types are about to print
        // - Meanwhile, the `maybe_highlighting_region` calls set up
        //   highlights so that, if they do appear, we will replace
        //   them `'0` and whatever.  (This replacement takes place
        //   inside the closure given to `maybe_highlighting_region`.)
        //
        // There is some duplication between the calls -- i.e., the
        // `maybe_highlighting_region` checks if (e.g.) `has_sub` is
        // None, an then we check again inside the closure, but this
        // setup sort of minimized the number of calls and so form.

        RegionHighlightMode::maybe_highlighting_region(sub_placeholder, has_sub, || {
            RegionHighlightMode::maybe_highlighting_region(sup_placeholder, has_sup, || {
                match (has_sub, has_sup) {
                    (Some(n1), Some(n2)) => {
                        if any_self_ty_has_vid {
                            err.note(&format!(
                                "`{}` would have to be implemented for the type `{}`, \
                                 for any two lifetimes `'{}` and `'{}`",
                                expected_trait_ref,
                                expected_trait_ref.self_ty(),
                                std::cmp::min(n1, n2),
                                std::cmp::max(n1, n2),
                            ));
                        } else {
                            err.note(&format!(
                                "`{}` must implement `{}`, \
                                 for any two lifetimes `'{}` and `'{}`",
                                expected_trait_ref.self_ty(),
                                expected_trait_ref,
                                std::cmp::min(n1, n2),
                                std::cmp::max(n1, n2),
                            ));
                        }
                    }
                    (Some(n), _) | (_, Some(n)) => {
                        if any_self_ty_has_vid {
                            err.note(&format!(
                                "`{}` would have to be implemented for the type `{}`, \
                                 for any lifetime `'{}`",
                                expected_trait_ref,
                                expected_trait_ref.self_ty(),
                                n,
                            ));
                        } else {
                            err.note(&format!(
                                "`{}` must implement `{}`, for any lifetime `'{}`",
                                expected_trait_ref.self_ty(),
                                expected_trait_ref,
                                n,
                            ));
                        }
                    }
                    (None, None) => RegionHighlightMode::maybe_highlighting_region(
                        vid,
                        expected_has_vid,
                        || {
                            if let Some(n) = expected_has_vid {
                                err.note(&format!(
                                    "`{}` would have to be implemented for the type `{}`, \
                                     for some specific lifetime `'{}`",
                                    expected_trait_ref,
                                    expected_trait_ref.self_ty(),
                                    n,
                                ));
                            } else {
                                if any_self_ty_has_vid {
                                    err.note(&format!(
                                        "`{}` would have to be implemented for the type `{}`",
                                        expected_trait_ref,
                                        expected_trait_ref.self_ty(),
                                    ));
                                } else {
                                    err.note(&format!(
                                        "`{}` must implement `{}`",
                                        expected_trait_ref.self_ty(),
                                        expected_trait_ref,
                                    ));
                                }
                            }
                        },
                    ),
                }
            })
        });

        RegionHighlightMode::maybe_highlighting_region(
            vid,
            actual_has_vid,
            || match actual_has_vid {
                Some(n) => {
                    if any_self_ty_has_vid {
                        err.note(&format!(
                            "but `{}` is actually implemented for the type `{}`, \
                             for the specific lifetime `'{}`",
                            actual_trait_ref,
                            actual_trait_ref.self_ty(),
                            n
                        ));
                    } else {
                        err.note(&format!(
                            "but `{}` actually implements `{}`, for some lifetime `'{}`",
                            actual_trait_ref.self_ty(),
                            actual_trait_ref,
                            n
                        ));
                    }
                }

                _ => {
                    err.note(&format!(
                        "but `{}` is actually implemented for the type `{}`",
                        actual_trait_ref,
                        actual_trait_ref.self_ty(),
                    ));
                }
            },
        );
    }
}
<|endoftext|>


<commit_before>//!
//! A reply is passed to filesystem operation implementations and must
//! be used to send back the result of an operation.
//! The reply can optionally be sent to another task to asynchronously
//! work on an operation and provide the result later. Also it allows
//! replying with a block of data without cloning the data.
//! A reply *must always* be used (by calling either ok() or error()
//! exactly once).
//!

use std::{mem, slice};
use std::libc::{c_int, EIO};
use fuse::fuse_out_header;
use sendable::{Sendable, DirBuffer};

/// Generic reply trait
pub trait Reply {
	/// Create a new reply for the given request
	fn new (unique: u64, sender: proc:Send(&[&[u8]])) -> Self;
}

/// Serialize an arbitrary type to bytes (memory copy, useful for fuse_*_out types)
fn as_bytes<T: Copy, U> (data: &T, f: |&[&[u8]]| -> U) -> U {
	let len = mem::size_of::<T>();
	match len {
		0 => f([]),
		len => unsafe { slice::raw::buf_as_slice(data as *T as *u8, len, |bytes| f([bytes]) ) },
	}
}

///
/// Raw reply
///
pub struct ReplyRaw<T> {
	/// Unique id of the request to reply to
	unique: u64,
	/// Proc to call for sending the reply
	sender: Option<proc:Send(&[&[u8]])>,
}

impl<T: Copy> Reply for ReplyRaw<T> {
	fn new (unique: u64, sender: proc:Send(&[&[u8]])) -> ReplyRaw<T> {
		ReplyRaw { unique: unique, sender: Some(sender) }
	}
}

impl<T: Copy> ReplyRaw<T> {
	/// Reply to a request with the given error code and data. Must be called
	/// only once (the `ok` and `error` methods ensure this by consuming `self`)
	fn send (&mut self, err: c_int, bytes: &[&[u8]]) {
		assert!(self.sender.is_some());
		let len = bytes.iter().fold(0, |l, b| { l +  b.len()});
		let header = fuse_out_header {
			len: (mem::size_of::<fuse_out_header>() + len) as u32,
			error: -err,
			unique: self.unique,
		};
		as_bytes(&header, |headerbytes| {
			let sender = self.sender.take_unwrap();
			sender(headerbytes + bytes);
		});
	}

	/// Reply to a request with the given type
	pub fn ok (mut self, data: &T) {
		as_bytes(data, |bytes| {
			self.send(0, bytes);
		})
	}

	/// Reply to a request with the given error code
	pub fn error (mut self, err: c_int) {
		self.send(err, []);
	}
}

#[unsafe_destructor]
impl<T: Copy> Drop for ReplyRaw<T> {
	fn drop (&mut self) {
		if self.sender.is_some() {
			warn!("Reply not sent for operation {:u}, replying with I/O error", self.unique);
			self.send(EIO, []);
		}
	}
}

///
/// Empty reply
///
pub struct ReplyEmpty {
	reply: ReplyRaw<()>,
}

impl Reply for ReplyEmpty {
	fn new (unique: u64, sender: proc:Send(&[&[u8]])) -> ReplyEmpty {
		ReplyEmpty { reply: Reply::new(unique, sender) }
	}
}

impl ReplyEmpty {
	/// Reply to a request with nothing
	pub fn ok (mut self) {
		self.reply.send(0, []);
	}

	/// Reply to a request with the given error code
	pub fn error (self, err: c_int) {
		self.reply.error(err);
	}
}

///
/// Data reply
///
pub struct ReplyData {
	reply: ReplyRaw<()>,
}

impl Reply for ReplyData {
	fn new (unique: u64, sender: proc:Send(&[&[u8]])) -> ReplyData {
		ReplyData { reply: Reply::new(unique, sender) }
	}
}

impl ReplyData {
	/// Reply to a request with the given data
	pub fn ok (mut self, data: &[u8]) {
		self.reply.send(0, [data]);
	}

	/// Reply to a request with the given error code
	pub fn error (self, err: c_int) {
		self.reply.error(err);
	}
}

///
/// Directory reply
///
pub struct ReplyDirectory {
	reply: ReplyRaw<()>,
}

impl Reply for ReplyDirectory {
	fn new (unique: u64, sender: proc:Send(&[&[u8]])) -> ReplyDirectory {
		ReplyDirectory { reply: Reply::new(unique, sender) }
	}
}

impl ReplyDirectory {
	/// Reply to a request with the given data
	pub fn ok (mut self, buffer: &DirBuffer) {
		buffer.as_bytegroups(|bytes| {
			self.reply.send(0, bytes);
		});
	}

	/// Reply to a request with the given error code
	pub fn error (self, err: c_int) {
		self.reply.error(err);
	}
}

#[cfg(test)]
mod test {
	use super::as_bytes;

	#[test]
	fn serialize_empty () {
		let data = ();
		as_bytes(&data, |bytes| {
			assert!(bytes == []);
		});
	}

	#[test]
	fn serialize_slice () {
		let data: [u8, ..4] = [0x12, 0x34, 0x56, 0x78];
		as_bytes(&data, |bytes| {
			assert!(bytes == [&[0x12, 0x34, 0x56, 0x78]]);
		});
	}

	#[test]
	fn serialize_struct () {
		struct Data { a: u8, b: u8, c: u16 }
		let data = Data { a: 0x12, b: 0x34, c: 0x5678 };
		as_bytes(&data, |bytes| {
			assert!(bytes == [&[0x12, 0x34, 0x78, 0x56]]);
		});
	}
}
<commit_msg>Add reply tests<commit_after>//!
//! A reply is passed to filesystem operation implementations and must
//! be used to send back the result of an operation.
//! The reply can optionally be sent to another task to asynchronously
//! work on an operation and provide the result later. Also it allows
//! replying with a block of data without cloning the data.
//! A reply *must always* be used (by calling either ok() or error()
//! exactly once).
//!

use std::{mem, slice};
use std::libc::{c_int, EIO};
use fuse::fuse_out_header;
use sendable::{Sendable, DirBuffer};

/// Generic reply trait
pub trait Reply {
	/// Create a new reply for the given request
	fn new (unique: u64, sender: proc:Send(&[&[u8]])) -> Self;
}

/// Serialize an arbitrary type to bytes (memory copy, useful for fuse_*_out types)
fn as_bytes<T: Copy, U> (data: &T, f: |&[&[u8]]| -> U) -> U {
	let len = mem::size_of::<T>();
	match len {
		0 => f([]),
		len => unsafe { slice::raw::buf_as_slice(data as *T as *u8, len, |bytes| f([bytes]) ) },
	}
}

///
/// Raw reply
///
pub struct ReplyRaw<T> {
	/// Unique id of the request to reply to
	unique: u64,
	/// Proc to call for sending the reply
	sender: Option<proc:Send(&[&[u8]])>,
}

impl<T: Copy> Reply for ReplyRaw<T> {
	fn new (unique: u64, sender: proc:Send(&[&[u8]])) -> ReplyRaw<T> {
		ReplyRaw { unique: unique, sender: Some(sender) }
	}
}

impl<T: Copy> ReplyRaw<T> {
	/// Reply to a request with the given error code and data. Must be called
	/// only once (the `ok` and `error` methods ensure this by consuming `self`)
	fn send (&mut self, err: c_int, bytes: &[&[u8]]) {
		assert!(self.sender.is_some());
		let len = bytes.iter().fold(0, |l, b| { l +  b.len()});
		let header = fuse_out_header {
			len: (mem::size_of::<fuse_out_header>() + len) as u32,
			error: -err,
			unique: self.unique,
		};
		as_bytes(&header, |headerbytes| {
			let sender = self.sender.take_unwrap();
			sender(headerbytes + bytes);
		});
	}

	/// Reply to a request with the given type
	pub fn ok (mut self, data: &T) {
		as_bytes(data, |bytes| {
			self.send(0, bytes);
		})
	}

	/// Reply to a request with the given error code
	pub fn error (mut self, err: c_int) {
		self.send(err, []);
	}
}

#[unsafe_destructor]
impl<T: Copy> Drop for ReplyRaw<T> {
	fn drop (&mut self) {
		if self.sender.is_some() {
			warn!("Reply not sent for operation {:u}, replying with I/O error", self.unique);
			self.send(EIO, []);
		}
	}
}

///
/// Empty reply
///
pub struct ReplyEmpty {
	reply: ReplyRaw<()>,
}

impl Reply for ReplyEmpty {
	fn new (unique: u64, sender: proc:Send(&[&[u8]])) -> ReplyEmpty {
		ReplyEmpty { reply: Reply::new(unique, sender) }
	}
}

impl ReplyEmpty {
	/// Reply to a request with nothing
	pub fn ok (mut self) {
		self.reply.send(0, []);
	}

	/// Reply to a request with the given error code
	pub fn error (self, err: c_int) {
		self.reply.error(err);
	}
}

///
/// Data reply
///
pub struct ReplyData {
	reply: ReplyRaw<()>,
}

impl Reply for ReplyData {
	fn new (unique: u64, sender: proc:Send(&[&[u8]])) -> ReplyData {
		ReplyData { reply: Reply::new(unique, sender) }
	}
}

impl ReplyData {
	/// Reply to a request with the given data
	pub fn ok (mut self, data: &[u8]) {
		self.reply.send(0, [data]);
	}

	/// Reply to a request with the given error code
	pub fn error (self, err: c_int) {
		self.reply.error(err);
	}
}

///
/// Directory reply
///
pub struct ReplyDirectory {
	reply: ReplyRaw<()>,
}

impl Reply for ReplyDirectory {
	fn new (unique: u64, sender: proc:Send(&[&[u8]])) -> ReplyDirectory {
		ReplyDirectory { reply: Reply::new(unique, sender) }
	}
}

impl ReplyDirectory {
	/// Reply to a request with the given data
	pub fn ok (mut self, buffer: &DirBuffer) {
		buffer.as_bytegroups(|bytes| {
			self.reply.send(0, bytes);
		});
	}

	/// Reply to a request with the given error code
	pub fn error (self, err: c_int) {
		self.reply.error(err);
	}
}

#[cfg(test)]
mod test {
	use super::as_bytes;
	use super::{Reply, ReplyRaw, ReplyEmpty, ReplyData};

	#[test]
	fn serialize_empty () {
		let data = ();
		as_bytes(&data, |bytes| {
			assert!(bytes == []);
		});
	}

	#[test]
	fn serialize_slice () {
		let data: [u8, ..4] = [0x12, 0x34, 0x56, 0x78];
		as_bytes(&data, |bytes| {
			assert!(bytes == [&[0x12, 0x34, 0x56, 0x78]]);
		});
	}

	#[test]
	fn serialize_struct () {
		struct Data { a: u8, b: u8, c: u16 }
		let data = Data { a: 0x12, b: 0x34, c: 0x5678 };
		as_bytes(&data, |bytes| {
			assert!(bytes == [&[0x12, 0x34, 0x78, 0x56]]);
		});
	}

	#[test]
	fn reply_raw () {
		struct Data { a: u8, b: u8, c: u16 }
		let data = Data { a: 0x12, b: 0x34, c: 0x5678 };
		let reply: ReplyRaw<Data> = Reply::new(0xdeadbeef, proc(bytes) {
			assert!(bytes == [
				&[0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0xef, 0xbe, 0xad, 0xde, 0x00, 0x00, 0x00, 0x00],
				&[0x12, 0x34, 0x78, 0x56],
			]);
		});
		reply.ok(&data);
	}

	#[test]
	fn reply_error () {
		struct Data { a: u8, b: u8, c: u16 }
		let reply: ReplyRaw<Data> = Reply::new(0xdeadbeef, proc(bytes) {
			assert!(bytes == [
				&[0x10, 0x00, 0x00, 0x00, 0xbe, 0xff, 0xff, 0xff,  0xef, 0xbe, 0xad, 0xde, 0x00, 0x00, 0x00, 0x00],
			]);
		});
		reply.error(66);
	}

	#[test]
	fn reply_empty () {
		let reply: ReplyEmpty = Reply::new(0xdeadbeef, proc(bytes) {
			assert!(bytes == [
				&[0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0xef, 0xbe, 0xad, 0xde, 0x00, 0x00, 0x00, 0x00],
			]);
		});
		reply.ok();
	}

	#[test]
	fn reply_data () {
		let reply: ReplyData = Reply::new(0xdeadbeef, proc(bytes) {
			assert!(bytes == [
				&[0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0xef, 0xbe, 0xad, 0xde, 0x00, 0x00, 0x00, 0x00],
				&[0xde, 0xad, 0xbe, 0xef],
			]);
		});
		reply.ok([0xde, 0xad, 0xbe, 0xef]);
	}
}
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2017 Guillaume Gomez
//

#![crate_type = "bin"]

#![allow(unused_must_use, non_upper_case_globals)]

extern crate sysinfo;

use sysinfo::{NetworkExt, Pid, ProcessExt, ProcessorExt, Signal, System, SystemExt};
use sysinfo::Signal::*;
use std::io::{self, BufRead, Write};
use std::str::FromStr;

const signals: [Signal; 31] = [Hangup, Interrupt, Quit, Illegal, Trap, Abort, Bus,
                               FloatingPointException, Kill, User1, Segv, User2, Pipe, Alarm,
                               Term, Stklft, Child, Continue, Stop, TSTP, TTIN, TTOU, Urgent,
                               XCPU, XFSZ, VirtualAlarm, Profiling, Winch, IO, Power, Sys];

fn print_help() {
    writeln!(&mut io::stdout(), "== Help menu ==");
    writeln!(&mut io::stdout(), "help               : show this menu");
    writeln!(&mut io::stdout(), "signals            : show the available signals");
    writeln!(&mut io::stdout(), "refresh            : reloads all processes' information");
    writeln!(&mut io::stdout(), "refresh [pid]      : reloads corresponding process' information");
    writeln!(&mut io::stdout(), "refresh_disks      : reloads only disks' information");
    writeln!(&mut io::stdout(), "show [pid | name]  : show information of the given process \
                                 corresponding to [pid | name]");
    writeln!(&mut io::stdout(), "kill [pid] [signal]: send [signal] to the process with this \
                                 [pid]. 0 < [signal] < 32");
    writeln!(&mut io::stdout(), "proc               : Displays proc state");
    writeln!(&mut io::stdout(), "memory             : Displays memory state");
    writeln!(&mut io::stdout(), "temperature        : Displays components' temperature");
    writeln!(&mut io::stdout(), "disks              : Displays disks' information");
    writeln!(&mut io::stdout(), "network            : Displays network' information");
    writeln!(&mut io::stdout(), "all                : Displays all process name and pid");
    writeln!(&mut io::stdout(), "uptime             : Displays system uptime");
    writeln!(&mut io::stdout(), "quit               : exit the program");
}

fn interpret_input(input: &str, sys: &mut System) -> bool {
    match input.trim() {
        "help" => print_help(),
        "refresh_disks" => {
            writeln!(&mut io::stdout(), "Refreshing disk list...");
            sys.refresh_disk_list();
            writeln!(&mut io::stdout(), "Done.");
        }
        "signals" => {
            let mut nb = 1i32;

            for sig in &signals {
                writeln!(&mut io::stdout(), "{:2}:{:?}", nb, sig);
                nb += 1;
            }
        }
        "proc" => {
            let procs = sys.get_processor_list();

            writeln!(&mut io::stdout(), "total process usage: {}%", procs[0].get_cpu_usage());
            for proc_ in procs.iter().skip(1) {
                writeln!(&mut io::stdout(), "{:?}", proc_);
            }
        }
        "memory" => {
            writeln!(&mut io::stdout(), "total memory: {} kB", sys.get_total_memory());
            writeln!(&mut io::stdout(), "used memory : {} kB", sys.get_used_memory());
            writeln!(&mut io::stdout(), "total swap  : {} kB", sys.get_total_swap());
            writeln!(&mut io::stdout(), "used swap   : {} kB", sys.get_used_swap());
        }
        "quit" | "exit" => return true,
        "all" => {
            for (pid, proc_) in sys.get_process_list() {
                writeln!(&mut io::stdout(), "{}:{} status={:?}", pid, proc_.name(), proc_.status());
            }
        }
        e if e.starts_with("show ") => {
            let tmp : Vec<&str> = e.split(' ').collect();

            if tmp.len() != 2 {
                writeln!(&mut io::stdout(), "show command takes a pid or a name in parameter!");
                writeln!(&mut io::stdout(), "example: show 1254");
            } else if let Ok(pid) = Pid::from_str(tmp[1]) {
                match sys.get_process(pid) {
                    Some(p) => writeln!(&mut io::stdout(), "{:?}", *p),
                    None => writeln!(&mut io::stdout(), "pid not found")
                };
            } else {
                let proc_name = tmp[1];
                for proc_ in sys.get_process_by_name(proc_name) {
                    writeln!(&mut io::stdout(), "==== {} ====", proc_.name());
                    writeln!(&mut io::stdout(), "{:?}", proc_);
                }
            }
        }
        "temperature" => {
            for component in sys.get_components_list() {
                writeln!(&mut io::stdout(), "{:?}", component);
            }
        }
        "network" => {
            writeln!(&mut io::stdout(), "input data : {} B", sys.get_network().get_income());
            writeln!(&mut io::stdout(), "output data: {} B", sys.get_network().get_outcome());
        }
        "show" => {
            writeln!(&mut io::stdout(), "'show' command expects a pid number or a process name");
        }
        e if e.starts_with("kill ") => {
            let tmp : Vec<&str> = e.split(' ').collect();

            if tmp.len() != 3 {
                writeln!(&mut io::stdout(),
                         "kill command takes the pid and a signal number in parameter !");
                writeln!(&mut io::stdout(), "example: kill 1254 9");
            } else {
                let pid = Pid::from_str(tmp[1]).unwrap();
                let signal = i32::from_str(tmp[2]).unwrap();

                if signal < 1 || signal > 31 {
                    writeln!(&mut io::stdout(),
                             "Signal must be between 0 and 32 ! See the signals list with the \
                              signals command");
                } else {
                    match sys.get_process(pid) {
                        Some(p) => {
                            writeln!(&mut io::stdout(), "kill: {}",
                                     p.kill(*signals.get(signal as usize - 1).unwrap()));
                        },
                        None => {
                            writeln!(&mut io::stdout(), "pid not found");
                        }
                    };
                }
            }
        }
        "disks" => {
            for disk in sys.get_disks() {
                writeln!(&mut io::stdout(), "{:?}", disk);
            }
        }
        "uptime" => {
            let mut uptime = sys.get_uptime();
            let days = uptime / 86400;
            uptime -= days * 86400;
            let hours = uptime / 3600;
            uptime -= hours * 3600;
            let minutes = uptime / 60;
            writeln!(&mut io::stdout(),
                     "{} days {} hours {} minutes",
                     days,
                     hours,
                     minutes);
        }
        x if x.starts_with("refresh") => {
            if x == "refresh" {
                writeln!(&mut io::stdout(), "Getting processes' information...");
                sys.refresh_all();
                writeln!(&mut io::stdout(), "Done.");
            } else if x.starts_with("refresh ") {
                writeln!(&mut io::stdout(), "Getting process' information...");
                if let Some(pid) = x.split(' ').filter_map(|pid| pid.parse().ok()).take(1).next() {
                    if sys.refresh_process(pid) {
                        writeln!(&mut io::stdout(), "Process `{}` updated successfully", pid);
                    } else {
                        writeln!(&mut io::stdout(), "Process `{}` couldn't be updated...", pid);
                    }
                } else {
                    writeln!(&mut io::stdout(), "Invalid [pid] received...");
                }
            } else {
                writeln!(&mut io::stdout(),
                     "\"{}\": Unknown command. Enter 'help' if you want to get the commands' \
                      list.", x);
            }
        }
        e => {
            writeln!(&mut io::stdout(),
                     "\"{}\": Unknown command. Enter 'help' if you want to get the commands' \
                      list.", e);
        }
    }
    false
}

fn main() {
    println!("Getting processes' information...");
    let mut t = System::new();
    println!("Done.");
    let t_stin = io::stdin();
    let mut stin = t_stin.lock();
    let mut done = false;

    println!("To get the commands' list, enter 'help'.");
    while !done {
        let mut input = String::new();
        write!(&mut io::stdout(), "> ");
        io::stdout().flush();

        stin.read_line(&mut input);
        if (&input as &str).ends_with('\n') {
            input.pop();
        }
        done = interpret_input(input.as_ref(), &mut t);
    }
}
<commit_msg>Add note about needing to refresh<commit_after>//
// Sysinfo
//
// Copyright (c) 2017 Guillaume Gomez
//

#![crate_type = "bin"]

#![allow(unused_must_use, non_upper_case_globals)]

extern crate sysinfo;

use sysinfo::{NetworkExt, Pid, ProcessExt, ProcessorExt, Signal, System, SystemExt};
use sysinfo::Signal::*;
use std::io::{self, BufRead, Write};
use std::str::FromStr;

const signals: [Signal; 31] = [Hangup, Interrupt, Quit, Illegal, Trap, Abort, Bus,
                               FloatingPointException, Kill, User1, Segv, User2, Pipe, Alarm,
                               Term, Stklft, Child, Continue, Stop, TSTP, TTIN, TTOU, Urgent,
                               XCPU, XFSZ, VirtualAlarm, Profiling, Winch, IO, Power, Sys];

fn print_help() {
    writeln!(&mut io::stdout(), "== Help menu ==");
    writeln!(&mut io::stdout(), "help               : show this menu");
    writeln!(&mut io::stdout(), "signals            : show the available signals");
    writeln!(&mut io::stdout(), "refresh            : reloads all processes' information");
    writeln!(&mut io::stdout(), "refresh [pid]      : reloads corresponding process' information");
    writeln!(&mut io::stdout(), "refresh_disks      : reloads only disks' information");
    writeln!(&mut io::stdout(), "show [pid | name]  : show information of the given process \
                                 corresponding to [pid | name]");
    writeln!(&mut io::stdout(), "kill [pid] [signal]: send [signal] to the process with this \
                                 [pid]. 0 < [signal] < 32");
    writeln!(&mut io::stdout(), "proc               : Displays proc state");
    writeln!(&mut io::stdout(), "memory             : Displays memory state");
    writeln!(&mut io::stdout(), "temperature        : Displays components' temperature");
    writeln!(&mut io::stdout(), "disks              : Displays disks' information");
    writeln!(&mut io::stdout(), "network            : Displays network' information");
    writeln!(&mut io::stdout(), "all                : Displays all process name and pid");
    writeln!(&mut io::stdout(), "uptime             : Displays system uptime");
    writeln!(&mut io::stdout(), "quit               : exit the program");
}

fn interpret_input(input: &str, sys: &mut System) -> bool {
    match input.trim() {
        "help" => print_help(),
        "refresh_disks" => {
            writeln!(&mut io::stdout(), "Refreshing disk list...");
            sys.refresh_disk_list();
            writeln!(&mut io::stdout(), "Done.");
        }
        "signals" => {
            let mut nb = 1i32;

            for sig in &signals {
                writeln!(&mut io::stdout(), "{:2}:{:?}", nb, sig);
                nb += 1;
            }
        }
        "proc" => {
            // Note: you should refresh a few times before using this, so that usage statistics can be ascertained
            let procs = sys.get_processor_list();

            writeln!(&mut io::stdout(), "total process usage: {}%", procs[0].get_cpu_usage());
            for proc_ in procs.iter().skip(1) {
                writeln!(&mut io::stdout(), "{:?}", proc_);
            }
        }
        "memory" => {
            writeln!(&mut io::stdout(), "total memory: {} kB", sys.get_total_memory());
            writeln!(&mut io::stdout(), "used memory : {} kB", sys.get_used_memory());
            writeln!(&mut io::stdout(), "total swap  : {} kB", sys.get_total_swap());
            writeln!(&mut io::stdout(), "used swap   : {} kB", sys.get_used_swap());
        }
        "quit" | "exit" => return true,
        "all" => {
            for (pid, proc_) in sys.get_process_list() {
                writeln!(&mut io::stdout(), "{}:{} status={:?}", pid, proc_.name(), proc_.status());
            }
        }
        e if e.starts_with("show ") => {
            let tmp : Vec<&str> = e.split(' ').collect();

            if tmp.len() != 2 {
                writeln!(&mut io::stdout(), "show command takes a pid or a name in parameter!");
                writeln!(&mut io::stdout(), "example: show 1254");
            } else if let Ok(pid) = Pid::from_str(tmp[1]) {
                match sys.get_process(pid) {
                    Some(p) => writeln!(&mut io::stdout(), "{:?}", *p),
                    None => writeln!(&mut io::stdout(), "pid not found")
                };
            } else {
                let proc_name = tmp[1];
                for proc_ in sys.get_process_by_name(proc_name) {
                    writeln!(&mut io::stdout(), "==== {} ====", proc_.name());
                    writeln!(&mut io::stdout(), "{:?}", proc_);
                }
            }
        }
        "temperature" => {
            for component in sys.get_components_list() {
                writeln!(&mut io::stdout(), "{:?}", component);
            }
        }
        "network" => {
            writeln!(&mut io::stdout(), "input data : {} B", sys.get_network().get_income());
            writeln!(&mut io::stdout(), "output data: {} B", sys.get_network().get_outcome());
        }
        "show" => {
            writeln!(&mut io::stdout(), "'show' command expects a pid number or a process name");
        }
        e if e.starts_with("kill ") => {
            let tmp : Vec<&str> = e.split(' ').collect();

            if tmp.len() != 3 {
                writeln!(&mut io::stdout(),
                         "kill command takes the pid and a signal number in parameter !");
                writeln!(&mut io::stdout(), "example: kill 1254 9");
            } else {
                let pid = Pid::from_str(tmp[1]).unwrap();
                let signal = i32::from_str(tmp[2]).unwrap();

                if signal < 1 || signal > 31 {
                    writeln!(&mut io::stdout(),
                             "Signal must be between 0 and 32 ! See the signals list with the \
                              signals command");
                } else {
                    match sys.get_process(pid) {
                        Some(p) => {
                            writeln!(&mut io::stdout(), "kill: {}",
                                     p.kill(*signals.get(signal as usize - 1).unwrap()));
                        },
                        None => {
                            writeln!(&mut io::stdout(), "pid not found");
                        }
                    };
                }
            }
        }
        "disks" => {
            for disk in sys.get_disks() {
                writeln!(&mut io::stdout(), "{:?}", disk);
            }
        }
        "uptime" => {
            let mut uptime = sys.get_uptime();
            let days = uptime / 86400;
            uptime -= days * 86400;
            let hours = uptime / 3600;
            uptime -= hours * 3600;
            let minutes = uptime / 60;
            writeln!(&mut io::stdout(),
                     "{} days {} hours {} minutes",
                     days,
                     hours,
                     minutes);
        }
        x if x.starts_with("refresh") => {
            if x == "refresh" {
                writeln!(&mut io::stdout(), "Getting processes' information...");
                sys.refresh_all();
                writeln!(&mut io::stdout(), "Done.");
            } else if x.starts_with("refresh ") {
                writeln!(&mut io::stdout(), "Getting process' information...");
                if let Some(pid) = x.split(' ').filter_map(|pid| pid.parse().ok()).take(1).next() {
                    if sys.refresh_process(pid) {
                        writeln!(&mut io::stdout(), "Process `{}` updated successfully", pid);
                    } else {
                        writeln!(&mut io::stdout(), "Process `{}` couldn't be updated...", pid);
                    }
                } else {
                    writeln!(&mut io::stdout(), "Invalid [pid] received...");
                }
            } else {
                writeln!(&mut io::stdout(),
                     "\"{}\": Unknown command. Enter 'help' if you want to get the commands' \
                      list.", x);
            }
        }
        e => {
            writeln!(&mut io::stdout(),
                     "\"{}\": Unknown command. Enter 'help' if you want to get the commands' \
                      list.", e);
        }
    }
    false
}

fn main() {
    println!("Getting processes' information...");
    let mut t = System::new();
    println!("Done.");
    let t_stin = io::stdin();
    let mut stin = t_stin.lock();
    let mut done = false;

    println!("To get the commands' list, enter 'help'.");
    while !done {
        let mut input = String::new();
        write!(&mut io::stdout(), "> ");
        io::stdout().flush();

        stin.read_line(&mut input);
        if (&input as &str).ends_with('\n') {
            input.pop();
        }
        done = interpret_input(input.as_ref(), &mut t);
    }
}
<|endoftext|>


<commit_before>//! Rust implementation of netcode.io protocol.
//!
//! This crate contains [Server](struct.Server.html), [Client](struct.Client.html) and [ConnectToken](struct.ConnectToken.html) used to establish a netcode.io session.
//!
//! # Connect Token
//! Each netcode.io session starts with a [ConnectToken](struct.ConnectToken.html). This token is handed out by a HTTPS webserver, authentication server or other *private* avenue
//! to allow a client to establish a connection with a netcode.io based server. Rather than specifying an address the list of hosts are contained within
//! the token. Note that private keys are included in the clear so HTTPS or other secure measures for delivering the token to the client are required.
//!
//! # Server
//! The netcode.io server is created with the [UDPServer](type.UdpServer.html)::new(...) call. It accepts a local address, number of clients and private key
//! used to sign the `ConnectToken`s send to the connecting clients.
//!
//! # Client
//! The netcode.io client is created with the [UDPClient](type.UdpClient.html)::new(...) call. It accepts a connection token that has been handed out from a
//! webserver or equivalent secure connection.
//!
//! # Server Example
//! ```rust
//! use netcode::{UdpServer, ServerEvent};
//!
//! fn run_server() {
//!     const PROTOCOL_ID: u64 = 0xFFEE;
//!     const MAX_CLIENTS: usize = 32;
//!     let mut server = UdpServer::new("127.0.0.1:0",
//!                                     MAX_CLIENTS,
//!                                     PROTOCOL_ID,
//!                                     &netcode::generate_key()).unwrap();
//!
//!     loop {
//!         server.update(1.0 / 10.0);
//!         let mut packet_data = [0; netcode::NETCODE_MAX_PAYLOAD_SIZE];
//!         match server.next_event(&mut packet_data) {
//!             Ok(Some(e)) => {
//!                 match e {
//!                     ServerEvent::ClientConnect(_id) => {},
//!                     ServerEvent::ClientDisconnect(_id) => {},
//!                     ServerEvent::Packet(_id,_size) => {
//!                         //Packet from `id` of `size` length stored in `packet_data`
//!                     },
//!                     _ => {}
//!                 }
//!             },
//!             Ok(None) => {},
//!             Err(err) => Err(err).unwrap()
//!         }
//!
//!         //Tick world/gamestate/etc.
//!         //Sleep till next frame.
//!     }
//! }
//! ```
//!
//! # Client Example
//! ```rust
//! use netcode::{UdpClient, ClientEvent, ClientState, ConnectToken};
//! use std::io;
//!
//! fn run_client() {
//!     let token_data = [0; 1024]; //Note that this should come from your webserver
//!                                 //or directly from the server you're connecting to.
//!                                 //It must be sent over a secure channel because
//!                                 //it contains private keys in the clear.
//!     let token = ConnectToken::read(&mut io::Cursor::new(&token_data[..])).unwrap();
//!     let mut client = UdpClient::new(&token).unwrap();
//!     loop {
//!         client.update(1.0 / 10.0);
//!         let mut packet_data = [0; netcode::NETCODE_MAX_PAYLOAD_SIZE];
//!         match client.next_event(&mut packet_data) {
//!             Ok(Some(e)) => {
//!                 match e {
//!                     ClientEvent::NewState(state) => match state {
//!                         ClientState::Connected => {},
//!                         ClientState::Disconnected => {},
//!                         _ => {}
//!                     },
//!                     ClientEvent::Packet(_size) => {
//!                         //Packet of `size` length stored in `packet_data`
//!                     },
//!                     _ => {}
//!                 }
//!             },
//!             Ok(None) => {},
//!             Err(err) => Err(err).unwrap()
//!         }
//!
//!         //Sleep till next frame.
//!     }
//! }
//! ```
//!
//! # Token Example
//! ```
//! use netcode::{self, ConnectToken};
//! use std::io;
//!
//! const EXPIRE_SECONDS: usize = 30;
//! const PROTOCOL_ID: u64 = 0xFFEE;
//!
//! # fn get_client_id() -> u64 { 0 }
//! # fn get_next_sequence() -> u64 { 0 }
//! let private_key = netcode::generate_key(); //Note: You probably want to
//!                                            //store this some where safe.
//! let client_id = get_client_id(); //Unique u64 client id.
//! let sequence = get_next_sequence(); //sequence passed to generate() must
//!                                     //be a monotically increasing u64
//!                                     //to prevent replay attacks.
//! let user_data = None;   //Any custom user data, can be up to 256 bytes.
//!                         //Will be encrypted and returned to sever on connect.
//!
//! let token = ConnectToken::generate_with_string(["127.0.0.1:5000"].iter().cloned(),
//!                                                &private_key,
//!                                                EXPIRE_SECONDS,
//!                                                sequence,
//!                                                PROTOCOL_ID,
//!                                                client_id,
//!                                                user_data).unwrap();
//! let mut token_data = vec!();
//! token.write(&mut token_data).unwrap();
//! ```
//! ```rust
//! # use netcode::{UdpServer};
//! //Alteratively if you already have a server you can generate a token like below:
//! const PROTOCOL_ID: u64 = 0xFFEE;
//! const MAX_CLIENTS: usize = 32;
//! let mut server = UdpServer::new("127.0.0.1:0",
//!                                 MAX_CLIENTS,
//!                                 PROTOCOL_ID,
//!                                 &netcode::generate_key()).unwrap();
//!
//! const EXPIRE_SECONDS: usize = 30;
//! # fn get_client_id() -> u64 { 0 }
//! let client_id = get_client_id(); //Unique u64 client id.
//!
//! let token = server.generate_token(EXPIRE_SECONDS, client_id, None).unwrap();
//! ```

extern crate libsodium_sys;
extern crate byteorder;
#[macro_use]
extern crate log;

#[cfg(test)]
extern crate env_logger;
#[cfg(test)]
#[macro_use]
extern crate lazy_static;

#[cfg(test)]
pub mod capi;

mod common;
mod error;
mod crypto;
mod server;
mod client;
mod channel;
mod replay;
mod token;
mod packet;
mod socket;

pub use token::{ConnectToken};
pub use common::{NETCODE_MAX_PACKET_SIZE, NETCODE_MAX_PAYLOAD_SIZE, NETCODE_USER_DATA_BYTES};
pub use server::{UdpServer, Server, ServerEvent};
pub use client::{UdpClient, Client, ClientEvent, State as ClientState};
pub use crypto::{generate_key};
pub use error::*;
<commit_msg>Exposed the DecodeError so that ConnectToken decoders can handle some error cases<commit_after>//! Rust implementation of netcode.io protocol.
//!
//! This crate contains [Server](struct.Server.html), [Client](struct.Client.html) and [ConnectToken](struct.ConnectToken.html) used to establish a netcode.io session.
//!
//! # Connect Token
//! Each netcode.io session starts with a [ConnectToken](struct.ConnectToken.html). This token is handed out by a HTTPS webserver, authentication server or other *private* avenue
//! to allow a client to establish a connection with a netcode.io based server. Rather than specifying an address the list of hosts are contained within
//! the token. Note that private keys are included in the clear so HTTPS or other secure measures for delivering the token to the client are required.
//!
//! # Server
//! The netcode.io server is created with the [UDPServer](type.UdpServer.html)::new(...) call. It accepts a local address, number of clients and private key
//! used to sign the `ConnectToken`s send to the connecting clients.
//!
//! # Client
//! The netcode.io client is created with the [UDPClient](type.UdpClient.html)::new(...) call. It accepts a connection token that has been handed out from a
//! webserver or equivalent secure connection.
//!
//! # Server Example
//! ```rust
//! use netcode::{UdpServer, ServerEvent};
//!
//! fn run_server() {
//!     const PROTOCOL_ID: u64 = 0xFFEE;
//!     const MAX_CLIENTS: usize = 32;
//!     let mut server = UdpServer::new("127.0.0.1:0",
//!                                     MAX_CLIENTS,
//!                                     PROTOCOL_ID,
//!                                     &netcode::generate_key()).unwrap();
//!
//!     loop {
//!         server.update(1.0 / 10.0);
//!         let mut packet_data = [0; netcode::NETCODE_MAX_PAYLOAD_SIZE];
//!         match server.next_event(&mut packet_data) {
//!             Ok(Some(e)) => {
//!                 match e {
//!                     ServerEvent::ClientConnect(_id) => {},
//!                     ServerEvent::ClientDisconnect(_id) => {},
//!                     ServerEvent::Packet(_id,_size) => {
//!                         //Packet from `id` of `size` length stored in `packet_data`
//!                     },
//!                     _ => {}
//!                 }
//!             },
//!             Ok(None) => {},
//!             Err(err) => Err(err).unwrap()
//!         }
//!
//!         //Tick world/gamestate/etc.
//!         //Sleep till next frame.
//!     }
//! }
//! ```
//!
//! # Client Example
//! ```rust
//! use netcode::{UdpClient, ClientEvent, ClientState, ConnectToken};
//! use std::io;
//!
//! fn run_client() {
//!     let token_data = [0; 1024]; //Note that this should come from your webserver
//!                                 //or directly from the server you're connecting to.
//!                                 //It must be sent over a secure channel because
//!                                 //it contains private keys in the clear.
//!     let token = ConnectToken::read(&mut io::Cursor::new(&token_data[..])).unwrap();
//!     let mut client = UdpClient::new(&token).unwrap();
//!     loop {
//!         client.update(1.0 / 10.0);
//!         let mut packet_data = [0; netcode::NETCODE_MAX_PAYLOAD_SIZE];
//!         match client.next_event(&mut packet_data) {
//!             Ok(Some(e)) => {
//!                 match e {
//!                     ClientEvent::NewState(state) => match state {
//!                         ClientState::Connected => {},
//!                         ClientState::Disconnected => {},
//!                         _ => {}
//!                     },
//!                     ClientEvent::Packet(_size) => {
//!                         //Packet of `size` length stored in `packet_data`
//!                     },
//!                     _ => {}
//!                 }
//!             },
//!             Ok(None) => {},
//!             Err(err) => Err(err).unwrap()
//!         }
//!
//!         //Sleep till next frame.
//!     }
//! }
//! ```
//!
//! # Token Example
//! ```
//! use netcode::{self, ConnectToken};
//! use std::io;
//!
//! const EXPIRE_SECONDS: usize = 30;
//! const PROTOCOL_ID: u64 = 0xFFEE;
//!
//! # fn get_client_id() -> u64 { 0 }
//! # fn get_next_sequence() -> u64 { 0 }
//! let private_key = netcode::generate_key(); //Note: You probably want to
//!                                            //store this some where safe.
//! let client_id = get_client_id(); //Unique u64 client id.
//! let sequence = get_next_sequence(); //sequence passed to generate() must
//!                                     //be a monotically increasing u64
//!                                     //to prevent replay attacks.
//! let user_data = None;   //Any custom user data, can be up to 256 bytes.
//!                         //Will be encrypted and returned to sever on connect.
//!
//! let token = ConnectToken::generate_with_string(["127.0.0.1:5000"].iter().cloned(),
//!                                                &private_key,
//!                                                EXPIRE_SECONDS,
//!                                                sequence,
//!                                                PROTOCOL_ID,
//!                                                client_id,
//!                                                user_data).unwrap();
//! let mut token_data = vec!();
//! token.write(&mut token_data).unwrap();
//! ```
//! ```rust
//! # use netcode::{UdpServer};
//! //Alteratively if you already have a server you can generate a token like below:
//! const PROTOCOL_ID: u64 = 0xFFEE;
//! const MAX_CLIENTS: usize = 32;
//! let mut server = UdpServer::new("127.0.0.1:0",
//!                                 MAX_CLIENTS,
//!                                 PROTOCOL_ID,
//!                                 &netcode::generate_key()).unwrap();
//!
//! const EXPIRE_SECONDS: usize = 30;
//! # fn get_client_id() -> u64 { 0 }
//! let client_id = get_client_id(); //Unique u64 client id.
//!
//! let token = server.generate_token(EXPIRE_SECONDS, client_id, None).unwrap();
//! ```

extern crate libsodium_sys;
extern crate byteorder;
#[macro_use]
extern crate log;

#[cfg(test)]
extern crate env_logger;
#[cfg(test)]
#[macro_use]
extern crate lazy_static;

#[cfg(test)]
pub mod capi;

mod common;
mod error;
mod crypto;
mod server;
mod client;
mod channel;
mod replay;
mod token;
mod packet;
mod socket;

pub use token::{ConnectToken, DecodeError};
pub use common::{NETCODE_MAX_PACKET_SIZE, NETCODE_MAX_PAYLOAD_SIZE, NETCODE_USER_DATA_BYTES};
pub use server::{UdpServer, Server, ServerEvent};
pub use client::{UdpClient, Client, ClientEvent, State as ClientState};
pub use crypto::{generate_key};
pub use error::*;
<|endoftext|>


<commit_before>//! Contains x86-specific types

pub use arch::arch_builder::x86::*;
use arch::DetailsArchInsn;
use capstone_sys::{x86_op_mem, x86_op_type, cs_x86, cs_x86_op};
use instruction::{RegId, RegIdInt};
use std::convert::From;
use std::{cmp, fmt, slice};

pub use capstone_sys::x86_insn_group as X86InsnGroup;
pub use capstone_sys::x86_insn as X86Insn;
pub use capstone_sys::x86_reg as X86Reg;

pub use capstone_sys::x86_avx_bcast as X86AvxBcast;
pub use capstone_sys::x86_sse_cc as X86SseCC;
pub use capstone_sys::x86_avx_cc as X86AvxCC;
pub use capstone_sys::x86_avx_rm as X86AvxRm;

use capstone_sys::cs_x86_op__bindgen_ty_1;

/// Contains X86-specific details for an instruction
pub struct X86InsnDetail<'a>(pub(crate) &'a cs_x86);

// todo(tmfink): expose new types cs_x86__bindgen_ty_1, cs_x86_encoding, x86_xop_cc,
// cs_x86_op::access

impl X86OperandType {
    fn new(op_type: x86_op_type, value: cs_x86_op__bindgen_ty_1) -> X86OperandType {
        use self::x86_op_type::*;
        use self::X86OperandType::*;

        match op_type {
            X86_OP_REG => Reg(RegId(unsafe { value.reg } as RegIdInt)),
            X86_OP_IMM => Imm(unsafe { value.imm }),
            X86_OP_MEM => Mem(X86OpMem(unsafe { value.mem })),
            X86_OP_INVALID => Invalid,
        }
    }
}

/// X86 operand
#[derive(Clone, Debug, PartialEq)]
pub struct X86Operand {
    /// Operand size
    pub size: u8,

    /// AVX broadcast
    pub avx_bcast: X86AvxBcast,

    /// AVX zero opmask
    pub avx_zero_opmask: bool,

    /// Operand type
    pub op_type: X86OperandType,
}

/// X86 operand
#[derive(Clone, Debug, PartialEq)]
pub enum X86OperandType {
    /// Register
    Reg(RegId),

    /// Immediate
    Imm(i64),

    /// Memory
    Mem(X86OpMem),

    /// Invalid
    Invalid,
}

/// X86 memory operand
#[derive(Debug, Copy, Clone)]
pub struct X86OpMem(pub(crate) x86_op_mem);

impl<'a> X86InsnDetail<'a> {
    /// Instruction prefix bytes
    pub fn prefix(&self) -> &[u8; 4] {
        &self.0.prefix
    }

    /// Opcode bytes
    pub fn opcode(&self) -> &[u8; 4] {
        &self.0.opcode
    }

    /// REX
    pub fn rex(&self) -> u8 {
        self.0.rex
    }

    /// Address size
    pub fn addr_size(&self) -> u8 {
        self.0.addr_size
    }

    /// MODRM
    pub fn modrm(&self) -> u8 {
        self.0.modrm
    }

    /// SIB (Scaled Index Byte)
    pub fn sib(&self) -> u8 {
        self.0.sib
    }

    /// Disp
    pub fn disp(&self) -> i64 {
        self.0.disp
    }

    /// Scaled Index Byte (SIB) index
    pub fn sib_index(&self) -> RegId {
        RegId(self.0.sib_index as RegIdInt)
    }

    /// Scaled Index Byte (SIB) scale
    pub fn sib_scale(&self) -> i8 {
        self.0.sib_scale
    }

    /// Scaled Index Byte (SIB) scale
    pub fn sib_base(&self) -> RegId {
        RegId(self.0.sib_base as RegIdInt)
    }

    /// Streaming SIMD Extensions (SSE) condition  codes
    pub fn sse_cc(&self) -> X86SseCC {
        self.0.sse_cc
    }

    /// Advanced Vector Extensions (AVX) condition  codes
    pub fn avx_cc(&self) -> X86AvxCC {
        self.0.avx_cc
    }

    /// Advanced Vector Extensions (AVX) sae
    pub fn avx_sae(&self) -> bool {
        self.0.avx_sae
    }

    /// Advanced Vector Extensions (AVX) rm
    pub fn avx_rm(&self) -> X86AvxRm {
        self.0.avx_rm
    }
}

impl_PartialEq_repr_fields!(X86InsnDetail<'a> [ 'a ];
    prefix, opcode, rex, addr_size, modrm, sib, disp, sib_index, sib_scale, sib_base, sse_cc,
    avx_cc, avx_sae, avx_rm, operands
);

impl X86OpMem {
    /// Segment
    pub fn segment(&self) -> u32 {
        self.0.segment as u32
    }

    /// Base register
    pub fn base(&self) -> RegId {
        RegId(self.0.base as RegIdInt)
    }

    /// Index register
    pub fn index(&self) -> RegId {
        RegId(self.0.index as RegIdInt)
    }

    /// Scale
    pub fn scale(&self) -> i32 {
        self.0.scale as i32
    }

    /// Display
    pub fn disp(&self) -> i64 {
        self.0.disp
    }
}

impl_PartialEq_repr_fields!(X86OpMem;
    segment, base, index, scale, disp
);

impl cmp::Eq for X86OpMem {}

impl Default for X86Operand {
    fn default() -> Self {
        X86Operand {
            size: 0,
            avx_bcast: X86AvxBcast::X86_AVX_BCAST_INVALID,
            avx_zero_opmask: false,
            op_type: X86OperandType::Invalid
        }
    }
}

impl<'a> From<&'a cs_x86_op> for X86Operand {
    fn from(op: &cs_x86_op) -> X86Operand {
        let op_type = X86OperandType::new(op.type_, op.__bindgen_anon_1);
        X86Operand {
            size: op.size,
            avx_bcast: op.avx_bcast,
            avx_zero_opmask: op.avx_zero_opmask,
            op_type,
        }
    }
}

def_arch_details_struct!(
    InsnDetail = X86InsnDetail;
    Operand = X86Operand;
    OperandIterator = X86OperandIterator;
    OperandIteratorLife = X86OperandIterator<'a>;
    [ pub struct X86OperandIterator<'a>(slice::Iter<'a, cs_x86_op>); ]
    cs_arch_op = cs_x86_op;
    cs_arch = cs_x86;
);

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

    #[test]
    fn test_x86_op_type() {
        use super::x86_op_type::*;
        use super::X86OperandType::*;

        fn t(
            op_type_value: (x86_op_type, cs_x86_op__bindgen_ty_1),
            expected_op_type: X86OperandType,
        ) {
            let (op_type, op_value) = op_type_value;
            let op_type = X86OperandType::new(op_type, op_value);
            assert_eq!(expected_op_type, op_type);
        }

        t(
            (X86_OP_INVALID, cs_x86_op__bindgen_ty_1 { reg: 0 }),
            Invalid,
        );
        t(
            (X86_OP_REG, cs_x86_op__bindgen_ty_1 { reg: 0 }),
            Reg(RegId(0)),
        );
    }

    #[test]
    fn test_x86_op_eq() {
        let a1 = X86Operand {
            op_type: X86OperandType::Imm(0),
            ..Default::default()
        };
        let a2 = X86Operand {
            op_type: X86OperandType::Imm(-100),
            ..Default::default()
        };

        assert_eq!(a1, a1.clone());
        assert_ne!(a1, a2.clone());
    }

    #[test]
    fn test_x86_insn_eq() {
        fn t_eq(a: &cs_x86, b: &cs_x86) {
            assert_eq!(X86InsnDetail(a), X86InsnDetail(b))
        }
        fn t_ne(a: &cs_x86, b: &cs_x86) {
            assert_ne!(X86InsnDetail(a), X86InsnDetail(b))
        }

        let a1 = cs_x86 {
            prefix: [0, 0, 0, 0],
            opcode: [0, 0, 0, 0],
            rex: 0,
            addr_size: 0,
            modrm: 0,
            sib: 0,
            disp: 0,
            sib_index: x86_reg::X86_REG_INVALID,
            sib_scale: 0,
            sib_base: x86_reg::X86_REG_INVALID,
            sse_cc: x86_sse_cc::X86_SSE_CC_INVALID,
            avx_cc: x86_avx_cc::X86_AVX_CC_INVALID,
            avx_sae: false,
            avx_rm: x86_avx_rm::X86_AVX_RM_INVALID,
            op_count: 0,
            __bindgen_anon_1: cs_x86__bindgen_ty_1 {
                eflags: 0,
            },
            encoding: cs_x86_encoding {
                modrm_offset: 0,
                disp_offset: 0,
                disp_size: 0,
                imm_offset: 0,
                imm_size: 0,
            },
            xop_cc: x86_xop_cc::X86_XOP_CC_INVALID,
            operands: [ cs_x86_op {
                type_: x86_op_type::X86_OP_INVALID,
                __bindgen_anon_1: cs_x86_op__bindgen_ty_1 { reg: x86_reg::X86_REG_INVALID },
                size: 0,
                avx_bcast: x86_avx_bcast::X86_AVX_BCAST_INVALID,
                avx_zero_opmask: false,
                access: 0,
            }
            ; 8],

        };
        let mut a2 = a1.clone();
        a2.operands[1].type_ = x86_op_type::X86_OP_REG;
        let a1_clone = cs_x86 {
            ..a1
        };
        let a3 = cs_x86 {
            rex: 1,
            ..a1
        };
        let op_count_differ = cs_x86 {
            op_count: 1,
            ..a1
        };
        let mut op1_differ = op_count_differ.clone();
        op1_differ.operands[0].avx_bcast = x86_avx_bcast::X86_AVX_BCAST_2;

        t_eq(&a1, &a1);
        t_eq(&a1, &a2);
        t_eq(&a1, &a1_clone);
        t_ne(&a1, &a3);
        t_ne(&a1, &op_count_differ);
        t_ne(&op_count_differ, &op1_differ);
    }
}
<commit_msg>x86: add xop_cc, export X86Prefix, update doc<commit_after>//! Contains x86-specific types

pub use arch::arch_builder::x86::*;
use arch::DetailsArchInsn;
use capstone_sys::{x86_op_mem, x86_op_type, cs_x86, cs_x86_op};
use instruction::{RegId, RegIdInt};
use std::convert::From;
use std::{cmp, fmt, slice};

pub use capstone_sys::x86_insn_group as X86InsnGroup;
pub use capstone_sys::x86_insn as X86Insn;
pub use capstone_sys::x86_reg as X86Reg;
pub use capstone_sys::x86_prefix as X86Prefix;

pub use capstone_sys::x86_avx_bcast as X86AvxBcast;
pub use capstone_sys::x86_sse_cc as X86SseCC;
pub use capstone_sys::x86_avx_cc as X86AvxCC;
pub use capstone_sys::x86_xop_cc as X86XopCC;
pub use capstone_sys::x86_avx_rm as X86AvxRm;

use capstone_sys::cs_x86_op__bindgen_ty_1;

/// Contains X86-specific details for an instruction
pub struct X86InsnDetail<'a>(pub(crate) &'a cs_x86);

// todo(tmfink): expose new types cs_x86__bindgen_ty_1, cs_x86_encoding, x86_xop_cc,
// cs_x86_op::access

impl X86OperandType {
    fn new(op_type: x86_op_type, value: cs_x86_op__bindgen_ty_1) -> X86OperandType {
        use self::x86_op_type::*;
        use self::X86OperandType::*;

        match op_type {
            X86_OP_REG => Reg(RegId(unsafe { value.reg } as RegIdInt)),
            X86_OP_IMM => Imm(unsafe { value.imm }),
            X86_OP_MEM => Mem(X86OpMem(unsafe { value.mem })),
            X86_OP_INVALID => Invalid,
        }
    }
}

/// X86 operand
#[derive(Clone, Debug, PartialEq)]
pub struct X86Operand {
    /// Operand size
    pub size: u8,

    /// AVX broadcast
    pub avx_bcast: X86AvxBcast,

    /// AVX zero opmask
    pub avx_zero_opmask: bool,

    /// Operand type
    pub op_type: X86OperandType,
}

/// X86 operand
#[derive(Clone, Debug, PartialEq)]
pub enum X86OperandType {
    /// Register
    Reg(RegId),

    /// Immediate
    Imm(i64),

    /// Memory
    Mem(X86OpMem),

    /// Invalid
    Invalid,
}

/// X86 memory operand
#[derive(Debug, Copy, Clone)]
pub struct X86OpMem(pub(crate) x86_op_mem);

impl<'a> X86InsnDetail<'a> {
    /// Instruction prefix, which can be up to 4 bytes.
    /// A prefix byte gets value 0 when irrelevant.
    /// See `X86Prefix` for details.
    ///
    /// prefix[0] indicates REP/REPNE/LOCK prefix (See `X86_PREFIX_REP`/`REPNE`/`LOCK`)
    ///
    /// prefix[1] indicates segment override (irrelevant for x86_64):
    /// See `X86_PREFIX_CS`/`SS`/`DS`/`ES`/`FS`/`GS`.
    ///
    /// prefix[2] indicates operand-size override (`X86_PREFIX_OPSIZE`)
    ///
    /// prefix[3] indicates address-size override (`X86_PREFIX_ADDRSIZE`)
    pub fn prefix(&self) -> &[u8; 4] {
        &self.0.prefix
    }

    /// Instruction opcode, which can be from 1 to 4 bytes in size.
    /// This contains VEX opcode as well.
    /// A trailing opcode byte gets value 0 when irrelevant.
    pub fn opcode(&self) -> &[u8; 4] {
        &self.0.opcode
    }

    /// REX prefix: only a non-zero value is relevant for x86_64
    pub fn rex(&self) -> u8 {
        self.0.rex
    }

    /// Address size
    pub fn addr_size(&self) -> u8 {
        self.0.addr_size
    }

    /// ModR/M byte
    pub fn modrm(&self) -> u8 {
        self.0.modrm
    }

    /// SIB (Scaled Index Byte) value, or 0 when irrelevant
    pub fn sib(&self) -> u8 {
        self.0.sib
    }

    /// Displacement value, valid if encoding.disp_offset != 0
    pub fn disp(&self) -> i64 {
        self.0.disp
    }

    /// Scaled Index Byte (SIB) index, or X86_REG_INVALID when irrelevant
    pub fn sib_index(&self) -> RegId {
        RegId(self.0.sib_index as RegIdInt)
    }

    /// Scaled Index Byte (SIB) scale, or X86_REG_INVALID when irrelevant
    pub fn sib_scale(&self) -> i8 {
        self.0.sib_scale
    }

    /// Scaled Index Byte (SIB) base register, or X86_REG_INVALID when irrelevant
    pub fn sib_base(&self) -> RegId {
        RegId(self.0.sib_base as RegIdInt)
    }

    /// eXtended Operations (XOP) Code Condition
    pub fn xop_cc(&self) -> X86XopCC {
        self.0.xop_cc
    }

    /// Streaming SIMD Extensions (SSE) condition  codes
    pub fn sse_cc(&self) -> X86SseCC {
        self.0.sse_cc
    }

    /// Advanced Vector Extensions (AVX) condition  codes
    pub fn avx_cc(&self) -> X86AvxCC {
        self.0.avx_cc
    }

    /// Advanced Vector Extensions (AVX) sae
    pub fn avx_sae(&self) -> bool {
        self.0.avx_sae
    }

    /// Advanced Vector Extensions (AVX) rm
    pub fn avx_rm(&self) -> X86AvxRm {
        self.0.avx_rm
    }
}

impl_PartialEq_repr_fields!(X86InsnDetail<'a> [ 'a ];
    prefix, opcode, rex, addr_size, modrm, sib, disp, sib_index, sib_scale, sib_base, sse_cc,
    avx_cc, avx_sae, avx_rm, operands
);

impl X86OpMem {
    /// Segment
    pub fn segment(&self) -> u32 {
        self.0.segment as u32
    }

    /// Base register
    pub fn base(&self) -> RegId {
        RegId(self.0.base as RegIdInt)
    }

    /// Index register
    pub fn index(&self) -> RegId {
        RegId(self.0.index as RegIdInt)
    }

    /// Scale
    pub fn scale(&self) -> i32 {
        self.0.scale as i32
    }

    /// Display
    pub fn disp(&self) -> i64 {
        self.0.disp
    }
}

impl_PartialEq_repr_fields!(X86OpMem;
    segment, base, index, scale, disp
);

impl cmp::Eq for X86OpMem {}

impl Default for X86Operand {
    fn default() -> Self {
        X86Operand {
            size: 0,
            avx_bcast: X86AvxBcast::X86_AVX_BCAST_INVALID,
            avx_zero_opmask: false,
            op_type: X86OperandType::Invalid
        }
    }
}

impl<'a> From<&'a cs_x86_op> for X86Operand {
    fn from(op: &cs_x86_op) -> X86Operand {
        let op_type = X86OperandType::new(op.type_, op.__bindgen_anon_1);
        X86Operand {
            size: op.size,
            avx_bcast: op.avx_bcast,
            avx_zero_opmask: op.avx_zero_opmask,
            op_type,
        }
    }
}

def_arch_details_struct!(
    InsnDetail = X86InsnDetail;
    Operand = X86Operand;
    OperandIterator = X86OperandIterator;
    OperandIteratorLife = X86OperandIterator<'a>;
    [ pub struct X86OperandIterator<'a>(slice::Iter<'a, cs_x86_op>); ]
    cs_arch_op = cs_x86_op;
    cs_arch = cs_x86;
);

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

    #[test]
    fn test_x86_op_type() {
        use super::x86_op_type::*;
        use super::X86OperandType::*;

        fn t(
            op_type_value: (x86_op_type, cs_x86_op__bindgen_ty_1),
            expected_op_type: X86OperandType,
        ) {
            let (op_type, op_value) = op_type_value;
            let op_type = X86OperandType::new(op_type, op_value);
            assert_eq!(expected_op_type, op_type);
        }

        t(
            (X86_OP_INVALID, cs_x86_op__bindgen_ty_1 { reg: 0 }),
            Invalid,
        );
        t(
            (X86_OP_REG, cs_x86_op__bindgen_ty_1 { reg: 0 }),
            Reg(RegId(0)),
        );
    }

    #[test]
    fn test_x86_op_eq() {
        let a1 = X86Operand {
            op_type: X86OperandType::Imm(0),
            ..Default::default()
        };
        let a2 = X86Operand {
            op_type: X86OperandType::Imm(-100),
            ..Default::default()
        };

        assert_eq!(a1, a1.clone());
        assert_ne!(a1, a2.clone());
    }

    #[test]
    fn test_x86_insn_eq() {
        fn t_eq(a: &cs_x86, b: &cs_x86) {
            assert_eq!(X86InsnDetail(a), X86InsnDetail(b))
        }
        fn t_ne(a: &cs_x86, b: &cs_x86) {
            assert_ne!(X86InsnDetail(a), X86InsnDetail(b))
        }

        let a1 = cs_x86 {
            prefix: [0, 0, 0, 0],
            opcode: [0, 0, 0, 0],
            rex: 0,
            addr_size: 0,
            modrm: 0,
            sib: 0,
            disp: 0,
            sib_index: x86_reg::X86_REG_INVALID,
            sib_scale: 0,
            sib_base: x86_reg::X86_REG_INVALID,
            sse_cc: x86_sse_cc::X86_SSE_CC_INVALID,
            avx_cc: x86_avx_cc::X86_AVX_CC_INVALID,
            avx_sae: false,
            avx_rm: x86_avx_rm::X86_AVX_RM_INVALID,
            op_count: 0,
            __bindgen_anon_1: cs_x86__bindgen_ty_1 {
                eflags: 0,
            },
            encoding: cs_x86_encoding {
                modrm_offset: 0,
                disp_offset: 0,
                disp_size: 0,
                imm_offset: 0,
                imm_size: 0,
            },
            xop_cc: x86_xop_cc::X86_XOP_CC_INVALID,
            operands: [ cs_x86_op {
                type_: x86_op_type::X86_OP_INVALID,
                __bindgen_anon_1: cs_x86_op__bindgen_ty_1 { reg: x86_reg::X86_REG_INVALID },
                size: 0,
                avx_bcast: x86_avx_bcast::X86_AVX_BCAST_INVALID,
                avx_zero_opmask: false,
                access: 0,
            }
            ; 8],

        };
        let mut a2 = a1.clone();
        a2.operands[1].type_ = x86_op_type::X86_OP_REG;
        let a1_clone = cs_x86 {
            ..a1
        };
        let a3 = cs_x86 {
            rex: 1,
            ..a1
        };
        let op_count_differ = cs_x86 {
            op_count: 1,
            ..a1
        };
        let mut op1_differ = op_count_differ.clone();
        op1_differ.operands[0].avx_bcast = x86_avx_bcast::X86_AVX_BCAST_2;

        t_eq(&a1, &a1);
        t_eq(&a1, &a2);
        t_eq(&a1, &a1_clone);
        t_ne(&a1, &a3);
        t_ne(&a1, &op_count_differ);
        t_ne(&op_count_differ, &op1_differ);
    }
}
<|endoftext|>