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

//! This module contains the code to instantiate a "query result", and
//! in particular to extract out the resulting region obligations and
//! encode them therein.
//!
//! For an overview of what canonicaliation is and how it fits into
//! rustc, check out the [chapter in the rustc guide][c].
//!
//! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html

use infer::canonical::substitute::substitute_value;
use infer::canonical::{
    Canonical, CanonicalVarValues, Canonicalize, CanonicalizedQueryResult, Certainty,
    QueryRegionConstraint, QueryResult,
};
use infer::region_constraints::{Constraint, RegionConstraintData};
use infer::{InferCtxt, InferOk, InferResult, RegionObligation};
use rustc_data_structures::indexed_vec::Idx;
use rustc_data_structures::indexed_vec::IndexVec;
use std::fmt::Debug;
use syntax::ast;
use traits::query::NoSolution;
use traits::{FulfillmentContext, TraitEngine};
use traits::{Obligation, ObligationCause, PredicateObligation};
use ty::fold::TypeFoldable;
use ty::subst::{Kind, UnpackedKind};
use ty::{self, CanonicalVar, Lift, TyCtxt};

impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
    /// This method is meant to be invoked as the final step of a canonical query
    /// implementation. It is given:
    ///
    /// - the instantiated variables `inference_vars` created from the query key
    /// - the result `answer` of the query
    /// - a fulfillment context `fulfill_cx` that may contain various obligations which
    ///   have yet to be proven.
    ///
    /// Given this, the function will process the obligations pending
    /// in `fulfill_cx`:
    ///
    /// - If all the obligations can be proven successfully, it will
    ///   package up any resulting region obligations (extracted from
    ///   `infcx`) along with the fully resolved value `answer` into a
    ///   query result (which is then itself canonicalized).
    /// - If some obligations can be neither proven nor disproven, then
    ///   the same thing happens, but the resulting query is marked as ambiguous.
    /// - Finally, if any of the obligations result in a hard error,
    ///   then `Err(NoSolution)` is returned.
    pub fn make_canonicalized_query_result<T>(
        &self,
        inference_vars: CanonicalVarValues<'tcx>,
        answer: T,
        fulfill_cx: &mut FulfillmentContext<'tcx>,
    ) -> Result<CanonicalizedQueryResult<'gcx, T>, NoSolution>
    where
        T: Debug + Lift<'gcx> + TypeFoldable<'tcx>,
    {
        let query_result = self.make_query_result(inference_vars, answer, fulfill_cx)?;
        let (canonical_result, _) = self.canonicalize_response(&query_result);

        debug!(
            "make_canonicalized_query_result: canonical_result = {:#?}",
            canonical_result
        );

        Ok(canonical_result)
    }

    /// Helper for `make_canonicalized_query_result` that does
    /// everything up until the final canonicalization.
    fn make_query_result<T>(
        &self,
        inference_vars: CanonicalVarValues<'tcx>,
        answer: T,
        fulfill_cx: &mut FulfillmentContext<'tcx>,
    ) -> Result<QueryResult<'tcx, T>, NoSolution>
    where
        T: Debug,
        QueryResult<'tcx, T>: Canonicalize<'gcx, 'tcx>,
    {
        let tcx = self.tcx;

        debug!(
            "make_query_result(\
             inference_vars={:?}, \
             answer={:?})",
            inference_vars, answer,
        );

        // Select everything, returning errors.
        let true_errors = match fulfill_cx.select_where_possible(self) {
            Ok(()) => vec![],
            Err(errors) => errors,
        };
        debug!("true_errors = {:#?}", true_errors);

        if !true_errors.is_empty() {
            // FIXME -- we don't indicate *why* we failed to solve
            debug!("make_query_result: true_errors={:#?}", true_errors);
            return Err(NoSolution);
        }

        // Anything left unselected *now* must be an ambiguity.
        let ambig_errors = match fulfill_cx.select_all_or_error(self) {
            Ok(()) => vec![],
            Err(errors) => errors,
        };
        debug!("ambig_errors = {:#?}", ambig_errors);

        let region_obligations = self.take_registered_region_obligations();
        let region_constraints = self.with_region_constraints(|region_constraints| {
            make_query_outlives(tcx, region_obligations, region_constraints)
        });

        let certainty = if ambig_errors.is_empty() {
            Certainty::Proven
        } else {
            Certainty::Ambiguous
        };

        Ok(QueryResult {
            var_values: inference_vars,
            region_constraints,
            certainty,
            value: answer,
        })
    }

    /// Given the (canonicalized) result to a canonical query,
    /// instantiates the result so it can be used, plugging in the
    /// values from the canonical query. (Note that the result may
    /// have been ambiguous; you should check the certainty level of
    /// the query before applying this function.)
    ///
    /// To get a good understanding of what is happening here, check
    /// out the [chapter in the rustc guide][c].
    ///
    /// [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html#processing-the-canonicalized-query-result
    pub fn instantiate_query_result_and_region_obligations<R>(
        &self,
        cause: &ObligationCause<'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        original_values: &CanonicalVarValues<'tcx>,
        query_result: &Canonical<'tcx, QueryResult<'tcx, R>>,
    ) -> InferResult<'tcx, R>
    where
        R: Debug + TypeFoldable<'tcx>,
    {
        debug!(
            "instantiate_query_result(original_values={:#?}, query_result={:#?})",
            original_values, query_result,
        );

        // Every canonical query result includes values for each of
        // the inputs to the query. Therefore, we begin by unifying
        // these values with the original inputs that were
        // canonicalized.
        let result_values = &query_result.value.var_values;
        assert_eq!(original_values.len(), result_values.len());

        // Quickly try to find initial values for the canonical
        // variables in the result in terms of the query. We do this
        // by iterating down the values that the query gave to each of
        // the canonical inputs. If we find that one of those values
        // is directly equal to one of the canonical variables in the
        // result, then we can type the corresponding value from the
        // input. See the example above.
        let mut opt_values: IndexVec<CanonicalVar, Option<Kind<'tcx>>> =
            IndexVec::from_elem_n(None, query_result.variables.len());

        // In terms of our example above, we are iterating over pairs like:
        // [(?A, Vec<?0>), ('static, '?1), (?B, ?0)]
        for (original_value, result_value) in original_values.iter().zip(result_values) {
            match result_value.unpack() {
                UnpackedKind::Type(result_value) => {
                    // e.g., here `result_value` might be `?0` in the example above...
                    if let ty::TyInfer(ty::InferTy::CanonicalTy(index)) = result_value.sty {
                        // in which case we would set `canonical_vars[0]` to `Some(?U)`.
                        opt_values[index] = Some(original_value);
                    }
                }
                UnpackedKind::Lifetime(result_value) => {
                    // e.g., here `result_value` might be `'?1` in the example above...
                    if let &ty::RegionKind::ReCanonical(index) = result_value {
                        // in which case we would set `canonical_vars[0]` to `Some('static)`.
                        opt_values[index] = Some(original_value);
                    }
                }
            }
        }

        // Create a result substitution: if we found a value for a
        // given variable in the loop above, use that. Otherwise, use
        // a fresh inference variable.
        let result_subst = &CanonicalVarValues {
            var_values: query_result
                .variables
                .iter()
                .enumerate()
                .map(|(index, info)| match opt_values[CanonicalVar::new(index)] {
                    Some(k) => k,
                    None => self.fresh_inference_var_for_canonical_var(cause.span, *info),
                })
                .collect(),
        };

        // Unify the original values for the canonical variables in
        // the input with the value found in the query
        // post-substitution. Often, but not always, this is a no-op,
        // because we already found the mapping in the first step.
        let substituted_values = |index: CanonicalVar| -> Kind<'tcx> {
            query_result.substitute_projected(self.tcx, result_subst, |v| &v.var_values[index])
        };
        let mut obligations = self
            .unify_canonical_vars(cause, param_env, original_values, substituted_values)?
            .into_obligations();

        obligations.extend(self.query_region_constraints_into_obligations(
            cause,
            param_env,
            &query_result.value.region_constraints,
            result_subst,
        ));

        let user_result: R =
            query_result.substitute_projected(self.tcx, result_subst, |q_r| &q_r.value);

        Ok(InferOk {
            value: user_result,
            obligations,
        })
    }

    /// Converts the region constraints resulting from a query into an
    /// iterator of obligations.
    fn query_region_constraints_into_obligations<'a>(
        &'a self,
        cause: &'a ObligationCause<'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        unsubstituted_region_constraints: &'a [QueryRegionConstraint<'tcx>],
        result_subst: &'a CanonicalVarValues<'tcx>,
    ) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a {
        Box::new(
            unsubstituted_region_constraints
                .iter()
                .map(move |constraint| {
                    let ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below
                    let k1 = substitute_value(self.tcx, result_subst, k1);
                    let r2 = substitute_value(self.tcx, result_subst, r2);
                    match k1.unpack() {
                        UnpackedKind::Lifetime(r1) => Obligation::new(
                            cause.clone(),
                            param_env,
                            ty::Predicate::RegionOutlives(ty::Binder::dummy(
                                ty::OutlivesPredicate(r1, r2),
                            )),
                        ),

                        UnpackedKind::Type(t1) => Obligation::new(
                            cause.clone(),
                            param_env,
                            ty::Predicate::TypeOutlives(ty::Binder::dummy(ty::OutlivesPredicate(
                                t1, r2,
                            ))),
                        ),
                    }
                }),
        ) as Box<dyn Iterator<Item = _>>
    }

    /// Given two sets of values for the same set of canonical variables, unify them.
    /// The second set is produced lazilly by supplying indices from the first set.
    fn unify_canonical_vars(
        &self,
        cause: &ObligationCause<'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        variables1: &CanonicalVarValues<'tcx>,
        variables2: impl Fn(CanonicalVar) -> Kind<'tcx>,
    ) -> InferResult<'tcx, ()> {
        self.commit_if_ok(|_| {
            let mut obligations = vec![];
            for (index, value1) in variables1.var_values.iter_enumerated() {
                let value2 = variables2(index);

                match (value1.unpack(), value2.unpack()) {
                    (UnpackedKind::Type(v1), UnpackedKind::Type(v2)) => {
                        obligations
                            .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations());
                    }
                    (
                        UnpackedKind::Lifetime(ty::ReErased),
                        UnpackedKind::Lifetime(ty::ReErased),
                    ) => {
                        // no action needed
                    }
                    (UnpackedKind::Lifetime(v1), UnpackedKind::Lifetime(v2)) => {
                        obligations
                            .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations());
                    }
                    _ => {
                        bug!("kind mismatch, cannot unify {:?} and {:?}", value1, value2,);
                    }
                }
            }
            Ok(InferOk {
                value: (),
                obligations,
            })
        })
    }
}

