<commit_before>use clippy_utils::diagnostics::span_lint_and_note;
use clippy_utils::{match_def_path, paths};
use rustc_hir::def_id::DefId;
use rustc_hir::{AsyncGeneratorKind, Body, BodyId, GeneratorKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::GeneratorInteriorTypeCause;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// ### What it does
    /// Checks for calls to await while holding a
    /// non-async-aware MutexGuard.
    ///
    /// ### Why is this bad?
    /// The Mutex types found in std::sync and parking_lot
    /// are not designed to operate in an async context across await points.
    ///
    /// There are two potential solutions. One is to use an asynx-aware Mutex
    /// type. Many asynchronous foundation crates provide such a Mutex type. The
    /// other solution is to ensure the mutex is unlocked before calling await,
    /// either by introducing a scope or an explicit call to Drop::drop.
    ///
    /// ### Known problems
    /// Will report false positive for explicitly dropped guards ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)).
    ///
    /// ### Example
    /// ```rust,ignore
    /// use std::sync::Mutex;
    ///
    /// async fn foo(x: &Mutex<u32>) {
    ///   let guard = x.lock().unwrap();
    ///   *guard += 1;
    ///   bar.await;
    /// }
    /// ```
    ///
    /// Use instead:
    /// ```rust,ignore
    /// use std::sync::Mutex;
    ///
    /// async fn foo(x: &Mutex<u32>) {
    ///   {
    ///     let guard = x.lock().unwrap();
    ///     *guard += 1;
    ///   }
    ///   bar.await;
    /// }
    /// ```
    pub AWAIT_HOLDING_LOCK,
    pedantic,
    "Inside an async function, holding a MutexGuard while calling await"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for calls to await while holding a
    /// `RefCell` `Ref` or `RefMut`.
    ///
    /// ### Why is this bad?
    /// `RefCell` refs only check for exclusive mutable access
    /// at runtime. Holding onto a `RefCell` ref across an `await` suspension point
    /// risks panics from a mutable ref shared while other refs are outstanding.
    ///
    /// ### Known problems
    /// Will report false positive for explicitly dropped refs ([#6353](https://github.com/rust-lang/rust-clippy/issues/6353)).
    ///
    /// ### Example
    /// ```rust,ignore
    /// use std::cell::RefCell;
    ///
    /// async fn foo(x: &RefCell<u32>) {
    ///   let mut y = x.borrow_mut();
    ///   *y += 1;
    ///   bar.await;
    /// }
    /// ```
    ///
    /// Use instead:
    /// ```rust,ignore
    /// use std::cell::RefCell;
    ///
    /// async fn foo(x: &RefCell<u32>) {
    ///   {
    ///      let mut y = x.borrow_mut();
    ///      *y += 1;
    ///   }
    ///   bar.await;
    /// }
    /// ```
    pub AWAIT_HOLDING_REFCELL_REF,
    pedantic,
    "Inside an async function, holding a RefCell ref while calling await"
}

declare_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF]);

impl LateLintPass<'_> for AwaitHolding {
    fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
        use AsyncGeneratorKind::{Block, Closure, Fn};
        if let Some(GeneratorKind::Async(Block | Closure | Fn)) = body.generator_kind {
            let body_id = BodyId {
                hir_id: body.value.hir_id,
            };
            let typeck_results = cx.tcx.typeck_body(body_id);
            check_interior_types(
                cx,
                typeck_results.generator_interior_types.as_ref().skip_binder(),
                body.value.span,
            );
        }
    }
}

fn check_interior_types(cx: &LateContext<'_>, ty_causes: &[GeneratorInteriorTypeCause<'_>], span: Span) {
    for ty_cause in ty_causes {
        if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() {
            if is_mutex_guard(cx, adt.did) {
                span_lint_and_note(
                    cx,
                    AWAIT_HOLDING_LOCK,
                    ty_cause.span,
                    "this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await",
                    ty_cause.scope_span.or(Some(span)),
                    "these are all the await points this lock is held through",
                );
            }
            if is_refcell_ref(cx, adt.did) {
                span_lint_and_note(
                    cx,
                    AWAIT_HOLDING_REFCELL_REF,
                    ty_cause.span,
                    "this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await",
                    ty_cause.scope_span.or(Some(span)),
                    "these are all the await points this ref is held through",
                );
            }
        }
    }
}

fn is_mutex_guard(cx: &LateContext<'_>, def_id: DefId) -> bool {
    match_def_path(cx, def_id, &paths::MUTEX_GUARD)
        || match_def_path(cx, def_id, &paths::RWLOCK_READ_GUARD)
        || match_def_path(cx, def_id, &paths::RWLOCK_WRITE_GUARD)
        || match_def_path(cx, def_id, &paths::PARKING_LOT_MUTEX_GUARD)
        || match_def_path(cx, def_id, &paths::PARKING_LOT_RWLOCK_READ_GUARD)
        || match_def_path(cx, def_id, &paths::PARKING_LOT_RWLOCK_WRITE_GUARD)
}

fn is_refcell_ref(cx: &LateContext<'_>, def_id: DefId) -> bool {
    match_def_path(cx, def_id, &paths::REFCELL_REF) || match_def_path(cx, def_id, &paths::REFCELL_REFMUT)
}
<commit_msg>Fix typo ("asynx" corrected to "async")<commit_after>use clippy_utils::diagnostics::span_lint_and_note;
use clippy_utils::{match_def_path, paths};
use rustc_hir::def_id::DefId;
use rustc_hir::{AsyncGeneratorKind, Body, BodyId, GeneratorKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::GeneratorInteriorTypeCause;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// ### What it does
    /// Checks for calls to await while holding a
    /// non-async-aware MutexGuard.
    ///
    /// ### Why is this bad?
    /// The Mutex types found in std::sync and parking_lot
    /// are not designed to operate in an async context across await points.
    ///
    /// There are two potential solutions. One is to use an async-aware Mutex
    /// type. Many asynchronous foundation crates provide such a Mutex type. The
    /// other solution is to ensure the mutex is unlocked before calling await,
    /// either by introducing a scope or an explicit call to Drop::drop.
    ///
    /// ### Known problems
    /// Will report false positive for explicitly dropped guards ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)).
    ///
    /// ### Example
    /// ```rust,ignore
    /// use std::sync::Mutex;
    ///
    /// async fn foo(x: &Mutex<u32>) {
    ///   let guard = x.lock().unwrap();
    ///   *guard += 1;
    ///   bar.await;
    /// }
    /// ```
    ///
    /// Use instead:
    /// ```rust,ignore
    /// use std::sync::Mutex;
    ///
    /// async fn foo(x: &Mutex<u32>) {
    ///   {
    ///     let guard = x.lock().unwrap();
    ///     *guard += 1;
    ///   }
    ///   bar.await;
    /// }
    /// ```
    pub AWAIT_HOLDING_LOCK,
    pedantic,
    "Inside an async function, holding a MutexGuard while calling await"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for calls to await while holding a
    /// `RefCell` `Ref` or `RefMut`.
    ///
    /// ### Why is this bad?
    /// `RefCell` refs only check for exclusive mutable access
    /// at runtime. Holding onto a `RefCell` ref across an `await` suspension point
    /// risks panics from a mutable ref shared while other refs are outstanding.
    ///
    /// ### Known problems
    /// Will report false positive for explicitly dropped refs ([#6353](https://github.com/rust-lang/rust-clippy/issues/6353)).
    ///
    /// ### Example
    /// ```rust,ignore
    /// use std::cell::RefCell;
    ///
    /// async fn foo(x: &RefCell<u32>) {
    ///   let mut y = x.borrow_mut();
    ///   *y += 1;
    ///   bar.await;
    /// }
    /// ```
    ///
    /// Use instead:
    /// ```rust,ignore
    /// use std::cell::RefCell;
    ///
    /// async fn foo(x: &RefCell<u32>) {
    ///   {
    ///      let mut y = x.borrow_mut();
    ///      *y += 1;
    ///   }
    ///   bar.await;
    /// }
    /// ```
    pub AWAIT_HOLDING_REFCELL_REF,
    pedantic,
    "Inside an async function, holding a RefCell ref while calling await"
}

declare_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF]);

impl LateLintPass<'_> for AwaitHolding {
    fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
        use AsyncGeneratorKind::{Block, Closure, Fn};
        if let Some(GeneratorKind::Async(Block | Closure | Fn)) = body.generator_kind {
            let body_id = BodyId {
                hir_id: body.value.hir_id,
            };
            let typeck_results = cx.tcx.typeck_body(body_id);
            check_interior_types(
                cx,
                typeck_results.generator_interior_types.as_ref().skip_binder(),
                body.value.span,
            );
        }
    }
}

fn check_interior_types(cx: &LateContext<'_>, ty_causes: &[GeneratorInteriorTypeCause<'_>], span: Span) {
    for ty_cause in ty_causes {
        if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() {
            if is_mutex_guard(cx, adt.did) {
                span_lint_and_note(
                    cx,
                    AWAIT_HOLDING_LOCK,
                    ty_cause.span,
                    "this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await",
                    ty_cause.scope_span.or(Some(span)),
                    "these are all the await points this lock is held through",
                );
            }
            if is_refcell_ref(cx, adt.did) {
                span_lint_and_note(
                    cx,
                    AWAIT_HOLDING_REFCELL_REF,
                    ty_cause.span,
                    "this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await",
                    ty_cause.scope_span.or(Some(span)),
                    "these are all the await points this ref is held through",
                );
            }
        }
    }
}

fn is_mutex_guard(cx: &LateContext<'_>, def_id: DefId) -> bool {
    match_def_path(cx, def_id, &paths::MUTEX_GUARD)
        || match_def_path(cx, def_id, &paths::RWLOCK_READ_GUARD)
        || match_def_path(cx, def_id, &paths::RWLOCK_WRITE_GUARD)
        || match_def_path(cx, def_id, &paths::PARKING_LOT_MUTEX_GUARD)
        || match_def_path(cx, def_id, &paths::PARKING_LOT_RWLOCK_READ_GUARD)
        || match_def_path(cx, def_id, &paths::PARKING_LOT_RWLOCK_WRITE_GUARD)
}

fn is_refcell_ref(cx: &LateContext<'_>, def_id: DefId) -> bool {
    match_def_path(cx, def_id, &paths::REFCELL_REF) || match_def_path(cx, def_id, &paths::REFCELL_REFMUT)
}
<|endoftext|>


<commit_before>use crate::utils::span_lint_and_help;
use if_chain::if_chain;
use rustc_ast::ast::{Param, TyKind};
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:** The lint checks for `self` fn fn parameters that explicitly
    /// specify the `Self`-type explicitly
    /// **Why is this bad?** Increases the amount and decreases the readability of code
    ///
    /// **Known problems:** None
    ///
    /// **Example:**
    /// ```rust
    /// impl ValType {
    ///     pub fn bytes(self: Self) -> usize {
    ///         match self {
    ///             Self::I32 | Self::F32 => 4,
    ///             Self::I64 | Self::F64 => 8,
    ///         }
    ///     }
    /// }
    /// ```
    ///
    /// Could be rewritten as
    ///
    /// ```rust
    /// impl ValType {
    ///     pub fn bytes(self) -> usize {
    ///         match self {
    ///             Self::I32 | Self::F32 => 4,
    ///             Self::I64 | Self::F64 => 8,
    ///         }
    ///     }
    /// }
    /// ```
    pub NEEDLESS_FN_SELF_TYPE,
    style,
    "type of `self` parameter is already by default `Self`"
}

declare_lint_pass!(NeedlessFnSelfType => [NEEDLESS_FN_SELF_TYPE]);

impl EarlyLintPass for NeedlessFnSelfType {
    fn check_param(&mut self, cx: &EarlyContext<'_>, p: &Param) {
        if_chain! {
            if p.is_self();
            if let TyKind::Path(None, path) = &p.ty.kind;
            if let Some(segment) = path.segments.first();
            if segment.ident.as_str() == sym!(Self).as_str();
            then {
                span_lint_and_help(
                    cx,
                    NEEDLESS_FN_SELF_TYPE,
                    p.ty.span,
                    "the type of the `self` parameter is already by default `Self`",
                    None,
                    "consider removing the type specification",
                );
            }
        }
    }
}
<commit_msg>fix doc<commit_after>use crate::utils::span_lint_and_help;
use if_chain::if_chain;
use rustc_ast::ast::{Param, TyKind};
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:** The lint checks for `self` fn fn parameters that explicitly
    /// specify the `Self`-type explicitly
    /// **Why is this bad?** Increases the amount and decreases the readability of code
    ///
    /// **Known problems:** None
    ///
    /// **Example:**
    /// ```rust
    /// enum ValType {
    ///     I32,
    ///     I64,
    ///     F32,
    ///     F64,
    /// }
    ///
    /// impl ValType {
    ///     pub fn bytes(self: Self) -> usize {
    ///         match self {
    ///             Self::I32 | Self::F32 => 4,
    ///             Self::I64 | Self::F64 => 8,
    ///         }
    ///     }
    /// }
    /// ```
    ///
    /// Could be rewritten as
    ///
    /// ```rust
    /// enum ValType {
    ///     I32,
    ///     I64,
    ///     F32,
    ///     F64,
    /// }
    ///
    /// impl ValType {
    ///     pub fn bytes(self) -> usize {
    ///         match self {
    ///             Self::I32 | Self::F32 => 4,
    ///             Self::I64 | Self::F64 => 8,
    ///         }
    ///     }
    /// }
    /// ```
    pub NEEDLESS_FN_SELF_TYPE,
    style,
    "type of `self` parameter is already by default `Self`"
}

declare_lint_pass!(NeedlessFnSelfType => [NEEDLESS_FN_SELF_TYPE]);

impl EarlyLintPass for NeedlessFnSelfType {
    fn check_param(&mut self, cx: &EarlyContext<'_>, p: &Param) {
        if_chain! {
            if p.is_self();
            if let TyKind::Path(None, path) = &p.ty.kind;
            if let Some(segment) = path.segments.first();
            if segment.ident.as_str() == sym!(Self).as_str();
            then {
                span_lint_and_help(
                    cx,
                    NEEDLESS_FN_SELF_TYPE,
                    p.ty.span,
                    "the type of the `self` parameter is already by default `Self`",
                    None,
                    "consider removing the type specification",
                );
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::utils::{last_path_segment, span_lint_and_help};
use rustc_hir::{
    intravisit, Body, Expr, ExprKind, FieldPat, FnDecl, HirId, LocalSource, MatchSource, Mutability, Pat, PatKind,
    QPath, Stmt, StmtKind,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{AdtDef, FieldDef, Ty, TyKind, VariantDef};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for patterns that aren't exact representations of the types
    /// they are applied to.
    ///
    /// **Why is this bad?** It isn't bad in general. But in some contexts it can be desirable
    /// because it increases ownership hints in the code, and will guard against some changes
    /// in ownership.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust,ignore
    /// // Bad
    /// let value = &Some(Box::new(23));
    /// match value {
    ///     Some(inner) => println!("{}", inner),
    ///     None => println!("none"),
    /// }
    ///
    /// // Good
    /// let value = &Some(Box::new(23));
    /// match *value {
    ///     Some(ref inner) => println!("{}", inner),
    ///     None => println!("none"),
    /// }
    /// ```
    pub PATTERN_TYPE_MISMATCH,
    restriction,
    "type of pattern does not match the expression type"
}

declare_lint_pass!(PatternTypeMismatch => [PATTERN_TYPE_MISMATCH]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PatternTypeMismatch {
    fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt<'_>) {
        if let StmtKind::Local(ref local) = stmt.kind {
            if let Some(init) = &local.init {
                if let Some(init_ty) = cx.tables.node_type_opt(init.hir_id) {
                    let pat = &local.pat;
                    if in_external_macro(cx.sess(), pat.span) {
                        return;
                    }
                    let deref_possible = match local.source {
                        LocalSource::Normal => DerefPossible::Possible,
                        _ => DerefPossible::Impossible,
                    };
                    apply_lint(cx, pat, init_ty, deref_possible);
                }
            }
        }
    }

    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
        if let ExprKind::Match(ref expr, arms, source) = expr.kind {
            match source {
                MatchSource::Normal | MatchSource::IfLetDesugar { .. } | MatchSource::WhileLetDesugar => {
                    if let Some(expr_ty) = cx.tables.node_type_opt(expr.hir_id) {
                        'pattern_checks: for arm in arms {
                            let pat = &arm.pat;
                            if in_external_macro(cx.sess(), pat.span) {
                                continue 'pattern_checks;
                            }
                            if apply_lint(cx, pat, expr_ty, DerefPossible::Possible) {
                                break 'pattern_checks;
                            }
                        }
                    }
                },
                _ => (),
            }
        }
    }

    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        _: intravisit::FnKind<'tcx>,
        _: &'tcx FnDecl<'_>,
        body: &'tcx Body<'_>,
        _: Span,
        hir_id: HirId,
    ) {
        if let Some(fn_sig) = cx.tables.liberated_fn_sigs().get(hir_id) {
            for (param, ty) in body.params.iter().zip(fn_sig.inputs().iter()) {
                apply_lint(cx, &param.pat, ty, DerefPossible::Impossible);
            }
        }
    }
}

#[derive(Debug, Clone, Copy)]
enum DerefPossible {
    Possible,
    Impossible,
}

fn apply_lint<'a, 'tcx>(
    cx: &LateContext<'a, 'tcx>,
    pat: &Pat<'_>,
    expr_ty: Ty<'tcx>,
    deref_possible: DerefPossible,
) -> bool {
    let maybe_mismatch = find_first_mismatch(cx, pat, expr_ty, Level::Top);
    if let Some((span, mutability, level)) = maybe_mismatch {
        span_lint_and_help(
            cx,
            PATTERN_TYPE_MISMATCH,
            span,
            "type of pattern does not match the expression type",
            None,
            &format!(
                "{}explicitly match against a `{}` pattern and adjust the enclosed variable bindings",
                match (deref_possible, level) {
                    (DerefPossible::Possible, Level::Top) => "use `*` to dereference the match expression or ",
                    _ => "",
                },
                match mutability {
                    Mutability::Mut => "&mut _",
                    Mutability::Not => "&_",
                },
            ),
        );
        true
    } else {
        false
    }
}

#[derive(Debug, Copy, Clone)]
enum Level {
    Top,
    Lower,
}

#[allow(rustc::usage_of_ty_tykind)]
fn find_first_mismatch<'a, 'tcx>(
    cx: &LateContext<'a, 'tcx>,
    pat: &Pat<'_>,
    ty: Ty<'tcx>,
    level: Level,
) -> Option<(Span, Mutability, Level)> {
    if let PatKind::Ref(ref sub_pat, _) = pat.kind {
        if let TyKind::Ref(_, sub_ty, _) = ty.kind {
            return find_first_mismatch(cx, sub_pat, sub_ty, Level::Lower);
        }
    }

    if let TyKind::Ref(_, _, mutability) = ty.kind {
        if is_non_ref_pattern(&pat.kind) {
            return Some((pat.span, mutability, level));
        }
    }

    if let PatKind::Struct(ref qpath, ref field_pats, _) = pat.kind {
        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind {
            if let Some(variant) = get_variant(adt_def, qpath) {
                let field_defs = &variant.fields;
                return find_first_mismatch_in_struct(cx, field_pats, field_defs, substs_ref);
            }
        }
    }

    if let PatKind::TupleStruct(ref qpath, ref pats, _) = pat.kind {
        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind {
            if let Some(variant) = get_variant(adt_def, qpath) {
                let field_defs = &variant.fields;
                let ty_iter = field_defs.iter().map(|field_def| field_def.ty(cx.tcx, substs_ref));
                return find_first_mismatch_in_tuple(cx, pats, ty_iter);
            }
        }
    }

    if let PatKind::Tuple(ref pats, _) = pat.kind {
        if let TyKind::Tuple(..) = ty.kind {
            return find_first_mismatch_in_tuple(cx, pats, ty.tuple_fields());
        }
    }

    if let PatKind::Or(sub_pats) = pat.kind {
        for pat in sub_pats {
            let maybe_mismatch = find_first_mismatch(cx, pat, ty, level);
            if let Some(mismatch) = maybe_mismatch {
                return Some(mismatch);
            }
        }
    }

    None
}

fn get_variant<'a>(adt_def: &'a AdtDef, qpath: &QPath<'_>) -> Option<&'a VariantDef> {
    if adt_def.is_struct() {
        if let Some(variant) = adt_def.variants.iter().next() {
            return Some(variant);
        }
    }

    if adt_def.is_enum() {
        let pat_ident = last_path_segment(qpath).ident;
        for variant in &adt_def.variants {
            if variant.ident == pat_ident {
                return Some(variant);
            }
        }
    }

    None
}

fn find_first_mismatch_in_tuple<'a, 'tcx, I>(
    cx: &LateContext<'a, 'tcx>,
    pats: &[&Pat<'_>],
    ty_iter_src: I,
) -> Option<(Span, Mutability, Level)>
where
    I: IntoIterator<Item = Ty<'tcx>>,
{
    let mut field_tys = ty_iter_src.into_iter();
    'fields: for pat in pats {
        let field_ty = if let Some(ty) = field_tys.next() {
            ty
        } else {
            break 'fields;
        };

        let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower);
        if let Some(mismatch) = maybe_mismatch {
            return Some(mismatch);
        }
    }