/// Given the region obligations and constraints scraped from the infcx,
/// creates query region constraints.
pub fn make_query_outlives<'tcx>(
    tcx: TyCtxt<'_, '_, 'tcx>,
    region_obligations: Vec<(ast::NodeId, RegionObligation<'tcx>)>,
    region_constraints: &RegionConstraintData<'tcx>,
) -> Vec<QueryRegionConstraint<'tcx>> {
    let RegionConstraintData {
        constraints,
        verifys,
        givens,
    } = region_constraints;

    assert!(verifys.is_empty());
    assert!(givens.is_empty());

    let mut outlives: Vec<_> = constraints
            .into_iter()
            .map(|(k, _)| match *k {
                // Swap regions because we are going from sub (<=) to outlives
                // (>=).
                Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
                    tcx.mk_region(ty::ReVar(v2)).into(),
                    tcx.mk_region(ty::ReVar(v1)),
                ),
                Constraint::VarSubReg(v1, r2) => {
                    ty::OutlivesPredicate(r2.into(), tcx.mk_region(ty::ReVar(v1)))
                }
                Constraint::RegSubVar(r1, v2) => {
                    ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1)
                }
                Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1),
            })
            .map(ty::Binder::dummy) // no bound regions in the code above
            .collect();

    outlives.extend(
        region_obligations
            .into_iter()
            .map(|(_, r_o)| ty::OutlivesPredicate(r_o.sup_type.into(), r_o.sub_region))
            .map(ty::Binder::dummy), // no bound regions in the code above
    );

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

//! This module contains the code to instantiate a "query result", and
//! in particular to extract out the resulting region obligations and
//! encode them therein.
//!
//! For an overview of what canonicaliation is and how it fits into
//! rustc, check out the [chapter in the rustc guide][c].
//!
//! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html

use infer::canonical::substitute::substitute_value;
use infer::canonical::{
    Canonical, CanonicalVarValues, Canonicalize, CanonicalizedQueryResult, Certainty,
    QueryRegionConstraint, QueryResult,
};
use infer::region_constraints::{Constraint, RegionConstraintData};
use infer::{InferCtxt, InferOk, InferResult, RegionObligation};
use rustc_data_structures::indexed_vec::Idx;
use rustc_data_structures::indexed_vec::IndexVec;
use std::fmt::Debug;
use syntax::ast;
use traits::query::NoSolution;
use traits::{FulfillmentContext, TraitEngine};
use traits::{Obligation, ObligationCause, PredicateObligation};
use ty::fold::TypeFoldable;
use ty::subst::{Kind, UnpackedKind};
use ty::{self, CanonicalVar, Lift, TyCtxt};

impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
    /// This method is meant to be invoked as the final step of a canonical query
    /// implementation. It is given:
    ///
    /// - the instantiated variables `inference_vars` created from the query key
    /// - the result `answer` of the query
    /// - a fulfillment context `fulfill_cx` that may contain various obligations which
    ///   have yet to be proven.
    ///
    /// Given this, the function will process the obligations pending
    /// in `fulfill_cx`:
    ///
    /// - If all the obligations can be proven successfully, it will
    ///   package up any resulting region obligations (extracted from
    ///   `infcx`) along with the fully resolved value `answer` into a
    ///   query result (which is then itself canonicalized).
    /// - If some obligations can be neither proven nor disproven, then
    ///   the same thing happens, but the resulting query is marked as ambiguous.
    /// - Finally, if any of the obligations result in a hard error,
    ///   then `Err(NoSolution)` is returned.
    pub fn make_canonicalized_query_result<T>(
        &self,
        inference_vars: CanonicalVarValues<'tcx>,
        answer: T,
        fulfill_cx: &mut FulfillmentContext<'tcx>,
    ) -> Result<CanonicalizedQueryResult<'gcx, T>, NoSolution>
    where
        T: Debug + Lift<'gcx> + TypeFoldable<'tcx>,
    {
        let query_result = self.make_query_result(inference_vars, answer, fulfill_cx)?;
        let (canonical_result, _) = self.canonicalize_response(&query_result);

        debug!(
            "make_canonicalized_query_result: canonical_result = {:#?}",
            canonical_result
        );

        Ok(canonical_result)
    }

    /// Helper for `make_canonicalized_query_result` that does
    /// everything up until the final canonicalization.
    fn make_query_result<T>(
        &self,
        inference_vars: CanonicalVarValues<'tcx>,
        answer: T,
        fulfill_cx: &mut FulfillmentContext<'tcx>,
    ) -> Result<QueryResult<'tcx, T>, NoSolution>
    where
        T: Debug,
        QueryResult<'tcx, T>: Canonicalize<'gcx, 'tcx>,
    {
        let tcx = self.tcx;

        debug!(
            "make_query_result(\
             inference_vars={:?}, \
             answer={:?})",
            inference_vars, answer,
        );

        // Select everything, returning errors.
        let true_errors = match fulfill_cx.select_where_possible(self) {
            Ok(()) => vec![],
            Err(errors) => errors,
        };
        debug!("true_errors = {:#?}", true_errors);

        if !true_errors.is_empty() {
            // FIXME -- we don't indicate *why* we failed to solve
            debug!("make_query_result: true_errors={:#?}", true_errors);
            return Err(NoSolution);
        }

        // Anything left unselected *now* must be an ambiguity.
        let ambig_errors = match fulfill_cx.select_all_or_error(self) {
            Ok(()) => vec![],
            Err(errors) => errors,
        };
        debug!("ambig_errors = {:#?}", ambig_errors);

        let region_obligations = self.take_registered_region_obligations();
        let region_constraints = self.with_region_constraints(|region_constraints| {
            make_query_outlives(tcx, region_obligations, region_constraints)
        });

        let certainty = if ambig_errors.is_empty() {
            Certainty::Proven
        } else {
            Certainty::Ambiguous
        };

        Ok(QueryResult {
            var_values: inference_vars,
            region_constraints,
            certainty,
            value: answer,
        })
    }

    /// Given the (canonicalized) result to a canonical query,
    /// instantiates the result so it can be used, plugging in the
    /// values from the canonical query. (Note that the result may
    /// have been ambiguous; you should check the certainty level of
    /// the query before applying this function.)
    ///
    /// To get a good understanding of what is happening here, check
    /// out the [chapter in the rustc guide][c].
    ///
    /// [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html#processing-the-canonicalized-query-result
    pub fn instantiate_query_result_and_region_obligations<R>(
        &self,
        cause: &ObligationCause<'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        original_values: &CanonicalVarValues<'tcx>,
        query_result: &Canonical<'tcx, QueryResult<'tcx, R>>,
    ) -> InferResult<'tcx, R>
    where
        R: Debug + TypeFoldable<'tcx>,
    {
        let InferOk { value: result_subst, mut obligations } = self.query_result_substitution(
            cause,
            param_env,
            original_values,
            query_result,
        )?;

        obligations.extend(self.query_region_constraints_into_obligations(
            cause,
            param_env,
            &query_result.value.region_constraints,
            &result_subst,
        ));

        let user_result: R =
            query_result.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value);

        Ok(InferOk {
            value: user_result,
            obligations,
        })
    }

    /// Given the original values and the (canonicalized) result from
    /// computing a query, returns a substitution that can be applied
    /// to the query result to convert the result back into the
    /// original namespace.
    ///
    /// The substitution also comes accompanied with subobligations
    /// that arose from unification; these might occur if (for
    /// example) we are doing lazy normalization and the value
    /// assigned to a type variable is unified with an unnormalized
    /// projection.
    pub fn query_result_substitution<R>(
        &self,
        cause: &ObligationCause<'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        original_values: &CanonicalVarValues<'tcx>,
        query_result: &Canonical<'tcx, QueryResult<'tcx, R>>,
    ) -> InferResult<'tcx, CanonicalVarValues<'tcx>>
    where
        R: Debug + TypeFoldable<'tcx>,
    {
        debug!(
            "instantiate_query_result(original_values={:#?}, query_result={:#?})",
            original_values, query_result,
        );

        // Every canonical query result includes values for each of
        // the inputs to the query. Therefore, we begin by unifying
        // these values with the original inputs that were
        // canonicalized.
        let result_values = &query_result.value.var_values;
        assert_eq!(original_values.len(), result_values.len());

        // Quickly try to find initial values for the canonical
        // variables in the result in terms of the query. We do this
        // by iterating down the values that the query gave to each of
        // the canonical inputs. If we find that one of those values
        // is directly equal to one of the canonical variables in the
        // result, then we can type the corresponding value from the
        // input. See the example above.
        let mut opt_values: IndexVec<CanonicalVar, Option<Kind<'tcx>>> =
            IndexVec::from_elem_n(None, query_result.variables.len());

        // In terms of our example above, we are iterating over pairs like:
        // [(?A, Vec<?0>), ('static, '?1), (?B, ?0)]
        for (original_value, result_value) in original_values.iter().zip(result_values) {
            match result_value.unpack() {
                UnpackedKind::Type(result_value) => {
                    // e.g., here `result_value` might be `?0` in the example above...
                    if let ty::TyInfer(ty::InferTy::CanonicalTy(index)) = result_value.sty {
                        // in which case we would set `canonical_vars[0]` to `Some(?U)`.
                        opt_values[index] = Some(original_value);
                    }
                }
                UnpackedKind::Lifetime(result_value) => {
                    // e.g., here `result_value` might be `'?1` in the example above...
                    if let &ty::RegionKind::ReCanonical(index) = result_value {
                        // in which case we would set `canonical_vars[0]` to `Some('static)`.
                        opt_values[index] = Some(original_value);
                    }
                }
            }
        }

        // Create a result substitution: if we found a value for a
        // given variable in the loop above, use that. Otherwise, use
        // a fresh inference variable.
        let result_subst = CanonicalVarValues {
            var_values: query_result
                .variables
                .iter()
                .enumerate()
                .map(|(index, info)| match opt_values[CanonicalVar::new(index)] {
                    Some(k) => k,
                    None => self.fresh_inference_var_for_canonical_var(cause.span, *info),
                })
                .collect(),
        };

        // Unify the original values for the canonical variables in
        // the input with the value found in the query
        // post-substitution. Often, but not always, this is a no-op,
        // because we already found the mapping in the first step.
        let obligations = {
            let substituted_values = |index: CanonicalVar| -> Kind<'tcx> {
                query_result.substitute_projected(self.tcx, &result_subst, |v| &v.var_values[index])
            };
            self.unify_canonical_vars(cause, param_env, original_values, substituted_values)?
                .into_obligations()
        };

        Ok(InferOk {
            value: result_subst,
            obligations,
        })
    }

    /// Converts the region constraints resulting from a query into an
    /// iterator of obligations.
    fn query_region_constraints_into_obligations<'a>(
        &'a self,
        cause: &'a ObligationCause<'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        unsubstituted_region_constraints: &'a [QueryRegionConstraint<'tcx>],
        result_subst: &'a CanonicalVarValues<'tcx>,
    ) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a {
        Box::new(
            unsubstituted_region_constraints
                .iter()
                .map(move |constraint| {
                    let ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below
                    let k1 = substitute_value(self.tcx, result_subst, k1);
                    let r2 = substitute_value(self.tcx, result_subst, r2);
                    match k1.unpack() {
                        UnpackedKind::Lifetime(r1) => Obligation::new(
                            cause.clone(),
                            param_env,
                            ty::Predicate::RegionOutlives(ty::Binder::dummy(
                                ty::OutlivesPredicate(r1, r2),
                            )),
                        ),

                        UnpackedKind::Type(t1) => Obligation::new(
                            cause.clone(),
                            param_env,
                            ty::Predicate::TypeOutlives(ty::Binder::dummy(ty::OutlivesPredicate(
                                t1, r2,
                            ))),
                        ),
                    }
                }),
        ) as Box<dyn Iterator<Item = _>>
    }

    /// Given two sets of values for the same set of canonical variables, unify them.
    /// The second set is produced lazilly by supplying indices from the first set.
    fn unify_canonical_vars(
        &self,
        cause: &ObligationCause<'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        variables1: &CanonicalVarValues<'tcx>,
        variables2: impl Fn(CanonicalVar) -> Kind<'tcx>,
    ) -> InferResult<'tcx, ()> {
        self.commit_if_ok(|_| {
            let mut obligations = vec![];
            for (index, value1) in variables1.var_values.iter_enumerated() {
                let value2 = variables2(index);

                match (value1.unpack(), value2.unpack()) {
                    (UnpackedKind::Type(v1), UnpackedKind::Type(v2)) => {
                        obligations
                            .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations());
                    }
                    (
                        UnpackedKind::Lifetime(ty::ReErased),
                        UnpackedKind::Lifetime(ty::ReErased),
                    ) => {
                        // no action needed
                    }
                    (UnpackedKind::Lifetime(v1), UnpackedKind::Lifetime(v2)) => {
                        obligations
                            .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations());
                    }
                    _ => {
                        bug!("kind mismatch, cannot unify {:?} and {:?}", value1, value2,);
                    }
                }
            }
            Ok(InferOk {
                value: (),
                obligations,
            })
        })
    }
}

/// Given the region obligations and constraints scraped from the infcx,
/// creates query region constraints.
pub fn make_query_outlives<'tcx>(
    tcx: TyCtxt<'_, '_, 'tcx>,
    region_obligations: Vec<(ast::NodeId, RegionObligation<'tcx>)>,
    region_constraints: &RegionConstraintData<'tcx>,
) -> Vec<QueryRegionConstraint<'tcx>> {
    let RegionConstraintData {
        constraints,
        verifys,
        givens,
    } = region_constraints;

    assert!(verifys.is_empty());
    assert!(givens.is_empty());

    let mut outlives: Vec<_> = constraints
            .into_iter()
            .map(|(k, _)| match *k {
                // Swap regions because we are going from sub (<=) to outlives
                // (>=).
                Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
                    tcx.mk_region(ty::ReVar(v2)).into(),
                    tcx.mk_region(ty::ReVar(v1)),
                ),
                Constraint::VarSubReg(v1, r2) => {
                    ty::OutlivesPredicate(r2.into(), tcx.mk_region(ty::ReVar(v1)))
                }
                Constraint::RegSubVar(r1, v2) => {
                    ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1)
                }
                Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1),
            })
            .map(ty::Binder::dummy) // no bound regions in the code above
            .collect();

    outlives.extend(
        region_obligations
            .into_iter()
            .map(|(_, r_o)| ty::OutlivesPredicate(r_o.sup_type.into(), r_o.sub_region))
            .map(ty::Binder::dummy), // no bound regions in the code above
    );

    outlives
}
<|endoftext|>


<commit_before>/* Copyright 2018-2022 Torbjørn Birch Moltu
 *
 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
 * http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
 * http://opensource.org/licenses/MIT>, at your option. This file may not be
 * copied, modified, or distributed except according to those terms.
 */

#![cfg(feature="std")]
#![feature(test)]
extern crate test;
use test::{Bencher, black_box};

use std::fs;
use std::path::Path;
use std::io::ErrorKind;
use std::thread::sleep;
use std::time::Duration;
use std::collections::HashMap;
extern crate minreq;
#[macro_use] extern crate lazy_static;
extern crate encode_unicode;
use encode_unicode::{CharExt, Utf8Char, U8UtfExt, Utf16Char, U16UtfExt};

// Setup; need longish strings to make benchmarks representative and
// reduce overhead (might get cache misses now though)
// Therefore we download a few wikipedia articles in different languages.
// Downloading a fixed revision of the articles doesn't prevent the HTML from
// changing due to changes in templates or rendering.

fn load_wikipedia(language: &str,  article: &str,  english: &str,  revision: usize) -> String {
    let cache_path = Path::new("benches").join("texts");
    let cache_path = cache_path.to_str().unwrap();
    let name = format!("{}_{}.html", language, english);
    let path = Path::new(cache_path).join(&name);
    let path = path.to_str().unwrap();
    match fs::read_to_string(path) {
        Ok(content) => return content,
        Err(ref e) if e.kind() == ErrorKind::NotFound => {},//continue
        Err(ref e) if e.kind() == ErrorKind::InvalidData => {
            panic!("{} exists but is not UTF-8", &name);
        },
        Err(e) => panic!("{} exists but cannot be read ({})", path, e),
    }
    let url = format!("https://{}.m.wikipedia.org/w/index.php?title={}&oldid={}",
        language, article, revision
    );
    println!("Downloading {} and saving to {}", &url, path);
    let response = minreq::get(&url).send().unwrap_or_else(|e| {
        panic!("Cannot get {}: {}", url, e);
    });
    if response.status_code != 200 {
        panic!("Bad URL {}: {} {}", url, response.status_code, response.reason_phrase);
    }
    let content = String::from_utf8(response.into_bytes()).unwrap_or_else(|_| {
        panic!("Response from {} is not UTF-8", url);
    });
    if let Err(e) = fs::create_dir_all(cache_path) {
        eprintln!("Warning: failed to create directory {}: {}", cache_path, e);
    } else if let Err(e) = fs::write(&path, &content) {
        eprintln!("Warning: failed to save {}: {}", path, e);
    }
    sleep(Duration::from_secs(1));
    content
}
const ARTICLES: &[(&str, &str, &str, usize)] = &[
    ("en", "United_Kingdom", "United_Kingdom", 855522252),// 99,7% ASCII
    ("es", "España", "Spain", 109861222),// 1,75% 2-byte characters
    ("ru", "Россия", "Russia", 94607243),// 36% 2-byte characters
    // Only UCS / bmp characters are allowed unescaped in URLs:
    ("zh", "%E4%B8%AD%E5%9C%8B", "China", 50868604),// 30% 3-byte characters
];
lazy_static!{
    static ref STRINGS: HashMap<&'static str, String> = {
        let mut content = HashMap::new();
        for &(language, article, english, revision) in ARTICLES {
            content.insert(language, load_wikipedia(language, article, english, revision));
        }
        // make one string with only ASCII
        let only_ascii = content.values()
            .map(|v| (v, v.bytes().filter(|b| b.is_ascii() ).count()) )
            .max_by_key(|&(_,len)| len )
            .map(|(v,_)| v.bytes().filter(|b| b.is_ascii() ).map(|b| b as char ).collect() )
            .unwrap();
        content.insert("ascii", only_ascii);
        content
    };
    static ref EQUAL_CHARS: HashMap<&'static str, &'static str> = {
        let (least, chars) = STRINGS.iter()
            .map(|(l,s)| (l, s.chars().count()) )
            .min_by_key(|&(_,chars)| chars )
            .unwrap();
        println!("chars: {} (limited by {})", chars, least);
        STRINGS.iter().map(|(&language, string)| {
            let cut = string.char_indices()
                .nth(chars)
                .map_or(string.len(), |(i,_)| i );
            let string = &string[..cut];
            assert_eq!(string.chars().count(), chars);
            (language, string)
        }).collect()
    };
    static ref EQUAL_BYTES: HashMap<&'static str, String> = {
        let (least, bytes) = STRINGS.iter()
            .map(|(l,s)| (l, s.len()) )
            .min_by_key(|&(_,bytes)| bytes )
            .unwrap();
        println!("bytes: {} (limited by {})", bytes, least);
        STRINGS.iter().map(|(&language, string)| {
            let mut remaining = bytes;
            // take just so many characters that their length is exactly $bytes
            // slicing won't if !string.is_char_boundary(bytes),
            let string = string.chars().filter(|c| {
                match remaining.checked_sub(c.len_utf8()) {
                    Some(after) => {remaining = after; true},
                    None => false
                }
            }).collect::<String>();
            assert_eq!(string.len(), bytes);
            (language, string)
        }).collect()
    };
    static ref EQUAL_UNITS: HashMap<&'static str, String> = {
        let (least, units) = STRINGS.iter()
            .map(|(l,s)| (l, s.chars().map(|c| c.len_utf16() ).sum::<usize>()) )
            .min_by_key(|&(_,units)| units )
            .unwrap();
        println!("units: {} (limited by {})", units, least);
        STRINGS.iter().map(|(&language, string)| {
            let mut remaining = units;
            let string = string.chars().filter(|c| {
                match remaining.checked_sub(c.len_utf16()) {
                    Some(after) => {remaining = after; true},
                    None => false
                }
            }).collect::<String>();
            assert_eq!(string.chars().map(|c| c.len_utf16() ).sum::<usize>(), units);
            (language, string)
        }).collect()
    };
}

  ///////////////////////////
 // benchmarks begin here //
///////////////////////////

fn utf8char_len(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_BYTES[language];
    let chars: Vec<Utf8Char> = string.chars().map(|c| c.to_utf8() ).collect();
    let bytes = string.len();
    b.iter(|| {
        let sum: usize = black_box(&chars).iter().map(|u8c| u8c.len() ).sum();
        assert_eq!(sum, bytes);
    });
}
#[bench] fn utf8char_len_ascii(b: &mut Bencher) {utf8char_len("ascii", b)}
#[bench] fn utf8char_len_en(b: &mut Bencher) {utf8char_len("en", b)}
#[bench] fn utf8char_len_es(b: &mut Bencher) {utf8char_len("en", b)}
#[bench] fn utf8char_len_ru(b: &mut Bencher) {utf8char_len("ru", b)}
#[bench] fn utf8char_len_zh(b: &mut Bencher) {utf8char_len("zh", b)}

fn utf8_extra_bytes_unchecked(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_CHARS[language];
    let chars = string.chars().count();
    let string = string.as_bytes();
    b.iter(|| {
        let mut i = 0;
        let mut loops = 0;
        while i < string.len() {
            i += string[i].extra_utf8_bytes_unchecked();
            i += 1;
            loops += 1;
        }
        assert_eq!(loops, chars);
    });
}
#[bench] fn utf8_extra_bytes_unchecked_ascii(b: &mut Bencher) {utf8_extra_bytes_unchecked("ascii", b)}
#[bench] fn utf8_extra_bytes_unchecked_en(b: &mut Bencher) {utf8_extra_bytes_unchecked("en", b)}
#[bench] fn utf8_extra_bytes_unchecked_es(b: &mut Bencher) {utf8_extra_bytes_unchecked("es", b)}
#[bench] fn utf8_extra_bytes_unchecked_ru(b: &mut Bencher) {utf8_extra_bytes_unchecked("ru", b)}
#[bench] fn utf8_extra_bytes_unchecked_zh(b: &mut Bencher) {utf8_extra_bytes_unchecked("zh", b)}

fn utf8_extra_bytes(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_CHARS[language];
    let chars = string.chars().count();
    let string = string.as_bytes();
    b.iter(|| {
        let mut i = 0;
        let mut loops = 0;
        let mut errors = 0;
        while i < string.len() {
            match string[i].extra_utf8_bytes() {
                Ok(n) => i += n,
                Err(_) => errors += 1,
            }
            i += 1;
            loops += 1;
        }
        assert_eq!(loops, chars);
        assert_eq!(errors, 0);
    });
}
#[bench] fn utf8_extra_bytes_ascii(b: &mut Bencher) {utf8_extra_bytes("ascii", b)}
#[bench] fn utf8_extra_bytes_en(b: &mut Bencher) {utf8_extra_bytes("en", b)}
#[bench] fn utf8_extra_bytes_es(b: &mut Bencher) {utf8_extra_bytes("es", b)}
#[bench] fn utf8_extra_bytes_ru(b: &mut Bencher) {utf8_extra_bytes("ru", b)}
#[bench] fn utf8_extra_bytes_zh(b: &mut Bencher) {utf8_extra_bytes("zh", b)}