    None
}

fn find_first_mismatch_in_struct<'a, 'tcx>(
    cx: &LateContext<'a, 'tcx>,
    field_pats: &[FieldPat<'_>],
    field_defs: &[FieldDef],
    substs_ref: SubstsRef<'tcx>,
) -> Option<(Span, Mutability, Level)> {
    for field_pat in field_pats {
        'definitions: for field_def in field_defs {
            if field_pat.ident == field_def.ident {
                let field_ty = field_def.ty(cx.tcx, substs_ref);
                let pat = &field_pat.pat;
                let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower);
                if let Some(mismatch) = maybe_mismatch {
                    return Some(mismatch);
                }
                break 'definitions;
            }
        }
    }

    None
}

fn is_non_ref_pattern(pat_kind: &PatKind<'_>) -> bool {
    match pat_kind {
        PatKind::Struct(..) | PatKind::Tuple(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => true,
        PatKind::Or(sub_pats) => sub_pats.iter().any(|pat| is_non_ref_pattern(&pat.kind)),
        _ => false,
    }
}
<commit_msg>Catching up with rustc changes<commit_after>use crate::utils::{last_path_segment, span_lint_and_help};
use rustc_hir::{
    intravisit, Body, Expr, ExprKind, FieldPat, FnDecl, HirId, LocalSource, MatchSource, Mutability, Pat, PatKind,
    QPath, Stmt, StmtKind,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{AdtDef, FieldDef, Ty, TyKind, VariantDef};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for patterns that aren't exact representations of the types
    /// they are applied to.
    ///
    /// **Why is this bad?** It isn't bad in general. But in some contexts it can be desirable
    /// because it increases ownership hints in the code, and will guard against some changes
    /// in ownership.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust,ignore
    /// // Bad
    /// let value = &Some(Box::new(23));
    /// match value {
    ///     Some(inner) => println!("{}", inner),
    ///     None => println!("none"),
    /// }
    ///
    /// // Good
    /// let value = &Some(Box::new(23));
    /// match *value {
    ///     Some(ref inner) => println!("{}", inner),
    ///     None => println!("none"),
    /// }
    /// ```
    pub PATTERN_TYPE_MISMATCH,
    restriction,
    "type of pattern does not match the expression type"
}

declare_lint_pass!(PatternTypeMismatch => [PATTERN_TYPE_MISMATCH]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PatternTypeMismatch {
    fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt<'_>) {
        if let StmtKind::Local(ref local) = stmt.kind {
            if let Some(init) = &local.init {
                if let Some(init_ty) = cx.tables().node_type_opt(init.hir_id) {
                    let pat = &local.pat;
                    if in_external_macro(cx.sess(), pat.span) {
                        return;
                    }
                    let deref_possible = match local.source {
                        LocalSource::Normal => DerefPossible::Possible,
                        _ => DerefPossible::Impossible,
                    };
                    apply_lint(cx, pat, init_ty, deref_possible);
                }
            }
        }
    }

    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
        if let ExprKind::Match(ref expr, arms, source) = expr.kind {
            match source {
                MatchSource::Normal | MatchSource::IfLetDesugar { .. } | MatchSource::WhileLetDesugar => {
                    if let Some(expr_ty) = cx.tables().node_type_opt(expr.hir_id) {
                        'pattern_checks: for arm in arms {
                            let pat = &arm.pat;
                            if in_external_macro(cx.sess(), pat.span) {
                                continue 'pattern_checks;
                            }
                            if apply_lint(cx, pat, expr_ty, DerefPossible::Possible) {
                                break 'pattern_checks;
                            }
                        }
                    }
                },
                _ => (),
            }
        }
    }

    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        _: intravisit::FnKind<'tcx>,
        _: &'tcx FnDecl<'_>,
        body: &'tcx Body<'_>,
        _: Span,
        hir_id: HirId,
    ) {
        if let Some(fn_sig) = cx.tables().liberated_fn_sigs().get(hir_id) {
            for (param, ty) in body.params.iter().zip(fn_sig.inputs().iter()) {
                apply_lint(cx, &param.pat, ty, DerefPossible::Impossible);
            }
        }
    }
}

#[derive(Debug, Clone, Copy)]
enum DerefPossible {
    Possible,
    Impossible,
}

fn apply_lint<'a, 'tcx>(
    cx: &LateContext<'a, 'tcx>,
    pat: &Pat<'_>,
    expr_ty: Ty<'tcx>,
    deref_possible: DerefPossible,
) -> bool {
    let maybe_mismatch = find_first_mismatch(cx, pat, expr_ty, Level::Top);
    if let Some((span, mutability, level)) = maybe_mismatch {
        span_lint_and_help(
            cx,
            PATTERN_TYPE_MISMATCH,
            span,
            "type of pattern does not match the expression type",
            None,
            &format!(
                "{}explicitly match against a `{}` pattern and adjust the enclosed variable bindings",
                match (deref_possible, level) {
                    (DerefPossible::Possible, Level::Top) => "use `*` to dereference the match expression or ",
                    _ => "",
                },
                match mutability {
                    Mutability::Mut => "&mut _",
                    Mutability::Not => "&_",
                },
            ),
        );
        true
    } else {
        false
    }
}

#[derive(Debug, Copy, Clone)]
enum Level {
    Top,
    Lower,
}

#[allow(rustc::usage_of_ty_tykind)]
fn find_first_mismatch<'a, 'tcx>(
    cx: &LateContext<'a, 'tcx>,
    pat: &Pat<'_>,
    ty: Ty<'tcx>,
    level: Level,
) -> Option<(Span, Mutability, Level)> {
    if let PatKind::Ref(ref sub_pat, _) = pat.kind {
        if let TyKind::Ref(_, sub_ty, _) = ty.kind {
            return find_first_mismatch(cx, sub_pat, sub_ty, Level::Lower);
        }
    }

    if let TyKind::Ref(_, _, mutability) = ty.kind {
        if is_non_ref_pattern(&pat.kind) {
            return Some((pat.span, mutability, level));
        }
    }

    if let PatKind::Struct(ref qpath, ref field_pats, _) = pat.kind {
        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind {
            if let Some(variant) = get_variant(adt_def, qpath) {
                let field_defs = &variant.fields;
                return find_first_mismatch_in_struct(cx, field_pats, field_defs, substs_ref);
            }
        }
    }

    if let PatKind::TupleStruct(ref qpath, ref pats, _) = pat.kind {
        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind {
            if let Some(variant) = get_variant(adt_def, qpath) {
                let field_defs = &variant.fields;
                let ty_iter = field_defs.iter().map(|field_def| field_def.ty(cx.tcx, substs_ref));
                return find_first_mismatch_in_tuple(cx, pats, ty_iter);
            }
        }
    }

    if let PatKind::Tuple(ref pats, _) = pat.kind {
        if let TyKind::Tuple(..) = ty.kind {
            return find_first_mismatch_in_tuple(cx, pats, ty.tuple_fields());
        }
    }

    if let PatKind::Or(sub_pats) = pat.kind {
        for pat in sub_pats {
            let maybe_mismatch = find_first_mismatch(cx, pat, ty, level);
            if let Some(mismatch) = maybe_mismatch {
                return Some(mismatch);
            }
        }
    }

    None
}

fn get_variant<'a>(adt_def: &'a AdtDef, qpath: &QPath<'_>) -> Option<&'a VariantDef> {
    if adt_def.is_struct() {
        if let Some(variant) = adt_def.variants.iter().next() {
            return Some(variant);
        }
    }

    if adt_def.is_enum() {
        let pat_ident = last_path_segment(qpath).ident;
        for variant in &adt_def.variants {
            if variant.ident == pat_ident {
                return Some(variant);
            }
        }
    }

    None
}

fn find_first_mismatch_in_tuple<'a, 'tcx, I>(
    cx: &LateContext<'a, 'tcx>,
    pats: &[&Pat<'_>],
    ty_iter_src: I,
) -> Option<(Span, Mutability, Level)>
where
    I: IntoIterator<Item = Ty<'tcx>>,
{
    let mut field_tys = ty_iter_src.into_iter();
    'fields: for pat in pats {
        let field_ty = if let Some(ty) = field_tys.next() {
            ty
        } else {
            break 'fields;
        };

        let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower);
        if let Some(mismatch) = maybe_mismatch {
            return Some(mismatch);
        }
    }

    None
}