fn utf16char_len(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_UNITS[language];
    let chars: Vec<Utf16Char> = string.chars().map(|c| c.to_utf16() ).collect();
    let units = string.chars().map(|c| c.len_utf16() ).sum::<usize>();
    b.iter(|| {
        let sum: usize = black_box(&chars).iter().map(|u8c| u8c.len() ).sum();
        assert_eq!(sum, units);
    });
}
#[bench] fn utf16char_len_ascii(b: &mut Bencher) {utf16char_len("ascii", b)}
#[bench] fn utf16char_len_en(b: &mut Bencher) {utf16char_len("en", b)}
#[bench] fn utf16char_len_es(b: &mut Bencher) {utf16char_len("en", b)}
#[bench] fn utf16char_len_ru(b: &mut Bencher) {utf16char_len("ru", b)}
#[bench] fn utf16char_len_zh(b: &mut Bencher) {utf16char_len("zh", b)}

fn utf16_is_leading_surrogate(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_UNITS[language];
    let chars = string.chars().count();
    let string: Vec<u16> = string.chars().map(|c| c.to_utf16() ).collect();
    b.iter(|| {
        let mut i = 0;
        let mut loops = 0;
        while i < string.len() {
            i += if string[i].is_utf16_leading_surrogate() {2} else {1};
            loops += 1;
        }
        assert_eq!(loops, chars);
    });
}
#[bench] fn utf16_is_leading_surrogate_ascii(b: &mut Bencher) {utf16_is_leading_surrogate("ascii", b)}
#[bench] fn utf16_is_leading_surrogate_en(b: &mut Bencher) {utf16_is_leading_surrogate("en", b)}
#[bench] fn utf16_is_leading_surrogate_es(b: &mut Bencher) {utf16_is_leading_surrogate("en", b)}
#[bench] fn utf16_is_leading_surrogate_ru(b: &mut Bencher) {utf16_is_leading_surrogate("ru", b)}
#[bench] fn utf16_is_leading_surrogate_zh(b: &mut Bencher) {utf16_is_leading_surrogate("zh", b)}

fn utf16_needs_extra_unit(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_UNITS[language];
    let chars = string.chars().count();
    let string: Vec<u16> = string.chars().map(|c| c.to_utf16() ).collect();
    b.iter(|| {
        let mut i = 0;
        let mut loops = 0;
        let mut errors = 0;
        while i < string.len() {
            i += match string[i].utf16_needs_extra_unit() {
                Ok(true) => 2,
                Ok(false) => 1,
                Err(_) => {errors+=1; 1}
            };
            loops += 1;
        }
        assert_eq!(loops, chars);
        assert_eq!(errors, 0);
    });
}
#[bench] fn utf16_needs_extra_unit_ascii(b: &mut Bencher) {utf16_needs_extra_unit("ascii", b)}
#[bench] fn utf16_needs_extra_unit_en(b: &mut Bencher) {utf16_needs_extra_unit("en", b)}
#[bench] fn utf16_needs_extra_unit_es(b: &mut Bencher) {utf16_needs_extra_unit("en", b)}
#[bench] fn utf16_needs_extra_unit_ru(b: &mut Bencher) {utf16_needs_extra_unit("ru", b)}
#[bench] fn utf16_needs_extra_unit_zh(b: &mut Bencher) {utf16_needs_extra_unit("zh", b)}
<commit_msg>Fix some benchmarks testing the wrong thing<commit_after>/* Copyright 2018-2022 Torbjørn Birch Moltu
 *
 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
 * http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
 * http://opensource.org/licenses/MIT>, at your option. This file may not be
 * copied, modified, or distributed except according to those terms.
 */

#![cfg(feature="std")]
#![feature(test)]
extern crate test;
use test::{Bencher, black_box};

use std::fs;
use std::path::Path;
use std::io::ErrorKind;
use std::thread::sleep;
use std::time::Duration;
use std::collections::HashMap;
extern crate minreq;
#[macro_use] extern crate lazy_static;
extern crate encode_unicode;
use encode_unicode::{CharExt, Utf8Char, U8UtfExt, Utf16Char, U16UtfExt};

// Setup; need longish strings to make benchmarks representative and
// reduce overhead (might get cache misses now though)
// Therefore we download a few wikipedia articles in different languages.
// Downloading a fixed revision of the articles doesn't prevent the HTML from
// changing due to changes in templates or rendering.

fn load_wikipedia(language: &str,  article: &str,  english: &str,  revision: usize) -> String {
    let cache_path = Path::new("benches").join("texts");
    let cache_path = cache_path.to_str().unwrap();
    let name = format!("{}_{}.html", language, english);
    let path = Path::new(cache_path).join(&name);
    let path = path.to_str().unwrap();
    match fs::read_to_string(path) {
        Ok(content) => return content,
        Err(ref e) if e.kind() == ErrorKind::NotFound => {},//continue
        Err(ref e) if e.kind() == ErrorKind::InvalidData => {
            panic!("{} exists but is not UTF-8", &name);
        },
        Err(e) => panic!("{} exists but cannot be read ({})", path, e),
    }
    let url = format!("https://{}.m.wikipedia.org/w/index.php?title={}&oldid={}",
        language, article, revision
    );
    println!("Downloading {} and saving to {}", &url, path);
    let response = minreq::get(&url).send().unwrap_or_else(|e| {
        panic!("Cannot get {}: {}", url, e);
    });
    if response.status_code != 200 {
        panic!("Bad URL {}: {} {}", url, response.status_code, response.reason_phrase);
    }
    let content = String::from_utf8(response.into_bytes()).unwrap_or_else(|_| {
        panic!("Response from {} is not UTF-8", url);
    });
    if let Err(e) = fs::create_dir_all(cache_path) {
        eprintln!("Warning: failed to create directory {}: {}", cache_path, e);
    } else if let Err(e) = fs::write(&path, &content) {
        eprintln!("Warning: failed to save {}: {}", path, e);
    }
    sleep(Duration::from_secs(1));
    content
}
const ARTICLES: &[(&str, &str, &str, usize)] = &[
    ("en", "United_Kingdom", "United_Kingdom", 855522252),// 99,7% ASCII
    ("es", "España", "Spain", 109861222),// 1,75% 2-byte characters
    ("ru", "Россия", "Russia", 94607243),// 36% 2-byte characters
    // Only UCS / bmp characters are allowed unescaped in URLs:
    ("zh", "%E4%B8%AD%E5%9C%8B", "China", 50868604),// 30% 3-byte characters
];
lazy_static!{
    static ref STRINGS: HashMap<&'static str, String> = {
        let mut content = HashMap::new();
        for &(language, article, english, revision) in ARTICLES {
            content.insert(language, load_wikipedia(language, article, english, revision));
        }
        // make one string with only ASCII
        let only_ascii = content.values()
            .map(|v| (v, v.bytes().filter(|b| b.is_ascii() ).count()) )
            .max_by_key(|&(_,len)| len )
            .map(|(v,_)| v.bytes().filter(|b| b.is_ascii() ).map(|b| b as char ).collect() )
            .unwrap();
        content.insert("ascii", only_ascii);
        content
    };
    static ref EQUAL_CHARS: HashMap<&'static str, &'static str> = {
        let (least, chars) = STRINGS.iter()
            .map(|(l,s)| (l, s.chars().count()) )
            .min_by_key(|&(_,chars)| chars )
            .unwrap();
        println!("chars: {} (limited by {})", chars, least);
        STRINGS.iter().map(|(&language, string)| {
            let cut = string.char_indices()
                .nth(chars)
                .map_or(string.len(), |(i,_)| i );
            let string = &string[..cut];
            assert_eq!(string.chars().count(), chars);
            (language, string)
        }).collect()
    };
    static ref EQUAL_BYTES: HashMap<&'static str, String> = {
        let (least, bytes) = STRINGS.iter()
            .map(|(l,s)| (l, s.len()) )
            .min_by_key(|&(_,bytes)| bytes )
            .unwrap();
        println!("bytes: {} (limited by {})", bytes, least);
        STRINGS.iter().map(|(&language, string)| {
            let mut remaining = bytes;
            // take just so many characters that their length is exactly $bytes
            // slicing won't if !string.is_char_boundary(bytes),
            let string = string.chars().filter(|c| {
                match remaining.checked_sub(c.len_utf8()) {
                    Some(after) => {remaining = after; true},
                    None => false
                }
            }).collect::<String>();
            assert_eq!(string.len(), bytes);
            (language, string)
        }).collect()
    };
    static ref EQUAL_UNITS: HashMap<&'static str, String> = {
        let (least, units) = STRINGS.iter()
            .map(|(l,s)| (l, s.chars().map(|c| c.len_utf16() ).sum::<usize>()) )
            .min_by_key(|&(_,units)| units )
            .unwrap();
        println!("units: {} (limited by {})", units, least);
        STRINGS.iter().map(|(&language, string)| {
            let mut remaining = units;
            let string = string.chars().filter(|c| {
                match remaining.checked_sub(c.len_utf16()) {
                    Some(after) => {remaining = after; true},
                    None => false
                }
            }).collect::<String>();
            assert_eq!(string.chars().map(|c| c.len_utf16() ).sum::<usize>(), units);
            (language, string)
        }).collect()
    };
}

  ///////////////////////////
 // benchmarks begin here //
///////////////////////////

fn utf8char_len(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_BYTES[language];
    let chars: Vec<Utf8Char> = string.chars().map(|c| c.to_utf8() ).collect();
    let bytes = string.len();
    b.iter(|| {
        let sum: usize = black_box(&chars).iter().map(|u8c| u8c.len() ).sum();
        assert_eq!(sum, bytes);
    });
}
#[bench] fn utf8char_len_ascii(b: &mut Bencher) {utf8char_len("ascii", b)}
#[bench] fn utf8char_len_en(b: &mut Bencher) {utf8char_len("en", b)}
#[bench] fn utf8char_len_es(b: &mut Bencher) {utf8char_len("es", b)}
#[bench] fn utf8char_len_ru(b: &mut Bencher) {utf8char_len("ru", b)}
#[bench] fn utf8char_len_zh(b: &mut Bencher) {utf8char_len("zh", b)}

fn utf8_extra_bytes_unchecked(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_CHARS[language];
    let chars = string.chars().count();
    let string = string.as_bytes();
    b.iter(|| {
        let mut i = 0;
        let mut loops = 0;
        while i < string.len() {
            i += string[i].extra_utf8_bytes_unchecked();
            i += 1;
            loops += 1;
        }
        assert_eq!(loops, chars);
    });
}
#[bench] fn utf8_extra_bytes_unchecked_ascii(b: &mut Bencher) {utf8_extra_bytes_unchecked("ascii", b)}
#[bench] fn utf8_extra_bytes_unchecked_en(b: &mut Bencher) {utf8_extra_bytes_unchecked("en", b)}
#[bench] fn utf8_extra_bytes_unchecked_es(b: &mut Bencher) {utf8_extra_bytes_unchecked("es", b)}
#[bench] fn utf8_extra_bytes_unchecked_ru(b: &mut Bencher) {utf8_extra_bytes_unchecked("ru", b)}
#[bench] fn utf8_extra_bytes_unchecked_zh(b: &mut Bencher) {utf8_extra_bytes_unchecked("zh", b)}

fn utf8_extra_bytes(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_CHARS[language];
    let chars = string.chars().count();
    let string = string.as_bytes();
    b.iter(|| {
        let mut i = 0;
        let mut loops = 0;
        let mut errors = 0;
        while i < string.len() {
            match string[i].extra_utf8_bytes() {
                Ok(n) => i += n,
                Err(_) => errors += 1,
            }
            i += 1;
            loops += 1;
        }
        assert_eq!(loops, chars);
        assert_eq!(errors, 0);
    });
}
#[bench] fn utf8_extra_bytes_ascii(b: &mut Bencher) {utf8_extra_bytes("ascii", b)}
#[bench] fn utf8_extra_bytes_en(b: &mut Bencher) {utf8_extra_bytes("en", b)}
#[bench] fn utf8_extra_bytes_es(b: &mut Bencher) {utf8_extra_bytes("es", b)}
#[bench] fn utf8_extra_bytes_ru(b: &mut Bencher) {utf8_extra_bytes("ru", b)}
#[bench] fn utf8_extra_bytes_zh(b: &mut Bencher) {utf8_extra_bytes("zh", b)}

fn utf16char_len(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_UNITS[language];
    let chars: Vec<Utf16Char> = string.chars().map(|c| c.to_utf16() ).collect();
    let units = string.chars().map(|c| c.len_utf16() ).sum::<usize>();
    b.iter(|| {
        let sum: usize = black_box(&chars).iter().map(|u8c| u8c.len() ).sum();
        assert_eq!(sum, units);
    });
}
#[bench] fn utf16char_len_ascii(b: &mut Bencher) {utf16char_len("ascii", b)}
#[bench] fn utf16char_len_en(b: &mut Bencher) {utf16char_len("en", b)}
#[bench] fn utf16char_len_es(b: &mut Bencher) {utf16char_len("en", b)}
#[bench] fn utf16char_len_ru(b: &mut Bencher) {utf16char_len("ru", b)}
#[bench] fn utf16char_len_zh(b: &mut Bencher) {utf16char_len("zh", b)}

fn utf16_is_leading_surrogate(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_UNITS[language];
    let chars = string.chars().count();
    let string: Vec<u16> = string.chars().map(|c| c.to_utf16() ).collect();
    b.iter(|| {
        let mut i = 0;
        let mut loops = 0;
        while i < string.len() {
            i += if string[i].is_utf16_leading_surrogate() {2} else {1};
            loops += 1;
        }
        assert_eq!(loops, chars);
    });
}
#[bench] fn utf16_is_leading_surrogate_ascii(b: &mut Bencher) {utf16_is_leading_surrogate("ascii", b)}
#[bench] fn utf16_is_leading_surrogate_en(b: &mut Bencher) {utf16_is_leading_surrogate("en", b)}
#[bench] fn utf16_is_leading_surrogate_es(b: &mut Bencher) {utf16_is_leading_surrogate("es", b)}
#[bench] fn utf16_is_leading_surrogate_ru(b: &mut Bencher) {utf16_is_leading_surrogate("ru", b)}
#[bench] fn utf16_is_leading_surrogate_zh(b: &mut Bencher) {utf16_is_leading_surrogate("zh", b)}

fn utf16_needs_extra_unit(language: &str,  b: &mut Bencher) {
    let string = &EQUAL_UNITS[language];
    let chars = string.chars().count();
    let string: Vec<u16> = string.chars().map(|c| c.to_utf16() ).collect();
    b.iter(|| {
        let mut i = 0;
        let mut loops = 0;
        let mut errors = 0;
        while i < string.len() {
            i += match string[i].utf16_needs_extra_unit() {
                Ok(true) => 2,
                Ok(false) => 1,
                Err(_) => {errors+=1; 1}
            };
            loops += 1;
        }
        assert_eq!(loops, chars);
        assert_eq!(errors, 0);
    });
}
#[bench] fn utf16_needs_extra_unit_ascii(b: &mut Bencher) {utf16_needs_extra_unit("ascii", b)}
#[bench] fn utf16_needs_extra_unit_en(b: &mut Bencher) {utf16_needs_extra_unit("en", b)}
#[bench] fn utf16_needs_extra_unit_es(b: &mut Bencher) {utf16_needs_extra_unit("es", b)}
#[bench] fn utf16_needs_extra_unit_ru(b: &mut Bencher) {utf16_needs_extra_unit("ru", b)}
#[bench] fn utf16_needs_extra_unit_zh(b: &mut Bencher) {utf16_needs_extra_unit("zh", b)}
<|endoftext|>


<commit_before>#![feature(test)]
extern crate rff;
extern crate test;

use test::Bencher;

use rff::scorer::{score, score_with_positions, compute_bonus};

#[bench]
fn bench_score(b: &mut Bencher) {
    b.iter(|| score("amor", "app/models/order.rb"))
}

#[bench]
fn bench_score_empty_needle(b: &mut Bencher) {
    b.iter(|| score("", "app/models/order.rb"))
}

#[bench]
fn bench_score_matching(b: &mut Bencher) {
    b.iter(|| score("app/models/order.rb", "app/models/order.rb"))
}

#[bench]
fn bench_score_huge_haystack(b: &mut Bencher) {
    let huge_string = "X".repeat(1025);
    b.iter(|| score("amor", &huge_string))
}

#[bench]
fn bench_score_multiple(b: &mut Bencher) {
    b.iter(|| {
        score("amor", "app/models/order.rb");
        score("amor", "spec/models/order_spec.rb");
        score("amor", "other_garbage.rb");
        score("amor", "Gemfile");
        score("amor", "node_modules/test/a/thing.js");
        score("amor", "vendor/bundle/ruby/gem.rb")
    })
}

#[bench]
fn bench_score_with_positions(b: &mut Bencher) {
    b.iter(|| score_with_positions("amor", "app/models/order.rb"))
}

#[bench]
fn bench_score_multiple_with_positions(b: &mut Bencher) {
    b.iter(|| {
        score_with_positions("amor", "app/models/order.rb");
        score_with_positions("amor", "spec/models/order_spec.rb");
        score_with_positions("amor", "other_garbage.rb");
        score_with_positions("amor", "Gemfile");
        score_with_positions("amor", "node_modules/test/a/thing.js");
        score_with_positions("amor", "vendor/bundle/ruby/gem.rb")
    })
}

#[bench]
fn bench_compute_bonus(b: &mut Bencher) {
    b.iter(|| compute_bonus("app/models/this/is/a/strangely/nested/path.rb"))
}

#[bench]
fn bench_compute_bonuses(b: &mut Bencher) {
    b.iter(|| {
        compute_bonus("app/models/order.rb");
        compute_bonus("spec/models/order_spec.rb");
        compute_bonus("other_garbage.rb");
        compute_bonus("Gemfile");
        compute_bonus("node_modules/test/a/thing.js");
        compute_bonus("vendor/bundle/ruby/gem.rb")
    })
}
<commit_msg>Add benchmark of large-but-not-massive haystack<commit_after>#![feature(test)]
extern crate rff;
extern crate test;

use test::Bencher;

use rff::scorer::{score, score_with_positions, compute_bonus};

#[bench]
fn bench_score(b: &mut Bencher) {
    b.iter(|| score("amor", "app/models/order.rb"))
}

#[bench]
fn bench_score_empty_needle(b: &mut Bencher) {
    b.iter(|| score("", "app/models/order.rb"))
}

#[bench]
fn bench_score_matching(b: &mut Bencher) {
    b.iter(|| score("app/models/order.rb", "app/models/order.rb"))
}

#[bench]
fn bench_score_large_haystack(b: &mut Bencher) {
    let large_string = "X".repeat(1024);
    b.iter(|| score("amor", &large_string))
}

#[bench]
fn bench_score_huge_haystack(b: &mut Bencher) {
    let huge_string = "X".repeat(1025);
    b.iter(|| score("amor", &huge_string))
}

#[bench]
fn bench_score_multiple(b: &mut Bencher) {
    b.iter(|| {
        score("amor", "app/models/order.rb");
        score("amor", "spec/models/order_spec.rb");
        score("amor", "other_garbage.rb");
        score("amor", "Gemfile");
        score("amor", "node_modules/test/a/thing.js");
        score("amor", "vendor/bundle/ruby/gem.rb")
    })
}

#[bench]
fn bench_score_with_positions(b: &mut Bencher) {
    b.iter(|| score_with_positions("amor", "app/models/order.rb"))
}

#[bench]
fn bench_score_multiple_with_positions(b: &mut Bencher) {
    b.iter(|| {
        score_with_positions("amor", "app/models/order.rb");
        score_with_positions("amor", "spec/models/order_spec.rb");
        score_with_positions("amor", "other_garbage.rb");
        score_with_positions("amor", "Gemfile");
        score_with_positions("amor", "node_modules/test/a/thing.js");
        score_with_positions("amor", "vendor/bundle/ruby/gem.rb")
    })
}

#[bench]
fn bench_compute_bonus(b: &mut Bencher) {
    b.iter(|| compute_bonus("app/models/this/is/a/strangely/nested/path.rb"))
}

#[bench]
fn bench_compute_bonuses(b: &mut Bencher) {
    b.iter(|| {
        compute_bonus("app/models/order.rb");
        compute_bonus("spec/models/order_spec.rb");
        compute_bonus("other_garbage.rb");
        compute_bonus("Gemfile");
        compute_bonus("node_modules/test/a/thing.js");
        compute_bonus("vendor/bundle/ruby/gem.rb")
    })
}
<|endoftext|>


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

#[doc(hidden)]; // FIXME #3538

use cast::transmute;

pub type Word = uint;

pub struct Frame {
    fp: *Word
}

pub fn Frame(fp: *Word) -> Frame {
    Frame {
        fp: fp
    }
}

pub fn walk_stack(visit: &fn(Frame) -> bool) {

    debug!("beginning stack walk");

    do frame_address |frame_pointer| {
        let mut frame_address: *Word = unsafe {
            transmute(frame_pointer)
        };
        loop {
            let fr = Frame(frame_address);

            debug!("frame: %x", unsafe { transmute(fr.fp) });
            visit(fr);

            unsafe {
                let next_fp: **Word = transmute(frame_address);
                frame_address = *next_fp;
                if *frame_address == 0u {
                    debug!("encountered task_start_wrapper. ending walk");
                    // This is the task_start_wrapper_frame. There is
                    // no stack beneath it and it is a foreign frame.
                    break;
                }
            }
        }
    }
}

#[test]
fn test_simple() {
    for walk_stack |_frame| {
    }
}

#[test]
fn test_simple_deep() {
    fn run(i: int) {
        if i == 0 { return }

        for walk_stack |_frame| {
            breakpoint();
        }
        run(i - 1);
    }

    run(10);
}