fn find_first_mismatch_in_struct<'a, 'tcx>(
    cx: &LateContext<'a, 'tcx>,
    field_pats: &[FieldPat<'_>],
    field_defs: &[FieldDef],
    substs_ref: SubstsRef<'tcx>,
) -> Option<(Span, Mutability, Level)> {
    for field_pat in field_pats {
        'definitions: for field_def in field_defs {
            if field_pat.ident == field_def.ident {
                let field_ty = field_def.ty(cx.tcx, substs_ref);
                let pat = &field_pat.pat;
                let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower);
                if let Some(mismatch) = maybe_mismatch {
                    return Some(mismatch);
                }
                break 'definitions;
            }
        }
    }

    None
}

fn is_non_ref_pattern(pat_kind: &PatKind<'_>) -> bool {
    match pat_kind {
        PatKind::Struct(..) | PatKind::Tuple(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => true,
        PatKind::Or(sub_pats) => sub_pats.iter().any(|pat| is_non_ref_pattern(&pat.kind)),
        _ => false,
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate base64;
extern crate test;
extern crate rand;

use base64::{decode, decode_mode_buf, encode, encode_mode_buf, Base64Mode};

use test::Bencher;
use rand::Rng;

#[bench]
fn encode_3b(b: &mut Bencher) {
    do_encode_bench(b, 3)
}

#[bench]
fn encode_3b_reuse_buf(b: &mut Bencher) {
    do_encode_bench_reuse_buf(b, 3)
}

#[bench]
fn encode_50b(b: &mut Bencher) {
    do_encode_bench(b, 50)
}

#[bench]
fn encode_50b_reuse_buf(b: &mut Bencher) {
    do_encode_bench_reuse_buf(b, 50)
}

#[bench]
fn encode_100b(b: &mut Bencher) {
    do_encode_bench(b, 100)
}

#[bench]
fn encode_100b_reuse_buf(b: &mut Bencher) {
    do_encode_bench_reuse_buf(b, 100)
}

#[bench]
fn encode_500b(b: &mut Bencher) {
    do_encode_bench(b, 500)
}

#[bench]
fn encode_500b_reuse_buf(b: &mut Bencher) {
    do_encode_bench_reuse_buf(b, 500)
}

#[bench]
fn encode_3kib(b: &mut Bencher) {
    do_encode_bench(b, 3 * 1024)
}

#[bench]
fn encode_3kib_reuse_buf(b: &mut Bencher) {
    do_encode_bench_reuse_buf(b, 3 * 1024)
}

#[bench]
fn encode_3mib(b: &mut Bencher) {
    do_encode_bench(b, 3 * 1024 * 1024)
}

#[bench]
fn encode_3mib_reuse_buf(b: &mut Bencher) {
    do_encode_bench_reuse_buf(b, 3 * 1024 * 1024)
}

#[bench]
fn encode_10mib(b: &mut Bencher) {
    do_encode_bench(b, 10 * 1024 * 1024)
}

#[bench]
fn encode_10mib_reuse_buf(b: &mut Bencher) {
    do_encode_bench_reuse_buf(b, 10 * 1024 * 1024)
}

#[bench]
fn encode_30mib(b: &mut Bencher) {
    do_encode_bench(b, 30 * 1024 * 1024)
}

#[bench]
fn encode_30mib_reuse_buf(b: &mut Bencher) {
    do_encode_bench_reuse_buf(b, 30 * 1024 * 1024)
}

#[bench]
fn decode_3b(b: &mut Bencher) {
    do_decode_bench(b, 3)
}

#[bench]
fn decode_3b_reuse_buf(b: &mut Bencher) {
    do_decode_bench_reuse_buf(b, 3)
}

#[bench]
fn decode_50b(b: &mut Bencher) {
    do_decode_bench(b, 50)
}

#[bench]
fn decode_50b_reuse_buf(b: &mut Bencher) {
    do_decode_bench_reuse_buf(b, 50)
}

#[bench]
fn decode_100b(b: &mut Bencher) {
    do_decode_bench(b, 100)
}

#[bench]
fn decode_100b_reuse_buf(b: &mut Bencher) {
    do_decode_bench_reuse_buf(b, 100)
}

#[bench]
fn decode_500b(b: &mut Bencher) {
    do_decode_bench(b, 500)
}

#[bench]
fn decode_500b_reuse_buf(b: &mut Bencher) {
    do_decode_bench_reuse_buf(b, 500)
}

#[bench]
fn decode_3kib(b: &mut Bencher) {
    do_decode_bench(b, 3 * 1024)
}

#[bench]
fn decode_3kib_reuse_buf(b: &mut Bencher) {
    do_decode_bench_reuse_buf(b, 3 * 1024)
}

#[bench]
fn decode_3mib(b: &mut Bencher) {
    do_decode_bench(b, 3 * 1024 * 1024)
}

#[bench]
fn decode_3mib_reuse_buf(b: &mut Bencher) {
    do_decode_bench_reuse_buf(b, 3 * 1024 * 1024)
}

#[bench]
fn decode_10mib(b: &mut Bencher) {
    do_decode_bench(b, 10 * 1024 * 1024)
}

#[bench]
fn decode_10mib_reuse_buf(b: &mut Bencher) {
    do_decode_bench_reuse_buf(b, 10 * 1024 * 1024)
}

#[bench]
fn decode_30mib(b: &mut Bencher) {
    do_decode_bench(b, 30 * 1024 * 1024)
}

#[bench]
fn decode_30mib_reuse_buf(b: &mut Bencher) {
    do_decode_bench_reuse_buf(b, 30 * 1024 * 1024)
}

fn do_decode_bench(b: &mut Bencher, size: usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size);
    fill(&mut v);
    let encoded = encode(&v);

    b.bytes = v.len() as u64;
    b.iter(|| {
        let orig = decode(&encoded);
        test::black_box(&orig);
    });
}

fn do_decode_bench_reuse_buf(b: &mut Bencher, size: usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size);
    fill(&mut v);
    let encoded = encode(&v);

    let mut buf = Vec::new();
    b.bytes = v.len() as u64;
    b.iter(|| {
        decode_mode_buf(&encoded, Base64Mode::Standard, &mut buf).unwrap();
        test::black_box(&buf);
        buf.clear();
    });
}

fn do_encode_bench(b: &mut Bencher, size: usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size);
    fill(&mut v);

    b.bytes = v.len() as u64;
    b.iter(|| {
        let e = encode(&v);
        test::black_box(&e);
    });
}

fn do_encode_bench_reuse_buf(b: &mut Bencher, size: usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size);
    fill(&mut v);

    let mut buf = String::new();

    b.bytes = v.len() as u64;
    b.iter(|| {
        let e = encode_mode_buf(&v, Base64Mode::Standard, &mut buf);
        test::black_box(&e);
        buf.clear();
    });
}

fn fill(v: &mut Vec<u8>) {
    let cap = v.capacity();
    // weak randomness is plenty; we just want to not be completely friendly to the branch predictor
    let mut r = rand::weak_rng();
    while v.len() < cap {
        v.push(r.gen::<u8>());
    }
}
<commit_msg>Use encoded size when calculating throughput for decoding<commit_after>#![feature(test)]

extern crate base64;
extern crate test;
extern crate rand;

use base64::{decode, decode_mode_buf, encode, encode_mode_buf, Base64Mode};

use test::Bencher;
use rand::Rng;

#[bench]
fn encode_3b(b: &mut Bencher) {
    do_encode_bench(b, 3)
}

#[bench]
fn encode_3b_reuse_buf(b: &mut Bencher) {
    do_encode_bench_reuse_buf(b, 3)
}

#[bench]
fn encode_50b(b: &mut Bencher) {
    do_encode_bench(b, 50)
}

#[bench]
fn encode_50b_reuse_buf(b: &mut Bencher) {
    do_encode_bench_reuse_buf(b, 50)
}

#[bench]
fn encode_100b(b: &mut Bencher) {
    do_encode_bench(b, 100)
}

#[bench]
fn encode_100b_reuse_buf(b: &mut Bencher) {
    do_encode_bench_reuse_buf(b, 100)
}

#[bench]
fn encode_500b(b: &mut Bencher) {
    do_encode_bench(b, 500)
}

#[bench]
fn encode_500b_reuse_buf(b: &mut Bencher) {
    do_encode_bench_reuse_buf(b, 500)
}

#[bench]
fn encode_3kib(b: &mut Bencher) {
    do_encode_bench(b, 3 * 1024)
}

#[bench]
fn encode_3kib_reuse_buf(b: &mut Bencher) {
    do_encode_bench_reuse_buf(b, 3 * 1024)
}

#[bench]
fn encode_3mib(b: &mut Bencher) {
    do_encode_bench(b, 3 * 1024 * 1024)
}

#[bench]
fn encode_3mib_reuse_buf(b: &mut Bencher) {
    do_encode_bench_reuse_buf(b, 3 * 1024 * 1024)
}

#[bench]
fn encode_10mib(b: &mut Bencher) {
    do_encode_bench(b, 10 * 1024 * 1024)
}

#[bench]
fn encode_10mib_reuse_buf(b: &mut Bencher) {
    do_encode_bench_reuse_buf(b, 10 * 1024 * 1024)
}

#[bench]
fn encode_30mib(b: &mut Bencher) {
    do_encode_bench(b, 30 * 1024 * 1024)
}

#[bench]
fn encode_30mib_reuse_buf(b: &mut Bencher) {
    do_encode_bench_reuse_buf(b, 30 * 1024 * 1024)
}

#[bench]
fn decode_3b(b: &mut Bencher) {
    do_decode_bench(b, 3)
}

#[bench]
fn decode_3b_reuse_buf(b: &mut Bencher) {
    do_decode_bench_reuse_buf(b, 3)
}

#[bench]
fn decode_50b(b: &mut Bencher) {
    do_decode_bench(b, 50)
}

#[bench]
fn decode_50b_reuse_buf(b: &mut Bencher) {
    do_decode_bench_reuse_buf(b, 50)
}

#[bench]
fn decode_100b(b: &mut Bencher) {
    do_decode_bench(b, 100)
}

#[bench]
fn decode_100b_reuse_buf(b: &mut Bencher) {
    do_decode_bench_reuse_buf(b, 100)
}

#[bench]
fn decode_500b(b: &mut Bencher) {
    do_decode_bench(b, 500)
}

#[bench]
fn decode_500b_reuse_buf(b: &mut Bencher) {
    do_decode_bench_reuse_buf(b, 500)
}

#[bench]
fn decode_3kib(b: &mut Bencher) {
    do_decode_bench(b, 3 * 1024)
}

#[bench]
fn decode_3kib_reuse_buf(b: &mut Bencher) {
    do_decode_bench_reuse_buf(b, 3 * 1024)
}

#[bench]
fn decode_3mib(b: &mut Bencher) {
    do_decode_bench(b, 3 * 1024 * 1024)
}

#[bench]
fn decode_3mib_reuse_buf(b: &mut Bencher) {
    do_decode_bench_reuse_buf(b, 3 * 1024 * 1024)
}

#[bench]
fn decode_10mib(b: &mut Bencher) {
    do_decode_bench(b, 10 * 1024 * 1024)
}

#[bench]
fn decode_10mib_reuse_buf(b: &mut Bencher) {
    do_decode_bench_reuse_buf(b, 10 * 1024 * 1024)
}

#[bench]
fn decode_30mib(b: &mut Bencher) {
    do_decode_bench(b, 30 * 1024 * 1024)
}

#[bench]
fn decode_30mib_reuse_buf(b: &mut Bencher) {
    do_decode_bench_reuse_buf(b, 30 * 1024 * 1024)
}

fn do_decode_bench(b: &mut Bencher, size: usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
    fill(&mut v);
    let encoded = encode(&v);

    b.bytes = encoded.len() as u64;
    b.iter(|| {
        let orig = decode(&encoded);
        test::black_box(&orig);
    });
}

fn do_decode_bench_reuse_buf(b: &mut Bencher, size: usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
    fill(&mut v);
    let encoded = encode(&v);

    let mut buf = Vec::new();
    b.bytes = encoded.len() as u64;
    b.iter(|| {
        decode_mode_buf(&encoded, Base64Mode::Standard, &mut buf).unwrap();
        test::black_box(&buf);
        buf.clear();
    });
}

fn do_encode_bench(b: &mut Bencher, size: usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size);
    fill(&mut v);

    b.bytes = v.len() as u64;
    b.iter(|| {
        let e = encode(&v);
        test::black_box(&e);
    });
}

fn do_encode_bench_reuse_buf(b: &mut Bencher, size: usize) {
    let mut v: Vec<u8> = Vec::with_capacity(size);
    fill(&mut v);

    let mut buf = String::new();

    b.bytes = v.len() as u64;
    b.iter(|| {
        let e = encode_mode_buf(&v, Base64Mode::Standard, &mut buf);
        test::black_box(&e);
        buf.clear();
    });
}