fn breakpoint() {
    unsafe {
        rustrt::rust_dbg_breakpoint()
    }
}

fn frame_address(f: &fn(x: *u8)) {
    unsafe {
        rusti::frame_address(f)
    }
}

pub mod rustrt {
    pub extern {
        pub unsafe fn rust_dbg_breakpoint();
    }
}

pub mod rusti {
    #[abi = "rust-intrinsic"]
    pub extern "rust-intrinsic" {
        pub fn frame_address(+f: &once fn(x: *u8));
    }
}
<commit_msg>auto merge of #6255 : brson/rust/nobreakpoint, r=graydon<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[doc(hidden)]; // FIXME #3538

use cast::transmute;

pub type Word = uint;

pub struct Frame {
    fp: *Word
}

pub fn Frame(fp: *Word) -> Frame {
    Frame {
        fp: fp
    }
}

pub fn walk_stack(visit: &fn(Frame) -> bool) {

    debug!("beginning stack walk");

    do frame_address |frame_pointer| {
        let mut frame_address: *Word = unsafe {
            transmute(frame_pointer)
        };
        loop {
            let fr = Frame(frame_address);

            debug!("frame: %x", unsafe { transmute(fr.fp) });
            visit(fr);

            unsafe {
                let next_fp: **Word = transmute(frame_address);
                frame_address = *next_fp;
                if *frame_address == 0u {
                    debug!("encountered task_start_wrapper. ending walk");
                    // This is the task_start_wrapper_frame. There is
                    // no stack beneath it and it is a foreign frame.
                    break;
                }
            }
        }
    }
}

#[test]
fn test_simple() {
    for walk_stack |_frame| {
    }
}

#[test]
fn test_simple_deep() {
    fn run(i: int) {
        if i == 0 { return }

        for walk_stack |_frame| {
            // Would be nice to test something here...
        }
        run(i - 1);
    }

    run(10);
}

fn frame_address(f: &fn(x: *u8)) {
    unsafe {
        rusti::frame_address(f)
    }
}

pub mod rusti {
    #[abi = "rust-intrinsic"]
    pub extern "rust-intrinsic" {
        pub fn frame_address(+f: &once fn(x: *u8));
    }
}
<|endoftext|>


<commit_before>// NB: Don't rely on other core mods here as this has to move into the rt

import unsafe::reinterpret_cast;
import ptr::offset;
import sys::size_of;

type word = uint;

class frame {
    let fp: *word;

    new(fp: *word) {
        self.fp = fp;
    }
}

fn walk_stack(visit: fn(frame) -> bool) {

    #debug("beginning stack walk");

    frame_address { |frame_pointer|
        let mut frame_address: *word = unsafe {
            reinterpret_cast(frame_pointer)
        };
        loop {
            let frame = frame(frame_address);

            #debug("frame: %x", unsafe { reinterpret_cast(frame.fp) });
            visit(frame);

            unsafe {
                let next_fp: **word = reinterpret_cast(frame_address);
                frame_address = *next_fp;
                if *frame_address == 0u {
                    #debug("encountered task_start_wrapper. ending walk");
                    // This is the task_start_wrapper_frame. There is
                    // no stack beneath it and it is a native frame.
                    break;
                }
            }
        }
    }
}

#[test]
fn test_simple() {
    for walk_stack { |frame|
    }
}

#[test]
fn test_simple_deep() {
    fn run(i: int) {
        if i == 0 { ret }

        for walk_stack { |frame|
            unsafe {
                breakpoint();
            }
        }
        run(i - 1);
    }

    run(10);
}

fn breakpoint() {
    rustrt::rust_dbg_breakpoint()
}

fn frame_address(f: fn(*u8)) {
    rusti::frame_address(f)
}

native mod rustrt {
    fn rust_dbg_breakpoint();
}

#[abi = "rust-intrinsic"]
native mod rusti {
    fn frame_address(f: fn(*u8));
}
<commit_msg>Don't shadow a class name with a local<commit_after>// NB: Don't rely on other core mods here as this has to move into the rt

import unsafe::reinterpret_cast;
import ptr::offset;
import sys::size_of;

type word = uint;

class frame {
    let fp: *word;

    new(fp: *word) {
        self.fp = fp;
    }
}

fn walk_stack(visit: fn(frame) -> bool) {

    #debug("beginning stack walk");

    frame_address { |frame_pointer|
        let mut frame_address: *word = unsafe {
            reinterpret_cast(frame_pointer)
        };
        loop {
            let fr = frame(frame_address);

            #debug("frame: %x", unsafe { reinterpret_cast(fr.fp) });
            visit(fr);

            unsafe {
                let next_fp: **word = reinterpret_cast(frame_address);
                frame_address = *next_fp;
                if *frame_address == 0u {
                    #debug("encountered task_start_wrapper. ending walk");
                    // This is the task_start_wrapper_frame. There is
                    // no stack beneath it and it is a native frame.
                    break;
                }
            }
        }
    }
}

#[test]
fn test_simple() {
    for walk_stack { |_frame|
    }
}

#[test]
fn test_simple_deep() {
    fn run(i: int) {
        if i == 0 { ret }

        for walk_stack { |_frame|
            unsafe {
                breakpoint();
            }
        }
        run(i - 1);
    }

    run(10);
}

fn breakpoint() {
    rustrt::rust_dbg_breakpoint()
}

fn frame_address(f: fn(*u8)) {
    rusti::frame_address(f)
}

native mod rustrt {
    fn rust_dbg_breakpoint();
}

#[abi = "rust-intrinsic"]
native mod rusti {
    fn frame_address(f: fn(*u8));
}
<|endoftext|>


<commit_before>use crate::alloc::Layout;
use crate::cmp;
use crate::ptr;

/// A memory allocator that can be registered as the standard library’s default
/// through the `#[global_allocator]` attribute.
///
/// Some of the methods require that a memory block be *currently
/// allocated* via an allocator. This means that:
///
/// * the starting address for that memory block was previously
///   returned by a previous call to an allocation method
///   such as `alloc`, and
///
/// * the memory block has not been subsequently deallocated, where
///   blocks are deallocated either by being passed to a deallocation
///   method such as `dealloc` or by being
///   passed to a reallocation method that returns a non-null pointer.
///
///
/// # Example
///
/// ```no_run
/// use std::alloc::{GlobalAlloc, Layout, alloc};
/// use std::ptr::null_mut;
///
/// struct MyAllocator;
///
/// unsafe impl GlobalAlloc for MyAllocator {
///     unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { null_mut() }
///     unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
/// }
///
/// #[global_allocator]
/// static A: MyAllocator = MyAllocator;
///
/// fn main() {
///     unsafe {
///         assert!(alloc(Layout::new::<u32>()).is_null())
///     }
/// }
/// ```
///
/// # Safety
///
/// The `GlobalAlloc` trait is an `unsafe` trait for a number of reasons, and
/// implementors must ensure that they adhere to these contracts:
///
/// * It's undefined behavior if global allocators unwind. This restriction may
///   be lifted in the future, but currently a panic from any of these
///   functions may lead to memory unsafety.
///
/// * `Layout` queries and calculations in general must be correct. Callers of
///   this trait are allowed to rely on the contracts defined on each method,
///   and implementors must ensure such contracts remain true.
#[stable(feature = "global_alloc", since = "1.28.0")]
pub unsafe trait GlobalAlloc {
    /// Allocate memory as described by the given `layout`.
    ///
    /// Returns a pointer to newly-allocated memory,
    /// or null to indicate allocation failure.
    ///
    /// # Safety
    ///
    /// This function is unsafe because undefined behavior can result
    /// if the caller does not ensure that `layout` has non-zero size.
    ///
    /// (Extension subtraits might provide more specific bounds on
    /// behavior, e.g., guarantee a sentinel address or a null pointer
    /// in response to a zero-size allocation request.)
    ///
    /// The allocated block of memory may or may not be initialized.
    ///
    /// # Errors
    ///
    /// Returning a null pointer indicates that either memory is exhausted
    /// or `layout` does not meet this allocator's size or alignment constraints.
    ///
    /// Implementations are encouraged to return null on memory
    /// exhaustion rather than aborting, but this is not
    /// a strict requirement. (Specifically: it is *legal* to
    /// implement this trait atop an underlying native allocation
    /// library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to an
    /// allocation error are encouraged to call the [`handle_alloc_error`] function,
    /// rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    #[stable(feature = "global_alloc", since = "1.28.0")]
    unsafe fn alloc(&self, layout: Layout) -> *mut u8;