fn fill(v: &mut Vec<u8>) {
    let cap = v.capacity();
    // weak randomness is plenty; we just want to not be completely friendly to the branch predictor
    let mut r = rand::weak_rng();
    while v.len() < cap {
        v.push(r.gen::<u8>());
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate test;
use test::Bencher;
extern crate lonlat_bng;
use lonlat_bng::convert_to_bng_threaded_vec;

extern crate rand;
use rand::distributions::{IndependentSample, Range};

#[bench]
fn bench_threads(b: &mut Bencher) {
    let num_coords = 10000;
    let between_lon = Range::new(-6.379880, 1.768960);
    let between_lat = Range::new(49.871159, 55.811741);
    let mut rng = rand::thread_rng();

    b.iter(||{
        let mut lon_vec = vec![between_lon.ind_sample(&mut rng); num_coords];
        let mut lat_vec = vec![between_lat.ind_sample(&mut rng); num_coords];
        convert_to_bng_threaded_vec(
            &mut lon_vec,
            &mut lat_vec
        );
    });
}
<commit_msg>Move point generation out of benchmark generation<commit_after>#![feature(test)]

extern crate test;
use test::Bencher;
extern crate lonlat_bng;
use lonlat_bng::convert_to_bng_threaded_vec;

extern crate rand;
use rand::distributions::{IndependentSample, Range};

#[bench]
fn bench_threads(b: &mut Bencher) {
    let num_coords = 100000;
    let between_lon = Range::new(-6.379880, 1.768960);
    let between_lat = Range::new(49.871159, 55.811741);
    let mut rng = rand::thread_rng();
    let mut lon_vec = vec![between_lon.ind_sample(&mut rng); num_coords];
    let mut lat_vec = vec![between_lat.ind_sample(&mut rng); num_coords];
    b.iter(||{
        convert_to_bng_threaded_vec(
            &mut lon_vec,
            &mut lat_vec
        );
    });
}
<|endoftext|>


<commit_before>#![allow(non_camel_case_types)]

use pyffi::*;
use std::os::raw::*;
use std::option::Option;

use super::types::*;
use super::array::*;

#[repr(C)]
#[derive(Clone, Copy)]
pub struct PyUFuncObject {
    pub ob_base: PyObject,
    pub nin: c_int,
    pub nout: c_int,
    pub nargs: c_int,
    pub identity: c_int,
    pub functions: *mut PyUFuncGenericFunction,
    pub data: *mut *mut c_void,
    pub ntypes: c_int,
    pub reserved1: c_int,
    pub name: *const c_char,
    pub types: *mut c_char,
    pub doc: *const c_char,
    pub ptr: *mut c_void,
    pub obj: *mut PyObject,
    pub userloops: *mut PyObject,
    pub core_enabled: c_int,
    pub core_num_dim_ix: c_int,
    pub core_num_dims: *mut c_int,
    pub core_dim_ixs: *mut c_int,
    pub core_offsets: *mut c_int,
    pub core_signature: *mut c_char,
    pub type_resolver: PyUFunc_TypeResolutionFunc,
    pub legacy_inner_loop_selector: PyUFunc_LegacyInnerLoopSelectionFunc,
    pub reserved2: *mut c_void,
    pub masked_inner_loop_selector: PyUFunc_MaskedInnerLoopSelectionFunc,
    pub op_flags: *mut npy_uint32,
    pub iter_flags: npy_uint32,
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct NpyAuxData {
    pub free: NpyAuxData_FreeFunc,
    pub clone: NpyAuxData_CloneFunc,
    pub reserved: [*mut c_void; 2usize],
}

pub type NpyAuxData_FreeFunc = Option<unsafe extern "C" fn(arg1: *mut NpyAuxData)>;
pub type NpyAuxData_CloneFunc = Option<unsafe extern "C" fn(arg1: *mut NpyAuxData) -> *mut NpyAuxData>;

pub type PyUFuncGenericFunction = Option<unsafe extern "C" fn(args: *mut *mut c_char,
                                                              dimensions: *mut npy_intp,
                                                              strides: *mut npy_intp,
                                                              innerloopdata: *mut c_void)>;
pub type PyUFunc_MaskedStridedInnerLoopFunc = Option<unsafe extern "C" fn(dataptrs: *mut *mut c_char,
                                                                          strides: *mut npy_intp,
                                                                          maskptr: *mut c_char,
                                                                          mask_stride: npy_intp,
                                                                          count: npy_intp,
                                                                          innerloopdata: *mut NpyAuxData)>;
pub type PyUFunc_TypeResolutionFunc = Option<unsafe extern "C" fn(ufunc: *mut PyUFuncObject,
                                                                  casting: NPY_CASTING,
                                                                  operands: *mut *mut PyArrayObject,
                                                                  type_tup: *mut PyObject,
                                                                  out_dtypes: *mut *mut PyArray_Descr)
                                                                  -> c_int>;
pub type PyUFunc_LegacyInnerLoopSelectionFunc = Option<unsafe extern "C" fn(ufunc: *mut PyUFuncObject,
                                                                            dtypes: *mut *mut PyArray_Descr,
                                                                            out_innerloop: *mut PyUFuncGenericFunction,
                                                                            out_innerloopdata: *mut *mut c_void,
                                                                            out_needs_api: *mut c_int)
                                                                            -> c_int>;
pub type PyUFunc_MaskedInnerLoopSelectionFunc = Option<unsafe extern "C" fn(ufunc: *mut PyUFuncObject,
                                                                            dtypes: *mut *mut PyArray_Descr,
                                                                            mask_dtype: *mut PyArray_Descr,
                                                                            fixed_strides: *mut npy_intp,
                                                                            fixed_mask_stride: npy_intp,
                                                                            out_innerloop: *mut PyUFunc_MaskedStridedInnerLoopFunc,
                                                                            out_innerloopdata: *mut *mut NpyAuxData,
                                                                            out_needs_api: *mut c_int)
                                                                            -> c_int>;
<commit_msg>Add ufunc API<commit_after>#![allow(non_camel_case_types)]

use pyffi::*;
use std::os::raw::*;
use std::option::Option;

use super::types::*;
use super::array::*;

#[repr(C)]
#[derive(Clone, Copy)]
pub struct PyUFuncObject {
    pub ob_base: PyObject,
    pub nin: c_int,
    pub nout: c_int,
    pub nargs: c_int,
    pub identity: c_int,
    pub functions: *mut PyUFuncGenericFunction,
    pub data: *mut *mut c_void,
    pub ntypes: c_int,
    pub reserved1: c_int,
    pub name: *const c_char,
    pub types: *mut c_char,
    pub doc: *const c_char,
    pub ptr: *mut c_void,
    pub obj: *mut PyObject,
    pub userloops: *mut PyObject,
    pub core_enabled: c_int,
    pub core_num_dim_ix: c_int,
    pub core_num_dims: *mut c_int,
    pub core_dim_ixs: *mut c_int,
    pub core_offsets: *mut c_int,
    pub core_signature: *mut c_char,
    pub type_resolver: PyUFunc_TypeResolutionFunc,
    pub legacy_inner_loop_selector: PyUFunc_LegacyInnerLoopSelectionFunc,
    pub reserved2: *mut c_void,
    pub masked_inner_loop_selector: PyUFunc_MaskedInnerLoopSelectionFunc,
    pub op_flags: *mut npy_uint32,
    pub iter_flags: npy_uint32,
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct NpyAuxData {
    pub free: NpyAuxData_FreeFunc,
    pub clone: NpyAuxData_CloneFunc,
    pub reserved: [*mut c_void; 2usize],
}

pub type NpyAuxData_FreeFunc = Option<unsafe extern "C" fn(arg1: *mut NpyAuxData)>;
pub type NpyAuxData_CloneFunc = Option<unsafe extern "C" fn(arg1: *mut NpyAuxData) -> *mut NpyAuxData>;

pub type PyUFuncGenericFunction = Option<unsafe extern "C" fn(args: *mut *mut c_char,
                                                              dimensions: *mut npy_intp,
                                                              strides: *mut npy_intp,
                                                              innerloopdata: *mut c_void)>;
pub type PyUFunc_MaskedStridedInnerLoopFunc = Option<unsafe extern "C" fn(dataptrs: *mut *mut c_char,
                                                                          strides: *mut npy_intp,
                                                                          maskptr: *mut c_char,
                                                                          mask_stride: npy_intp,
                                                                          count: npy_intp,
                                                                          innerloopdata: *mut NpyAuxData)>;
pub type PyUFunc_TypeResolutionFunc = Option<unsafe extern "C" fn(ufunc: *mut PyUFuncObject,
                                                                  casting: NPY_CASTING,
                                                                  operands: *mut *mut PyArrayObject,
                                                                  type_tup: *mut PyObject,
                                                                  out_dtypes: *mut *mut PyArray_Descr)
                                                                  -> c_int>;
pub type PyUFunc_LegacyInnerLoopSelectionFunc = Option<unsafe extern "C" fn(ufunc: *mut PyUFuncObject,
                                                                            dtypes: *mut *mut PyArray_Descr,
                                                                            out_innerloop: *mut PyUFuncGenericFunction,
                                                                            out_innerloopdata: *mut *mut c_void,
                                                                            out_needs_api: *mut c_int)
                                                                            -> c_int>;
pub type PyUFunc_MaskedInnerLoopSelectionFunc = Option<unsafe extern "C" fn(ufunc: *mut PyUFuncObject,
                                                                            dtypes: *mut *mut PyArray_Descr,
                                                                            mask_dtype: *mut PyArray_Descr,
                                                                            fixed_strides: *mut npy_intp,
                                                                            fixed_mask_stride: npy_intp,
                                                                            out_innerloop: *mut PyUFunc_MaskedStridedInnerLoopFunc,
                                                                            out_innerloopdata: *mut *mut NpyAuxData,
                                                                            out_needs_api: *mut c_int)
                                                                            -> c_int>;

extern "C" {
    pub fn PyUFunc_FromFuncAndData(func: *mut PyUFuncGenericFunction,
                                   data: *mut *mut c_void,
                                   types: *mut c_char,
                                   ntypes: c_int,
                                   nin: c_int,
                                   nout: c_int,
                                   identity: c_int,
                                   name: *const c_char,
                                   doc: *const c_char,
                                   unused: c_int)
                                   -> *mut PyObject;
    pub fn PyUFunc_RegisterLoopForType(ufunc: *mut PyUFuncObject,
                                       usertype: c_int,
                                       function: PyUFuncGenericFunction,
                                       arg_types: *mut c_int,
                                       data: *mut c_void)
                                       -> c_int;
    pub fn PyUFunc_GenericFunction(ufunc: *mut PyUFuncObject, args: *mut PyObject, kwds: *mut PyObject, op: *mut *mut PyArrayObject) -> c_int;
    pub fn PyUFunc_f_f_As_d_d(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_d_d(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_f_f(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_g_g(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_F_F_As_D_D(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_F_F(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_D_D(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_G_G(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_O_O(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_ff_f_As_dd_d(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_ff_f(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_dd_d(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_gg_g(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_FF_F_As_DD_D(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_DD_D(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_FF_F(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_GG_G(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_OO_O(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_O_O_method(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_OO_O_method(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_On_Om(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_GetPyValues(name: *mut c_char, bufsize: *mut c_int, errmask: *mut c_int, errobj: *mut *mut PyObject) -> c_int;
    pub fn PyUFunc_checkfperr(errmask: c_int, errobj: *mut PyObject, first: *mut c_int) -> c_int;
    pub fn PyUFunc_clearfperr();
    pub fn PyUFunc_getfperr() -> c_int;
    pub fn PyUFunc_handlefperr(errmask: c_int, errobj: *mut PyObject, retstatus: c_int, first: *mut c_int) -> c_int;
    pub fn PyUFunc_ReplaceLoopBySignature(func: *mut PyUFuncObject,
                                          newfunc: PyUFuncGenericFunction,
                                          signature: *mut c_int,
                                          oldfunc: *mut PyUFuncGenericFunction)
                                          -> c_int;
    pub fn PyUFunc_FromFuncAndDataAndSignature(func: *mut PyUFuncGenericFunction,
                                               data: *mut *mut c_void,
                                               types: *mut c_char,
                                               ntypes: c_int,
                                               nin: c_int,
                                               nout: c_int,
                                               identity: c_int,
                                               name: *const c_char,
                                               doc: *const c_char,
                                               unused: c_int,
                                               signature: *const c_char)
                                               -> *mut PyObject;
    pub fn PyUFunc_SetUsesArraysAsData(data: *mut *mut c_void, i: usize) -> c_int;
    pub fn PyUFunc_e_e(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_e_e_As_f_f(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_e_e_As_d_d(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_ee_e(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_ee_e_As_ff_f(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_ee_e_As_dd_d(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void);
    pub fn PyUFunc_DefaultTypeResolver(ufunc: *mut PyUFuncObject,
                                       casting: NPY_CASTING,
                                       operands: *mut *mut PyArrayObject,
                                       type_tup: *mut PyObject,
                                       out_dtypes: *mut *mut PyArray_Descr)
                                       -> c_int;
    pub fn PyUFunc_ValidateCasting(ufunc: *mut PyUFuncObject,
                                   casting: NPY_CASTING,
                                   operands: *mut *mut PyArrayObject,
                                   dtypes: *mut *mut PyArray_Descr)
                                   -> c_int;
    pub fn PyUFunc_RegisterLoopForDescr(ufunc: *mut PyUFuncObject,
                                        user_dtype: *mut PyArray_Descr,
                                        function: PyUFuncGenericFunction,
                                        arg_dtypes: *mut *mut PyArray_Descr,
                                        data: *mut c_void)
                                        -> c_int;
}
<|endoftext|>


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

//! Implementation of cookie creation and matching as specified by
//! http://tools.ietf.org/html/rfc6265

use cookie_rs;
use hyper_serde::{self, Serde};
use net_traits::CookieSource;
use net_traits::pub_domains::is_pub_domain;
use servo_url::ServoUrl;
use std::borrow::ToOwned;
use std::net::{Ipv4Addr, Ipv6Addr};
use time::{Tm, now, at, Duration};

/// A stored cookie that wraps the definition in cookie-rs. This is used to implement
/// various behaviours defined in the spec that rely on an associated request URL,
/// which cookie-rs and hyper's header parsing do not support.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Cookie {
    #[serde(deserialize_with = "hyper_serde::deserialize",
            serialize_with = "hyper_serde::serialize")]
    pub cookie: cookie_rs::Cookie,
    pub host_only: bool,
    pub persistent: bool,
    #[serde(deserialize_with = "hyper_serde::deserialize",
            serialize_with = "hyper_serde::serialize")]
    pub creation_time: Tm,
    #[serde(deserialize_with = "hyper_serde::deserialize",
            serialize_with = "hyper_serde::serialize")]
    pub last_access: Tm,
    pub expiry_time: Option<Serde<Tm>>,
}

impl Cookie {
    /// http://tools.ietf.org/html/rfc6265#section-5.3
    pub fn new_wrapped(mut cookie: cookie_rs::Cookie, request: &ServoUrl, source: CookieSource)
                       -> Option<Cookie> {
        // Step 3
        let (persistent, expiry_time) = match (&cookie.max_age, &cookie.expires) {
            (&Some(max_age), _) => {
                (true, Some(at(now().to_timespec() + Duration::seconds(max_age as i64))))
            }
            (_, &Some(expires)) => (true, Some(expires)),
            _ => (false, None)
        };

        let url_host = request.host_str().unwrap_or("").to_owned();

        // Step 4
        let mut domain = cookie.domain.clone().unwrap_or("".to_owned());

        // Step 5
        if is_pub_domain(&domain) {
            if domain == url_host {
                domain = "".to_owned();
            } else {
                return None
            }
        }

        // Step 6
        let host_only = if !domain.is_empty() {
            if !Cookie::domain_match(&url_host, &domain) {
                return None;
            } else {
                cookie.domain = Some(domain);
                false
            }
        } else {
            cookie.domain = Some(url_host);
            true
        };

        // Step 7
        let mut path = cookie.path.unwrap_or("".to_owned());
        if path.chars().next() != Some('/') {
            path = Cookie::default_path(request.path()).to_owned();
        }
        cookie.path = Some(path);

        // Step 10
        if cookie.httponly && source == CookieSource::NonHTTP {
            return None;
        }

        Some(Cookie {
            cookie: cookie,
            host_only: host_only,
            persistent: persistent,
            creation_time: now(),
            last_access: now(),
            expiry_time: expiry_time.map(Serde),
        })
    }

    pub fn touch(&mut self) {
        self.last_access = now();
    }

    // http://tools.ietf.org/html/rfc6265#section-5.1.4
    pub fn default_path(request_path: &str) -> &str {
        // Step 2
        if request_path.chars().next() != Some('/') {
            return "/";
        }

        // Step 3
        let rightmost_slash_idx = request_path.rfind("/").unwrap();
        if rightmost_slash_idx == 0 {
            // There's only one slash; it's the first character
            return "/";
        }

        // Step 4
        &request_path[..rightmost_slash_idx]
    }

    // http://tools.ietf.org/html/rfc6265#section-5.1.4
    pub fn path_match(request_path: &str, cookie_path: &str) -> bool {
        // A request-path path-matches a given cookie-path if at least one of
        // the following conditions holds:

        // The cookie-path and the request-path are identical.
        request_path == cookie_path ||

        (request_path.starts_with(cookie_path) && (
            // The cookie-path is a prefix of the request-path, and the last
            // character of the cookie-path is %x2F ("/").
            cookie_path.ends_with("/") ||
            // The cookie-path is a prefix of the request-path, and the first
            // character of the request-path that is not included in the cookie-
            // path is a %x2F ("/") character.
            request_path[cookie_path.len()..].starts_with("/")
        ))
    }

    // http://tools.ietf.org/html/rfc6265#section-5.1.3
    pub fn domain_match(string: &str, domain_string: &str) -> bool {
        string == domain_string ||
        (string.ends_with(domain_string) &&
         string.as_bytes()[string.len()-domain_string.len()-1] == b'.' &&
         string.parse::<Ipv4Addr>().is_err() &&
         string.parse::<Ipv6Addr>().is_err())
    }

    // http://tools.ietf.org/html/rfc6265#section-5.4 step 1
    pub fn appropriate_for_url(&self, url: &ServoUrl, source: CookieSource) -> bool {
        let domain = url.host_str();
        if self.host_only {
            if self.cookie.domain.as_ref().map(String::as_str) != domain {
                return false;
            }
        } else {
            if let (Some(domain), &Some(ref cookie_domain)) = (domain, &self.cookie.domain) {
                if !Cookie::domain_match(domain, cookie_domain) {
                    return false;
                }
            }
        }

        if let Some(ref cookie_path) = self.cookie.path {
            if !Cookie::path_match(url.path(), cookie_path) {
                return false;
            }
        }

        if self.cookie.secure && !url.is_secure_scheme() {
            return false;
        }
        if self.cookie.httponly && source == CookieSource::NonHTTP {
            return false;
        }

        true
    }
}
<commit_msg>Auto merge of #15844 - notriddle:domain_match_lowercase, r=nox<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Implementation of cookie creation and matching as specified by
//! http://tools.ietf.org/html/rfc6265

use cookie_rs;
use hyper_serde::{self, Serde};
use net_traits::CookieSource;
use net_traits::pub_domains::is_pub_domain;
use servo_url::ServoUrl;
use std::borrow::ToOwned;
use std::net::{Ipv4Addr, Ipv6Addr};
use time::{Tm, now, at, Duration};

/// A stored cookie that wraps the definition in cookie-rs. This is used to implement
/// various behaviours defined in the spec that rely on an associated request URL,
/// which cookie-rs and hyper's header parsing do not support.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Cookie {
    #[serde(deserialize_with = "hyper_serde::deserialize",
            serialize_with = "hyper_serde::serialize")]
    pub cookie: cookie_rs::Cookie,
    pub host_only: bool,
    pub persistent: bool,
    #[serde(deserialize_with = "hyper_serde::deserialize",
            serialize_with = "hyper_serde::serialize")]
    pub creation_time: Tm,
    #[serde(deserialize_with = "hyper_serde::deserialize",
            serialize_with = "hyper_serde::serialize")]
    pub last_access: Tm,
    pub expiry_time: Option<Serde<Tm>>,
}

impl Cookie {
    /// http://tools.ietf.org/html/rfc6265#section-5.3
    pub fn new_wrapped(mut cookie: cookie_rs::Cookie, request: &ServoUrl, source: CookieSource)
                       -> Option<Cookie> {
        // Step 3
        let (persistent, expiry_time) = match (&cookie.max_age, &cookie.expires) {
            (&Some(max_age), _) => {
                (true, Some(at(now().to_timespec() + Duration::seconds(max_age as i64))))
            }
            (_, &Some(expires)) => (true, Some(expires)),
            _ => (false, None)
        };

        let url_host = request.host_str().unwrap_or("").to_owned();

        // Step 4
        let mut domain = cookie.domain.clone().unwrap_or("".to_owned());

        // Step 5
        if is_pub_domain(&domain) {
            if domain == url_host {
                domain = "".to_owned();
            } else {
                return None
            }
        }

        // Step 6
        let host_only = if !domain.is_empty() {
            if !Cookie::domain_match(&url_host, &domain) {
                return None;
            } else {
                cookie.domain = Some(domain);
                false
            }
        } else {
            cookie.domain = Some(url_host);
            true
        };

        // Step 7
        let mut path = cookie.path.unwrap_or("".to_owned());
        if path.chars().next() != Some('/') {
            path = Cookie::default_path(request.path()).to_owned();
        }
        cookie.path = Some(path);

        // Step 10
        if cookie.httponly && source == CookieSource::NonHTTP {
            return None;
        }

        Some(Cookie {
            cookie: cookie,
            host_only: host_only,
            persistent: persistent,
            creation_time: now(),
            last_access: now(),
            expiry_time: expiry_time.map(Serde),
        })
    }

    pub fn touch(&mut self) {
        self.last_access = now();
    }

    // http://tools.ietf.org/html/rfc6265#section-5.1.4
    pub fn default_path(request_path: &str) -> &str {
        // Step 2
        if request_path.chars().next() != Some('/') {
            return "/";
        }

        // Step 3
        let rightmost_slash_idx = request_path.rfind("/").unwrap();
        if rightmost_slash_idx == 0 {
            // There's only one slash; it's the first character
            return "/";
        }

        // Step 4
        &request_path[..rightmost_slash_idx]
    }

    // http://tools.ietf.org/html/rfc6265#section-5.1.4
    pub fn path_match(request_path: &str, cookie_path: &str) -> bool {
        // A request-path path-matches a given cookie-path if at least one of
        // the following conditions holds:

        // The cookie-path and the request-path are identical.
        request_path == cookie_path ||

        (request_path.starts_with(cookie_path) && (
            // The cookie-path is a prefix of the request-path, and the last
            // character of the cookie-path is %x2F ("/").
            cookie_path.ends_with("/") ||
            // The cookie-path is a prefix of the request-path, and the first
            // character of the request-path that is not included in the cookie-
            // path is a %x2F ("/") character.
            request_path[cookie_path.len()..].starts_with("/")
        ))
    }

    // http://tools.ietf.org/html/rfc6265#section-5.1.3
    pub fn domain_match(string: &str, domain_string: &str) -> bool {
        debug_assert!(string.to_lowercase() == string);
        debug_assert!(domain_string.to_lowercase() == domain_string);
        string == domain_string ||
        (string.ends_with(domain_string) &&
         string.as_bytes()[string.len()-domain_string.len()-1] == b'.' &&
         string.parse::<Ipv4Addr>().is_err() &&
         string.parse::<Ipv6Addr>().is_err())
    }

    // http://tools.ietf.org/html/rfc6265#section-5.4 step 1
    pub fn appropriate_for_url(&self, url: &ServoUrl, source: CookieSource) -> bool {
        let domain = url.host_str();
        if self.host_only {
            if self.cookie.domain.as_ref().map(String::as_str) != domain {
                return false;
            }
        } else {
            if let (Some(domain), &Some(ref cookie_domain)) = (domain, &self.cookie.domain) {
                if !Cookie::domain_match(domain, cookie_domain) {
                    return false;
                }
            }
        }

        if let Some(ref cookie_path) = self.cookie.path {
            if !Cookie::path_match(url.path(), cookie_path) {
                return false;
            }
        }

        if self.cookie.secure && !url.is_secure_scheme() {
            return false;
        }
        if self.cookie.httponly && source == CookieSource::NonHTTP {
            return false;
        }

        true
    }
}
<|endoftext|>


<commit_before>//! Treiber stacks.

use std::sync::atomic;
use std::ptr;
use {Atomic, Guard};

/// A Treiber stack.
///
/// Treiber stacks are one way to implement concurrent LIFO stack.
///
/// Treiber stacks builds on linked lists. They are lock-free and non-blocking. It can be compared
/// to transactional memory in that it repeats operations, if another thread changes it while.
///
/// The ABA problem is of course addressed through the API of this crate.
pub struct Treiber<T> {
    /// The head node.
    head: Atomic<Node<T>>,
}

/// A node in the stack.
struct Node<T> {
    /// The data this node holds.
    data: T,
    /// The next node.
    next: *const Node<T>,
}

impl<T> Treiber<T> {
    /// Create a new, empty Treiber stack.
    pub fn new() -> Treiber<T> {
        Treiber {
            head: Atomic::default(),
        }
    }

    /// Pop an item from the stack.
    pub fn pop(&self) -> Option<Guard<T>> {
        // TODO: Use `catch {}` here when it lands.
        // Read the head snapshot.
        let mut snapshot = self.head.load(atomic::Ordering::Acquire);

        // Unless the head snapshot is `None`, try to replace it with the tail.
        while let Some(node) = snapshot {
            // Attempt to replace the head with the tail of the head.
            match unsafe {
                self.head.compare_and_swap_raw(
                    &*node,
                    node.next as *mut Node<T>,
                    atomic::Ordering::Release,
                )
            } {
                // It succeeded; return the item.
                Ok(_) => return Some(node.map(|x| &x.data)),
                // It failed, update the head snapshot and continue.
                Err(new) => snapshot = new,
            }
        }

        // As the head was empty, there is nothing to pop.
        None
    }

    /// Push an item to the stack.
    pub fn push(&self, item: T)
    where T: 'static {
        // Load the head snapshot.
        let mut snapshot = self.head.load(atomic::Ordering::Acquire);
        let mut snapshot_ptr: Option<*const Node<T>>;

        // TODO: Use `catch {}` here when it lands.
        // Construct a node, which will be the new head.
        let mut node = Box::new(Node {
            data: item,
            // Placeholder; we will replace it with an actual value in the loop.
            next: ptr::null(),
        });

        loop {
            // Derive the nullable snapshot pointer from the head snapshot.
            snapshot_ptr = snapshot.as_ref().map(Guard::as_raw);
            // Construct the next-pointer of the new node from the head snapshot.
            node.next = snapshot_ptr.unwrap_or(ptr::null());

            // TODO: This should be something that ignores the guard creation when the CAS
            //       succeeds, because it's expensive to do and not used anyway. It should be easy
            //       enough to implement, but I am struggling to come up with a good name for the
            //       method.

            // CAS from the read pointer to the new head.
            match self.head.compare_and_swap(snapshot_ptr, Some(node), atomic::Ordering::Release) {
                // If it succeeds, the item has been pushed.
                Ok(_) => break,
                // If it fails, we will retry the CAS with updated values.
                Err((new_head, Some(node2))) => {
                    // Update the head snapshot.
                    snapshot = new_head;
                    // Put the box we gave back to the variable where it belongs.
                    node = node2;
                },
                // This should never be reached as we gave an argument which was unconditionally
                // `Some`.
                _ => unreachable!(),
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::thread;
    use std::sync::Arc;

    #[test]
    fn single_thread() {
        let stack = Treiber::new();

        for i in 0..10000 {
            stack.push(i);
        }

        for i in (0..10000).rev() {
            assert_eq!(*stack.pop().unwrap(), i);
        }

        for i in 0..10000 {
            stack.push(i);
        }

        for i in (0..10000).rev() {
            assert_eq!(*stack.pop().unwrap(), i);
        }

        assert!(stack.pop().is_none());
        assert!(stack.pop().is_none());
        assert!(stack.pop().is_none());
        assert!(stack.pop().is_none());
    }

    #[test]
    fn push_pop() {
        let stack = Arc::new(Treiber::new());
        let mut j = Vec::new();
        for _ in 0..16 {
            let s = stack.clone();
            j.push(thread::spawn(move || {
                for _ in 0..10_000_000 {
                    s.push(23);
                    assert_eq!(*s.pop().unwrap(), 23);
                }
            }));
        }

        for i in j {
            i.join().unwrap();
        }
    }

    #[test]
    fn increment() {
        let stack = Arc::new(Treiber::<u64>::new());
        let mut j = Vec::new();

        // 16 times, we add the numbers from 0 to 1000 to the only element in the stack.
        for _ in 0..16 {
            let s = stack.clone();
            j.push(thread::spawn(move || {
                for n in 0..1000 {
                    loop {
                        if let Some(x) = s.pop() {
                            s.push(*x + n);
                            break;
                        }
                    }
                }
            }));
        }

        for i in j {
            i.join().unwrap();
        }

        assert!(*stack.pop().unwrap() == 16 * 1000 * 1001 / 2);
    }

    #[test]
    fn sum() {
        let stack = Arc::new(Treiber::<i64>::new());
        let mut j = Vec::new();

        for _ in 0..1000 {
            stack.push(10);
        }

        // We preserve the sum of the stack's elements.
        for _ in 0..16 {
            let s = stack.clone();
            j.push(thread::spawn(move || {
                for _ in 0..100000 {
                    loop {
                        if let Some(a) = s.pop() {
                            loop {
                                if let Some(b) = s.pop() {
                                    s.push(*a + 1);
                                    s.push(*b - 1);

                                    break;
                                }
                            }

                            break;
                        }
                    }
                }
            }));
        }

        for i in j {
            i.join().unwrap();
        }

        let mut sum = 0;
        while let Some(x) = stack.pop() {
            sum += *x;
        }
        assert_eq!(sum, 10000);
    }
}
<commit_msg>Add simple single-threaded test to `conc::sync::Treiber`.<commit_after>//! Treiber stacks.

use std::sync::atomic;
use std::ptr;
use {Atomic, Guard};

/// A Treiber stack.
///
/// Treiber stacks are one way to implement concurrent LIFO stack.
///
/// Treiber stacks builds on linked lists. They are lock-free and non-blocking. It can be compared
/// to transactional memory in that it repeats operations, if another thread changes it while.
///
/// The ABA problem is of course addressed through the API of this crate.
pub struct Treiber<T> {
    /// The head node.
    head: Atomic<Node<T>>,
}

/// A node in the stack.
struct Node<T> {
    /// The data this node holds.
    data: T,
    /// The next node.
    next: *const Node<T>,
}

impl<T> Treiber<T> {
    /// Create a new, empty Treiber stack.
    pub fn new() -> Treiber<T> {
        Treiber {
            head: Atomic::default(),
        }
    }

    /// Pop an item from the stack.
    pub fn pop(&self) -> Option<Guard<T>> {
        // TODO: Use `catch {}` here when it lands.
        // Read the head snapshot.
        let mut snapshot = self.head.load(atomic::Ordering::Acquire);

        // Unless the head snapshot is `None`, try to replace it with the tail.
        while let Some(node) = snapshot {
            // Attempt to replace the head with the tail of the head.
            match unsafe {
                self.head.compare_and_swap_raw(
                    &*node,
                    node.next as *mut Node<T>,
                    atomic::Ordering::Release,
                )
            } {
                // It succeeded; return the item.
                Ok(_) => return Some(node.map(|x| &x.data)),
                // It failed, update the head snapshot and continue.
                Err(new) => snapshot = new,
            }
        }

        // As the head was empty, there is nothing to pop.
        None
    }

    /// Push an item to the stack.
    pub fn push(&self, item: T)
    where T: 'static {
        // Load the head snapshot.
        let mut snapshot = self.head.load(atomic::Ordering::Acquire);
        let mut snapshot_ptr: Option<*const Node<T>>;

        // TODO: Use `catch {}` here when it lands.
        // Construct a node, which will be the new head.
        let mut node = Box::new(Node {
            data: item,
            // Placeholder; we will replace it with an actual value in the loop.
            next: ptr::null(),
        });

        loop {
            // Derive the nullable snapshot pointer from the head snapshot.
            snapshot_ptr = snapshot.as_ref().map(Guard::as_raw);
            // Construct the next-pointer of the new node from the head snapshot.
            node.next = snapshot_ptr.unwrap_or(ptr::null());

            // TODO: This should be something that ignores the guard creation when the CAS
            //       succeeds, because it's expensive to do and not used anyway. It should be easy
            //       enough to implement, but I am struggling to come up with a good name for the
            //       method.

            // CAS from the read pointer to the new head.
            match self.head.compare_and_swap(snapshot_ptr, Some(node), atomic::Ordering::Release) {
                // If it succeeds, the item has been pushed.
                Ok(_) => break,
                // If it fails, we will retry the CAS with updated values.
                Err((new_head, Some(node2))) => {
                    // Update the head snapshot.
                    snapshot = new_head;
                    // Put the box we gave back to the variable where it belongs.
                    node = node2;
                },
                // This should never be reached as we gave an argument which was unconditionally
                // `Some`.
                _ => unreachable!(),
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::thread;
    use std::sync::Arc;

    #[test]
    fn simple() {
        let stack = Treiber::new();
        stack.push(1);
        stack.push(200);
        stack.push(44);

        assert_eq!(*stack.pop().unwrap(), 44);
        assert_eq!(*stack.pop().unwrap(), 200);
        assert_eq!(*stack.pop().unwrap(), 1);
        assert!(stack.pop().is_none());
    }

    #[test]
    fn single_thread() {
        let stack = Treiber::new();

        for i in 0..10000 {
            stack.push(i);
        }

        for i in (0..10000).rev() {
            assert_eq!(*stack.pop().unwrap(), i);
        }

        for i in 0..10000 {
            stack.push(i);
        }

        for i in (0..10000).rev() {
            assert_eq!(*stack.pop().unwrap(), i);
        }

        assert!(stack.pop().is_none());
        assert!(stack.pop().is_none());
        assert!(stack.pop().is_none());
        assert!(stack.pop().is_none());
    }

    #[test]
    fn push_pop() {
        let stack = Arc::new(Treiber::new());
        let mut j = Vec::new();
        for _ in 0..16 {
            let s = stack.clone();
            j.push(thread::spawn(move || {
                for _ in 0..10_000_000 {
                    s.push(23);
                    assert_eq!(*s.pop().unwrap(), 23);
                }
            }));
        }

        for i in j {
            i.join().unwrap();
        }
    }

    #[test]
    fn increment() {
        let stack = Arc::new(Treiber::<u64>::new());
        let mut j = Vec::new();

        // 16 times, we add the numbers from 0 to 1000 to the only element in the stack.
        for _ in 0..16 {
            let s = stack.clone();
            j.push(thread::spawn(move || {
                for n in 0..1000 {
                    loop {
                        if let Some(x) = s.pop() {
                            s.push(*x + n);
                            break;
                        }
                    }
                }
            }));
        }

        for i in j {
            i.join().unwrap();
        }

        assert!(*stack.pop().unwrap() == 16 * 1000 * 1001 / 2);
    }

    #[test]
    fn sum() {
        let stack = Arc::new(Treiber::<i64>::new());
        let mut j = Vec::new();

        for _ in 0..1000 {
            stack.push(10);
        }

        // We preserve the sum of the stack's elements.
        for _ in 0..16 {
            let s = stack.clone();
            j.push(thread::spawn(move || {
                for _ in 0..100000 {
                    loop {
                        if let Some(a) = s.pop() {
                            loop {
                                if let Some(b) = s.pop() {
                                    s.push(*a + 1);
                                    s.push(*b - 1);

                                    break;
                                }
                            }

                            break;
                        }
                    }
                }
            }));
        }

        for i in j {
            i.join().unwrap();
        }

        let mut sum = 0;
        while let Some(x) = stack.pop() {
            sum += *x;
        }
        assert_eq!(sum, 10000);
    }
}
<|endoftext|>