    /// Deallocate the block of memory at the given `ptr` pointer with the given `layout`.
    ///
    /// # Safety
    ///
    /// This function is unsafe because undefined behavior can result
    /// if the caller does not ensure all of the following:
    ///
    /// * `ptr` must denote a block of memory currently allocated via
    ///   this allocator,
    ///
    /// * `layout` must be the same layout that was used
    ///   to allocate that block of memory,
    #[stable(feature = "global_alloc", since = "1.28.0")]
    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout);

    /// Behaves like `alloc`, but also ensures that the contents
    /// are set to zero before being returned.
    ///
    /// # Safety
    ///
    /// This function is unsafe for the same reasons that `alloc` is.
    /// However the allocated block of memory is guaranteed to be initialized.
    ///
    /// # Errors
    ///
    /// Returning a null pointer indicates that either memory is exhausted
    /// or `layout` does not meet allocator's size or alignment constraints,
    /// just as in `alloc`.
    ///
    /// Clients wishing to abort computation in response to an
    /// allocation error are encouraged to call the [`handle_alloc_error`] function,
    /// rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    #[stable(feature = "global_alloc", since = "1.28.0")]
    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
        let size = layout.size();
        // SAFETY: the safety contract for `alloc` must be upheld by the caller.
        let ptr = unsafe { self.alloc(layout) };
        if !ptr.is_null() {
            // SAFETY: as allocation succeeded, the region from `ptr`
            // of size `size` is guaranteed to be valid for writes.
            unsafe { ptr::write_bytes(ptr, 0, size) };
        }
        ptr
    }

    /// Shrink or grow a block of memory to the given `new_size`.
    /// The block is described by the given `ptr` pointer and `layout`.
    ///
    /// If this returns a non-null pointer, then ownership of the memory block
    /// referenced by `ptr` has been transferred to this allocator.
    /// The memory may or may not have been deallocated,
    /// and should be considered unusable (unless of course it was
    /// transferred back to the caller again via the return value of
    /// this method). The new memory block is allocated with `layout`, but
    /// with the `size` updated to `new_size`.
    ///
    /// If this method returns null, then ownership of the memory
    /// block has not been transferred to this allocator, and the
    /// contents of the memory block are unaltered.
    ///
    /// # Safety
    ///
    /// This function is unsafe because undefined behavior can result
    /// if the caller does not ensure all of the following:
    ///
    /// * `ptr` must be currently allocated via this allocator,
    ///
    /// * `layout` must be the same layout that was used
    ///   to allocate that block of memory,
    ///
    /// * `new_size` must be greater than zero.
    ///
    /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`,
    ///   must not overflow (i.e., the rounded value must be less than `usize::MAX`).
    ///
    /// (Extension subtraits might provide more specific bounds on
    /// behavior, e.g., guarantee a sentinel address or a null pointer
    /// in response to a zero-size allocation request.)
    ///
    /// # Errors
    ///
    /// Returns null if the new layout does not meet the size
    /// and alignment constraints of the allocator, or if reallocation
    /// otherwise fails.
    ///
    /// Implementations are encouraged to return null on memory
    /// exhaustion rather than panicking or aborting, but this is not
    /// a strict requirement. (Specifically: it is *legal* to
    /// implement this trait atop an underlying native allocation
    /// library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to a
    /// reallocation error are encouraged to call the [`handle_alloc_error`] function,
    /// rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    #[stable(feature = "global_alloc", since = "1.28.0")]
    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
        // SAFETY: the caller must ensure that the `new_size` does not overflow.
        // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid.
        let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
        // SAFETY: the caller must ensure that `new_layout` is greater than zero.
        let new_ptr = unsafe { self.alloc(new_layout) };
        if !new_ptr.is_null() {
            // SAFETY: the previously allocated block cannot overlap the newly allocated block.
            // The safety contract for `dealloc` must be upheld by the caller.
            unsafe {
                ptr::copy_nonoverlapping(ptr, new_ptr, cmp::min(layout.size(), new_size));
                self.dealloc(ptr, layout);
            }
        }
        new_ptr
    }
}
<commit_msg>Auto merge of #79045 - oli-obk:dont_rely_on_alloc_happening_for_soundness, r=TimDiekmann<commit_after>use crate::alloc::Layout;
use crate::cmp;
use crate::ptr;

/// A memory allocator that can be registered as the standard library’s default
/// through the `#[global_allocator]` attribute.
///
/// Some of the methods require that a memory block be *currently
/// allocated* via an allocator. This means that:
///
/// * the starting address for that memory block was previously
///   returned by a previous call to an allocation method
///   such as `alloc`, and
///
/// * the memory block has not been subsequently deallocated, where
///   blocks are deallocated either by being passed to a deallocation
///   method such as `dealloc` or by being
///   passed to a reallocation method that returns a non-null pointer.
///
///
/// # Example
///
/// ```no_run
/// use std::alloc::{GlobalAlloc, Layout, alloc};
/// use std::ptr::null_mut;
///
/// struct MyAllocator;
///
/// unsafe impl GlobalAlloc for MyAllocator {
///     unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { null_mut() }
///     unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
/// }
///
/// #[global_allocator]
/// static A: MyAllocator = MyAllocator;
///
/// fn main() {
///     unsafe {
///         assert!(alloc(Layout::new::<u32>()).is_null())
///     }
/// }
/// ```
///
/// # Safety
///
/// The `GlobalAlloc` trait is an `unsafe` trait for a number of reasons, and
/// implementors must ensure that they adhere to these contracts:
///
/// * It's undefined behavior if global allocators unwind. This restriction may
///   be lifted in the future, but currently a panic from any of these
///   functions may lead to memory unsafety.
///
/// * `Layout` queries and calculations in general must be correct. Callers of
///   this trait are allowed to rely on the contracts defined on each method,
///   and implementors must ensure such contracts remain true.
///
/// * You may not rely on allocations actually happening, even if there are explicit
///   heap allocations in the source. The optimizer may detect unused allocations that it can either
///   eliminate entirely or move to the stack and thus never invoke the allocator. The
///   optimizer may further assume that allocation is infallible, so code that used to fail due
///   to allocator failures may now suddenly work because the optimizer worked around the
///   need for an allocation. More concretely, the following code example is unsound, irrespective
///   of whether your custom allocator allows counting how many allocations have happened.
///
///   ```rust,ignore (unsound and has placeholders)
///   drop(Box::new(42));
///   let number_of_heap_allocs = /* call private allocator API */;
///   unsafe { std::intrinsics::assume(number_of_heap_allocs > 0); }
///   ```
///
///   Note that the optimizations mentioned above are not the only
///   optimization that can be applied. You may generally not rely on heap allocations
///   happening if they can be removed without changing program behavior.
///   Whether allocations happen or not is not part of the program behavior, even if it
///   could be detected via an allocator that tracks allocations by printing or otherwise
///   having side effects.
#[stable(feature = "global_alloc", since = "1.28.0")]
pub unsafe trait GlobalAlloc {
    /// Allocate memory as described by the given `layout`.
    ///
    /// Returns a pointer to newly-allocated memory,
    /// or null to indicate allocation failure.
    ///
    /// # Safety
    ///
    /// This function is unsafe because undefined behavior can result
    /// if the caller does not ensure that `layout` has non-zero size.
    ///
    /// (Extension subtraits might provide more specific bounds on
    /// behavior, e.g., guarantee a sentinel address or a null pointer
    /// in response to a zero-size allocation request.)
    ///
    /// The allocated block of memory may or may not be initialized.
    ///
    /// # Errors
    ///
    /// Returning a null pointer indicates that either memory is exhausted
    /// or `layout` does not meet this allocator's size or alignment constraints.
    ///
    /// Implementations are encouraged to return null on memory
    /// exhaustion rather than aborting, but this is not
    /// a strict requirement. (Specifically: it is *legal* to
    /// implement this trait atop an underlying native allocation
    /// library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to an
    /// allocation error are encouraged to call the [`handle_alloc_error`] function,
    /// rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    #[stable(feature = "global_alloc", since = "1.28.0")]
    unsafe fn alloc(&self, layout: Layout) -> *mut u8;

    /// Deallocate the block of memory at the given `ptr` pointer with the given `layout`.
    ///
    /// # Safety
    ///
    /// This function is unsafe because undefined behavior can result
    /// if the caller does not ensure all of the following:
    ///
    /// * `ptr` must denote a block of memory currently allocated via
    ///   this allocator,
    ///
    /// * `layout` must be the same layout that was used
    ///   to allocate that block of memory,
    #[stable(feature = "global_alloc", since = "1.28.0")]
    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout);

    /// Behaves like `alloc`, but also ensures that the contents
    /// are set to zero before being returned.
    ///
    /// # Safety
    ///
    /// This function is unsafe for the same reasons that `alloc` is.
    /// However the allocated block of memory is guaranteed to be initialized.
    ///
    /// # Errors
    ///
    /// Returning a null pointer indicates that either memory is exhausted
    /// or `layout` does not meet allocator's size or alignment constraints,
    /// just as in `alloc`.
    ///
    /// Clients wishing to abort computation in response to an
    /// allocation error are encouraged to call the [`handle_alloc_error`] function,
    /// rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    #[stable(feature = "global_alloc", since = "1.28.0")]
    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
        let size = layout.size();
        // SAFETY: the safety contract for `alloc` must be upheld by the caller.
        let ptr = unsafe { self.alloc(layout) };
        if !ptr.is_null() {
            // SAFETY: as allocation succeeded, the region from `ptr`
            // of size `size` is guaranteed to be valid for writes.
            unsafe { ptr::write_bytes(ptr, 0, size) };
        }
        ptr
    }

    /// Shrink or grow a block of memory to the given `new_size`.
    /// The block is described by the given `ptr` pointer and `layout`.
    ///
    /// If this returns a non-null pointer, then ownership of the memory block
    /// referenced by `ptr` has been transferred to this allocator.
    /// The memory may or may not have been deallocated,
    /// and should be considered unusable (unless of course it was
    /// transferred back to the caller again via the return value of
    /// this method). The new memory block is allocated with `layout`, but
    /// with the `size` updated to `new_size`.
    ///
    /// If this method returns null, then ownership of the memory
    /// block has not been transferred to this allocator, and the
    /// contents of the memory block are unaltered.
    ///
    /// # Safety
    ///
    /// This function is unsafe because undefined behavior can result
    /// if the caller does not ensure all of the following:
    ///
    /// * `ptr` must be currently allocated via this allocator,
    ///
    /// * `layout` must be the same layout that was used
    ///   to allocate that block of memory,
    ///
    /// * `new_size` must be greater than zero.
    ///
    /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`,
    ///   must not overflow (i.e., the rounded value must be less than `usize::MAX`).
    ///
    /// (Extension subtraits might provide more specific bounds on
    /// behavior, e.g., guarantee a sentinel address or a null pointer
    /// in response to a zero-size allocation request.)
    ///
    /// # Errors
    ///
    /// Returns null if the new layout does not meet the size
    /// and alignment constraints of the allocator, or if reallocation
    /// otherwise fails.
    ///
    /// Implementations are encouraged to return null on memory
    /// exhaustion rather than panicking or aborting, but this is not
    /// a strict requirement. (Specifically: it is *legal* to
    /// implement this trait atop an underlying native allocation
    /// library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to a
    /// reallocation error are encouraged to call the [`handle_alloc_error`] function,
    /// rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    #[stable(feature = "global_alloc", since = "1.28.0")]
    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
        // SAFETY: the caller must ensure that the `new_size` does not overflow.
        // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid.
        let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
        // SAFETY: the caller must ensure that `new_layout` is greater than zero.
        let new_ptr = unsafe { self.alloc(new_layout) };
        if !new_ptr.is_null() {
            // SAFETY: the previously allocated block cannot overlap the newly allocated block.
            // The safety contract for `dealloc` must be upheld by the caller.
            unsafe {
                ptr::copy_nonoverlapping(ptr, new_ptr, cmp::min(layout.size(), new_size));
                self.dealloc(ptr, layout);
            }
        }
        new_ptr
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

pub struct Translator
{
	rules: HashMap<(char, char), char>,
}

impl Translator
{
	pub fn new() -> Translator
	{
		Translator
		{
			rules: get_default_rules(),
		}
	}

	fn translate_char(&self, current : char, previous : char) -> char
	{
		match self.rules.get(&(current, previous))
		{
			Some(result) => *result,
			None => match self.rules.get(&(current, ' '))
			{
				Some(result) => *result,
				None => current,
			}
		}
	}

	pub fn translate(&self, text : &str) -> String
	{
		let mut result = String::with_capacity(text.len());

		let mut previous = ' ';
		for c in text.chars()
		{
			previous = self.translate_char(c, previous);
			result.push(previous);
		}

		result
	}
}

fn get_default_rules() -> HashMap<(char, char), char>
{
	let mut result = HashMap::with_capacity(50);

	result.insert(('a', ' '), 'а');
	result.insert(('b', ' '), 'б');
	result.insert(('v', ' '), 'в');
	result.insert(('g', ' '), 'г');
	result.insert(('d', ' '), 'д');
	result.insert(('e', ' '), 'е');
	result.insert(('o', 'j'), 'ё');
	result.insert(('o', 'й'), 'ё');
	result.insert(('h', 'z'), 'ж');
	result.insert(('h', 'з'), 'ж');
	result.insert(('z', ' '), 'з');
	result.insert(('i', ' '), 'и');
	result.insert(('j', ' '), 'й');
	result.insert(('k', ' '), 'к');
	result.insert(('l', ' '), 'л');
	result.insert(('m', ' '), 'м');
	result.insert(('n', ' '), 'н');
	result.insert(('o', ' '), 'о');
	result.insert(('p', ' '), 'п');
	result.insert(('r', ' '), 'р');
	result.insert(('s', ' '), 'с');
	result.insert(('t', ' '), 'т');
	result.insert(('u', ' '), 'у');
	result.insert(('f', ' '), 'ф');
	result.insert(('h', ' '), 'х');
	result.insert(('x', ' '), 'х');
	result.insert(('c', ' '), 'ц');
	result.insert(('h', 'c'), 'ч');
	result.insert(('h', 'ц'), 'ч');
	result.insert(('h', 'h'), 'ш');
	result.insert(('h', 'с'), 'ш');
	result.insert(('h', 'ш'), 'щ');
	result.insert(('w', ' '), 'щ');
	result.insert(('#', ' '), 'ъ');
	result.insert(('y', ' '), 'ы');
	result.insert(('\'', ' '), 'ь');
	result.insert(('e', 'j'), 'э');
	result.insert(('e', 'й'), 'э');
	result.insert(('u', 'j'), 'ю');
	result.insert(('u', 'й'), 'ю');
	result.insert(('a', 'j'), 'я');
	result.insert(('a', 'й'), 'я');

	result.insert(('A', ' '), 'А');
	result.insert(('B', ' '), 'Б');
	result.insert(('V', ' '), 'В');
	result.insert(('G', ' '), 'Г');
	result.insert(('D', ' '), 'Д');
	result.insert(('E', ' '), 'Е');
	result.insert(('O', 'J'), 'Ё');
	result.insert(('O', 'Й'), 'Ё');
	result.insert(('H', 'Z'), 'Ж');
	result.insert(('H', 'З'), 'Ж');
	result.insert(('Z', ' '), 'З');
	result.insert(('I', ' '), 'И');
	result.insert(('J', ' '), 'Й');
	result.insert(('K', ' '), 'К');
	result.insert(('L', ' '), 'Л');
	result.insert(('M', ' '), 'М');
	result.insert(('N', ' '), 'Н');
	result.insert(('O', ' '), 'О');
	result.insert(('P', ' '), 'П');
	result.insert(('R', ' '), 'Р');
	result.insert(('S', ' '), 'С');
	result.insert(('T', ' '), 'Т');
	result.insert(('U', ' '), 'У');
	result.insert(('F', ' '), 'Ф');
	result.insert(('H', ' '), 'Х');
	result.insert(('X', ' '), 'Х');
	result.insert(('C', ' '), 'Ц');
	result.insert(('H', 'C'), 'Ч');
	result.insert(('H', 'Ц'), 'Ч');
	result.insert(('H', 'H'), 'Ш');
	result.insert(('H', 'С'), 'Ш');
	result.insert(('H', 'Ш'), 'Щ');
	result.insert(('W', ' '), 'Щ');
	result.insert(('#', 'ъ'), 'Ъ');
	result.insert(('Y', ' '), 'Ы');
	result.insert(('\'', 'ь'), 'Ь');
	result.insert(('E', 'J'), 'Э');
	result.insert(('E', 'Й'), 'Э');
	result.insert(('U', 'J'), 'Ю');
	result.insert(('U', 'Й'), 'Ю');
	result.insert(('A', 'J'), 'Я');
	result.insert(('A', 'Й'), 'Я');

	result
}
<commit_msg>Tests have been fixed<commit_after>use std::collections::HashMap;

pub struct Translator
{
	rules: HashMap<(char, char), char>,
}

impl Translator
{
	pub fn new() -> Translator
	{
		Translator
		{
			rules: get_default_rules(),
		}
	}

	// Returns translated characted and boolean value indicating that previous character should be erased.
	fn translate_char(&self, current : char, previous : char) -> (char, bool)
	{
		match self.rules.get(&(current, previous))
		{
			Some(result) => (*result, true),
			None => match self.rules.get(&(current, ' '))
			{
				Some(result) => (*result, false),
				None => (current, false),
			}
		}
	}

	pub fn translate(&self, text : &str) -> String
	{
		let mut result = String::with_capacity(text.len());

		let mut previous = ' ';
		for c in text.chars()
		{
			let (translated, erasePrevious) = self.translate_char(c, previous);
			if(erasePrevious)
			{
				result.pop();
			}

			result.push(translated);
			previous = translated;
		}

		result
	}
}

fn get_default_rules() -> HashMap<(char, char), char>
{
	let mut result = HashMap::with_capacity(50);

	result.insert(('a', ' '), 'а');
	result.insert(('b', ' '), 'б');
	result.insert(('v', ' '), 'в');
	result.insert(('g', ' '), 'г');
	result.insert(('d', ' '), 'д');
	result.insert(('e', ' '), 'е');
	result.insert(('o', 'j'), 'ё');
	result.insert(('o', 'й'), 'ё');
	result.insert(('h', 'z'), 'ж');
	result.insert(('h', 'з'), 'ж');
	result.insert(('z', ' '), 'з');
	result.insert(('i', ' '), 'и');
	result.insert(('j', ' '), 'й');
	result.insert(('k', ' '), 'к');
	result.insert(('l', ' '), 'л');
	result.insert(('m', ' '), 'м');
	result.insert(('n', ' '), 'н');
	result.insert(('o', ' '), 'о');
	result.insert(('p', ' '), 'п');
	result.insert(('r', ' '), 'р');
	result.insert(('s', ' '), 'с');
	result.insert(('t', ' '), 'т');
	result.insert(('u', ' '), 'у');
	result.insert(('f', ' '), 'ф');
	result.insert(('h', ' '), 'х');
	result.insert(('x', ' '), 'х');
	result.insert(('c', ' '), 'ц');
	result.insert(('h', 'c'), 'ч');
	result.insert(('h', 'ц'), 'ч');
	result.insert(('h', 'h'), 'ш');
	result.insert(('h', 'с'), 'ш');
	result.insert(('h', 'ш'), 'щ');
	result.insert(('w', ' '), 'щ');
	result.insert(('#', ' '), 'ъ');
	result.insert(('y', ' '), 'ы');
	result.insert(('\'', ' '), 'ь');
	result.insert(('e', 'j'), 'э');
	result.insert(('e', 'й'), 'э');
	result.insert(('u', 'j'), 'ю');
	result.insert(('u', 'й'), 'ю');
	result.insert(('a', 'j'), 'я');
	result.insert(('a', 'й'), 'я');

	result.insert(('A', ' '), 'А');
	result.insert(('B', ' '), 'Б');
	result.insert(('V', ' '), 'В');
	result.insert(('G', ' '), 'Г');
	result.insert(('D', ' '), 'Д');
	result.insert(('E', ' '), 'Е');
	result.insert(('O', 'J'), 'Ё');
	result.insert(('O', 'Й'), 'Ё');
	result.insert(('H', 'Z'), 'Ж');
	result.insert(('H', 'З'), 'Ж');
	result.insert(('Z', ' '), 'З');
	result.insert(('I', ' '), 'И');
	result.insert(('J', ' '), 'Й');
	result.insert(('K', ' '), 'К');
	result.insert(('L', ' '), 'Л');
	result.insert(('M', ' '), 'М');
	result.insert(('N', ' '), 'Н');
	result.insert(('O', ' '), 'О');
	result.insert(('P', ' '), 'П');
	result.insert(('R', ' '), 'Р');
	result.insert(('S', ' '), 'С');
	result.insert(('T', ' '), 'Т');
	result.insert(('U', ' '), 'У');
	result.insert(('F', ' '), 'Ф');
	result.insert(('H', ' '), 'Х');
	result.insert(('X', ' '), 'Х');
	result.insert(('C', ' '), 'Ц');
	result.insert(('H', 'C'), 'Ч');
	result.insert(('H', 'Ц'), 'Ч');
	result.insert(('H', 'H'), 'Ш');
	result.insert(('H', 'С'), 'Ш');
	result.insert(('H', 'Ш'), 'Щ');
	result.insert(('W', ' '), 'Щ');
	result.insert(('#', 'ъ'), 'Ъ');
	result.insert(('Y', ' '), 'Ы');
	result.insert(('\'', 'ь'), 'Ь');
	result.insert(('E', 'J'), 'Э');
	result.insert(('E', 'Й'), 'Э');
	result.insert(('U', 'J'), 'Ю');
	result.insert(('U', 'Й'), 'Ю');
	result.insert(('A', 'J'), 'Я');
	result.insert(('A', 'Й'), 'Я');

	result
}
<|endoftext|>


<commit_before><commit_msg>cea608overlay: Handle errors when rendering captions more gracefully<commit_after><|endoftext|>


<commit_before>include!(concat!(env!("OUT_DIR"), "/count.rs"));

#[doc(hidden)]
#[macro_export]
macro_rules! dispatch {
    (() $($bang:tt)*) => {
        $crate::count!($($bang)*)
    };
    ((($($first:tt)*) $($rest:tt)*) $($bang:tt)*) => {
        $crate::dispatch!(($($first)* $($rest)*) $($bang)*)
    };
    (([$($first:tt)*] $($rest:tt)*) $($bang:tt)*) => {
        $crate::dispatch!(($($first)* $($rest)*) $($bang)*)
    };
    (({$($first:tt)*} $($rest:tt)*) $($bang:tt)*) => {
        $crate::dispatch!(($($first)* $($rest)*) $($bang)*)
    };
    ((! $($rest:tt)*) $($bang:tt)*) => {
        $crate::dispatch!(($($rest)*) $($bang)* !)
    };
    (($first:tt $($rest:tt)*) $($bang:tt)*) => {
        $crate::dispatch!(($($rest)*) $($bang)*)
    };
}
<commit_msg>Document proc-macro-nested<commit_after>//! Support for nested invocations of proc-macro-hack expression macros.
//!
//! By default, macros defined through proc-macro-hack do not support nested
//! invocations, i.e. the code emitted by a proc-macro-hack macro invocation
//! cannot contain recursive calls to the same proc-macro-hack macro nor calls
//! to any other proc-macro-hack macros.
//!
//! This crate provides opt-in support for such nested invocations.
//!
//! To make a macro callable recursively, add a dependency on this crate from
//! your declaration crate and update the `#[proc_macro_hack]` re-export as
//! follows.
//!
//! ```rust
//! // Before
//! # const IGNORE: &str = stringify! {
//! #[proc_macro_hack]
//! pub use demo_hack_impl::add_one;
//! # }
//! ```
//!
//! ```rust
//! // After
//! # const IGNORE: &str = stringify! {
//! extern crate proc_macro_nested;
//!
//! #[proc_macro_hack(support_nested)]
//! pub use demo_hack_impl::add_one;
//! # }
//! ```
//!
//! No change is required within your definition crate, only in the declaration
//! crate.

include!(concat!(env!("OUT_DIR"), "/count.rs"));

#[doc(hidden)]
#[macro_export]
macro_rules! dispatch {
    (() $($bang:tt)*) => {
        $crate::count!($($bang)*)
    };
    ((($($first:tt)*) $($rest:tt)*) $($bang:tt)*) => {
        $crate::dispatch!(($($first)* $($rest)*) $($bang)*)
    };
    (([$($first:tt)*] $($rest:tt)*) $($bang:tt)*) => {
        $crate::dispatch!(($($first)* $($rest)*) $($bang)*)
    };
    (({$($first:tt)*} $($rest:tt)*) $($bang:tt)*) => {
        $crate::dispatch!(($($first)* $($rest)*) $($bang)*)
    };
    ((! $($rest:tt)*) $($bang:tt)*) => {
        $crate::dispatch!(($($rest)*) $($bang)* !)
    };
    (($first:tt $($rest:tt)*) $($bang:tt)*) => {
        $crate::dispatch!(($($rest)*) $($bang)*)
    };
}
<|endoftext|>