<commit_before>//! checks for attributes

use reexport::*;
use rustc::lint::*;
use rustc::hir::*;
use rustc::ty::{self, TyCtxt};
use semver::Version;
use syntax::ast::{Attribute, AttrStyle, Lit, LitKind, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
use syntax::codemap::Span;
use utils::{in_macro, match_def_path, opt_def_id, paths, snippet_opt, span_lint, span_lint_and_then};

/// **What it does:** Checks for items annotated with `#[inline(always)]`,
/// unless the annotated function is empty or simply panics.
///
/// **Why is this bad?** While there are valid uses of this annotation (and once
/// you know when to use it, by all means `allow` this lint), it's a common
/// newbie-mistake to pepper one's code with it.
///
/// As a rule of thumb, before slapping `#[inline(always)]` on a function,
/// measure if that additional function call really affects your runtime profile
/// sufficiently to make up for the increase in compile time.
///
/// **Known problems:** False positives, big time. This lint is meant to be
/// deactivated by everyone doing serious performance work. This means having
/// done the measurement.
///
/// **Example:**
/// ```rust
/// #[inline(always)]
/// fn not_quite_hot_code(..) { ... }
/// ```
declare_lint! {
    pub INLINE_ALWAYS,
    Warn,
    "use of `#[inline(always)]`"
}

/// **What it does:** Checks for `extern crate` and `use` items annotated with
/// lint attributes
///
/// **Why is this bad?** Lint attributes have no effect on crate imports. Most
/// likely a `!` was
/// forgotten
///
/// **Known problems:** Technically one might allow `unused_import` on a `use`
/// item,
/// but it's easier to remove the unused item.
///
/// **Example:**
/// ```rust
/// #[deny(dead_code)]
/// extern crate foo;
/// #[allow(unused_import)]
/// use foo::bar;
/// ```
declare_lint! {
    pub USELESS_ATTRIBUTE,
    Warn,
    "use of lint attributes on `extern crate` items"
}

/// **What it does:** Checks for `#[deprecated]` annotations with a `since`
/// field that is not a valid semantic version.
///
/// **Why is this bad?** For checking the version of the deprecation, it must be
/// a valid semver. Failing that, the contained information is useless.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// #[deprecated(since = "forever")]
/// fn something_else(..) { ... }
/// ```
declare_lint! {
    pub DEPRECATED_SEMVER,
    Warn,
    "use of `#[deprecated(since = \"x\")]` where x is not semver"
}

/// **What it does:** Checks for empty lines after outer attributes
///
/// **Why is this bad?**
/// Most likely the attribute was meant to be an inner attribute using a '!'.
/// If it was meant to be an outer attribute, then the following item
/// should not be separated by empty lines.
///
/// **Known problems:** None
///
/// **Example:**
/// ```rust
/// // Bad
/// #[inline(always)]
///
/// fn not_quite_good_code(..) { ... }
///
/// // Good (as inner attribute)
/// #![inline(always)]
///
/// fn this_is_fine_too(..) { ... }
///
/// // Good (as outer attribute)
/// #[inline(always)]
/// fn this_is_fine(..) { ... }
///
/// ```
declare_lint! {
    pub EMPTY_LINE_AFTER_OUTER_ATTR,
    Warn,
    "empty line after outer attribute"
}

#[derive(Copy, Clone)]
pub struct AttrPass;

impl LintPass for AttrPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(INLINE_ALWAYS, DEPRECATED_SEMVER, USELESS_ATTRIBUTE, EMPTY_LINE_AFTER_OUTER_ATTR)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AttrPass {
    fn check_attribute(&mut self, cx: &LateContext<'a, 'tcx>, attr: &'tcx Attribute) {
        if let Some(ref items) = attr.meta_item_list() {
            if items.is_empty() || attr.name().map_or(true, |n| n != "deprecated") {
                return;
            }
            for item in items {
                if_chain! {
                    if let NestedMetaItemKind::MetaItem(ref mi) = item.node;
                    if let MetaItemKind::NameValue(ref lit) = mi.node;
                    if mi.name() == "since";
                    then {
                        check_semver(cx, item.span, lit);
                    }
                }
            }
        }
    }

    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
        if is_relevant_item(cx.tcx, item) {
            check_attrs(cx, item.span, &item.name, &item.attrs)
        }
        match item.node {
            ItemExternCrate(_) | ItemUse(_, _) => {
                for attr in &item.attrs {
                    if let Some(ref lint_list) = attr.meta_item_list() {
                        if let Some(name) = attr.name() {
                            match &*name.as_str() {
                                "allow" | "warn" | "deny" | "forbid" => {
                                    // whitelist `unused_imports` and `deprecated`
                                    for lint in lint_list {
                                        if is_word(lint, "unused_imports") || is_word(lint, "deprecated") {
                                            if let ItemUse(_, _) = item.node {
                                                return;
                                            }
                                        }
                                    }
                                    if let Some(mut sugg) = snippet_opt(cx, attr.span) {
                                        if sugg.len() > 1 {
                                            span_lint_and_then(
                                                cx,
                                                USELESS_ATTRIBUTE,
                                                attr.span,
                                                "useless lint attribute",
                                                |db| {
                                                    sugg.insert(1, '!');
                                                    db.span_suggestion(
                                                        attr.span,
                                                        "if you just forgot a `!`, use",
                                                        sugg,
                                                    );
                                                },
                                            );
                                        }
                                    }
                                },
                                _ => {},
                            }
                        }
                    }
                }
            },
            _ => {},
        }
    }

    fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx ImplItem) {
        if is_relevant_impl(cx.tcx, item) {
            check_attrs(cx, item.span, &item.name, &item.attrs)
        }
    }

    fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) {
        if is_relevant_trait(cx.tcx, item) {
            check_attrs(cx, item.span, &item.name, &item.attrs)
        }
    }
}

fn is_relevant_item(tcx: TyCtxt, item: &Item) -> bool {
    if let ItemFn(_, _, _, _, _, eid) = item.node {
        is_relevant_expr(tcx, tcx.body_tables(eid), &tcx.hir.body(eid).value)
    } else {
        true
    }
}

fn is_relevant_impl(tcx: TyCtxt, item: &ImplItem) -> bool {
    match item.node {
        ImplItemKind::Method(_, eid) => is_relevant_expr(tcx, tcx.body_tables(eid), &tcx.hir.body(eid).value),
        _ => false,
    }
}

fn is_relevant_trait(tcx: TyCtxt, item: &TraitItem) -> bool {
    match item.node {
        TraitItemKind::Method(_, TraitMethod::Required(_)) => true,
        TraitItemKind::Method(_, TraitMethod::Provided(eid)) => {
            is_relevant_expr(tcx, tcx.body_tables(eid), &tcx.hir.body(eid).value)
        },
        _ => false,
    }
}

fn is_relevant_block(tcx: TyCtxt, tables: &ty::TypeckTables, block: &Block) -> bool {
    if let Some(stmt) = block.stmts.first() {
        match stmt.node {
            StmtDecl(_, _) => true,
            StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => is_relevant_expr(tcx, tables, expr),
        }
    } else {
        block
            .expr
            .as_ref()
            .map_or(false, |e| is_relevant_expr(tcx, tables, e))
    }
}

fn is_relevant_expr(tcx: TyCtxt, tables: &ty::TypeckTables, expr: &Expr) -> bool {
    match expr.node {
        ExprBlock(ref block) => is_relevant_block(tcx, tables, block),
        ExprRet(Some(ref e)) => is_relevant_expr(tcx, tables, e),
        ExprRet(None) | ExprBreak(_, None) => false,
        ExprCall(ref path_expr, _) => if let ExprPath(ref qpath) = path_expr.node {
            if let Some(fun_id) = opt_def_id(tables.qpath_def(qpath, path_expr.hir_id)) {
                !match_def_path(tcx, fun_id, &paths::BEGIN_PANIC)
            } else {
                true
            }
        } else {
            true
        },
        _ => true,
    }
}

fn check_attrs(cx: &LateContext, span: Span, name: &Name, attrs: &[Attribute]) {
    if in_macro(span) {
        return;
    }

    for attr in attrs {
        if attr.style == AttrStyle::Outer {
            let attr_to_item_span = Span::new(attr.span.lo(), span.lo(), span.ctxt());

            if let Some(snippet) = snippet_opt(cx, attr_to_item_span) {
                let lines = snippet.split('\n').collect::<Vec<_>>();
                if lines.iter().filter(|l| l.trim().is_empty()).count() > 1 {
                    span_lint(
                        cx,
                        EMPTY_LINE_AFTER_OUTER_ATTR,
                        attr_to_item_span,
                        &format!("Found an empty line after an outer attribute. Perhaps you forgot to add a '!' to make it an inner attribute?")
                        );

                }
            }
        }

        if let Some(ref values) = attr.meta_item_list() {
            if values.len() != 1 || attr.name().map_or(true, |n| n != "inline") {
                continue;
            }
            if is_word(&values[0], "always") {
                span_lint(
                    cx,
                    INLINE_ALWAYS,
                    attr.span,
                    &format!(
                        "you have declared `#[inline(always)]` on `{}`. This is usually a bad idea",
                        name
                    ),
                );
            }
        }
    }
}

fn check_semver(cx: &LateContext, span: Span, lit: &Lit) {
    if let LitKind::Str(ref is, _) = lit.node {
        if Version::parse(&is.as_str()).is_ok() {
            return;
        }
    }
    span_lint(
        cx,
        DEPRECATED_SEMVER,
        span,
        "the since field must contain a semver-compliant version",
    );
}

fn is_word(nmi: &NestedMetaItem, expected: &str) -> bool {
    if let NestedMetaItemKind::MetaItem(ref mi) = nmi.node {
        mi.is_word() && mi.name() == expected
    } else {
        false
    }
}
<commit_msg>Add workaround for hidden outer attribute<commit_after>//! checks for attributes

use reexport::*;
use rustc::lint::*;
use rustc::hir::*;
use rustc::ty::{self, TyCtxt};
use semver::Version;
use syntax::ast::{Attribute, AttrStyle, Lit, LitKind, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
use syntax::codemap::Span;
use utils::{in_macro, match_def_path, opt_def_id, paths, snippet_opt, span_lint, span_lint_and_then};

/// **What it does:** Checks for items annotated with `#[inline(always)]`,
/// unless the annotated function is empty or simply panics.
///
/// **Why is this bad?** While there are valid uses of this annotation (and once
/// you know when to use it, by all means `allow` this lint), it's a common
/// newbie-mistake to pepper one's code with it.
///
/// As a rule of thumb, before slapping `#[inline(always)]` on a function,
/// measure if that additional function call really affects your runtime profile
/// sufficiently to make up for the increase in compile time.
///
/// **Known problems:** False positives, big time. This lint is meant to be
/// deactivated by everyone doing serious performance work. This means having
/// done the measurement.
///
/// **Example:**
/// ```rust
/// #[inline(always)]
/// fn not_quite_hot_code(..) { ... }
/// ```
declare_lint! {
    pub INLINE_ALWAYS,
    Warn,
    "use of `#[inline(always)]`"
}

/// **What it does:** Checks for `extern crate` and `use` items annotated with
/// lint attributes
///
/// **Why is this bad?** Lint attributes have no effect on crate imports. Most
/// likely a `!` was
/// forgotten
///
/// **Known problems:** Technically one might allow `unused_import` on a `use`
/// item,
/// but it's easier to remove the unused item.
///
/// **Example:**
/// ```rust
/// #[deny(dead_code)]
/// extern crate foo;
/// #[allow(unused_import)]
/// use foo::bar;
/// ```
declare_lint! {
    pub USELESS_ATTRIBUTE,
    Warn,
    "use of lint attributes on `extern crate` items"
}

/// **What it does:** Checks for `#[deprecated]` annotations with a `since`
/// field that is not a valid semantic version.
///
/// **Why is this bad?** For checking the version of the deprecation, it must be
/// a valid semver. Failing that, the contained information is useless.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// #[deprecated(since = "forever")]
/// fn something_else(..) { ... }
/// ```
declare_lint! {
    pub DEPRECATED_SEMVER,
    Warn,
    "use of `#[deprecated(since = \"x\")]` where x is not semver"
}

/// **What it does:** Checks for empty lines after outer attributes
///
/// **Why is this bad?**
/// Most likely the attribute was meant to be an inner attribute using a '!'.
/// If it was meant to be an outer attribute, then the following item
/// should not be separated by empty lines.
///
/// **Known problems:** None
///
/// **Example:**
/// ```rust
/// // Bad
/// #[inline(always)]
///
/// fn not_quite_good_code(..) { ... }
///
/// // Good (as inner attribute)
/// #![inline(always)]
///
/// fn this_is_fine_too(..) { ... }
///
/// // Good (as outer attribute)
/// #[inline(always)]
/// fn this_is_fine(..) { ... }
///
/// ```
declare_lint! {
    pub EMPTY_LINE_AFTER_OUTER_ATTR,
    Warn,
    "empty line after outer attribute"
}

#[derive(Copy, Clone)]
pub struct AttrPass;

impl LintPass for AttrPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(INLINE_ALWAYS, DEPRECATED_SEMVER, USELESS_ATTRIBUTE, EMPTY_LINE_AFTER_OUTER_ATTR)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AttrPass {
    fn check_attribute(&mut self, cx: &LateContext<'a, 'tcx>, attr: &'tcx Attribute) {
        if let Some(ref items) = attr.meta_item_list() {
            if items.is_empty() || attr.name().map_or(true, |n| n != "deprecated") {
                return;
            }
            for item in items {
                if_chain! {
                    if let NestedMetaItemKind::MetaItem(ref mi) = item.node;
                    if let MetaItemKind::NameValue(ref lit) = mi.node;
                    if mi.name() == "since";
                    then {
                        check_semver(cx, item.span, lit);
                    }
                }
            }
        }
    }

    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
        if is_relevant_item(cx.tcx, item) {
            check_attrs(cx, item.span, &item.name, &item.attrs)
        }
        match item.node {
            ItemExternCrate(_) | ItemUse(_, _) => {
                for attr in &item.attrs {
                    if let Some(ref lint_list) = attr.meta_item_list() {
                        if let Some(name) = attr.name() {
                            match &*name.as_str() {
                                "allow" | "warn" | "deny" | "forbid" => {
                                    // whitelist `unused_imports` and `deprecated`
                                    for lint in lint_list {
                                        if is_word(lint, "unused_imports") || is_word(lint, "deprecated") {
                                            if let ItemUse(_, _) = item.node {
                                                return;
                                            }
                                        }
                                    }
                                    if let Some(mut sugg) = snippet_opt(cx, attr.span) {
                                        if sugg.len() > 1 {
                                            span_lint_and_then(
                                                cx,
                                                USELESS_ATTRIBUTE,
                                                attr.span,
                                                "useless lint attribute",
                                                |db| {
                                                    sugg.insert(1, '!');
                                                    db.span_suggestion(
                                                        attr.span,
                                                        "if you just forgot a `!`, use",
                                                        sugg,
                                                    );
                                                },
                                            );
                                        }
                                    }
                                },
                                _ => {},
                            }
                        }
                    }
                }
            },
            _ => {},
        }
    }

    fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx ImplItem) {
        if is_relevant_impl(cx.tcx, item) {
            check_attrs(cx, item.span, &item.name, &item.attrs)
        }
    }

    fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) {
        if is_relevant_trait(cx.tcx, item) {
            check_attrs(cx, item.span, &item.name, &item.attrs)
        }
    }
}

fn is_relevant_item(tcx: TyCtxt, item: &Item) -> bool {
    if let ItemFn(_, _, _, _, _, eid) = item.node {
        is_relevant_expr(tcx, tcx.body_tables(eid), &tcx.hir.body(eid).value)
    } else {
        true
    }
}

fn is_relevant_impl(tcx: TyCtxt, item: &ImplItem) -> bool {
    match item.node {
        ImplItemKind::Method(_, eid) => is_relevant_expr(tcx, tcx.body_tables(eid), &tcx.hir.body(eid).value),
        _ => false,
    }
}

fn is_relevant_trait(tcx: TyCtxt, item: &TraitItem) -> bool {
    match item.node {
        TraitItemKind::Method(_, TraitMethod::Required(_)) => true,
        TraitItemKind::Method(_, TraitMethod::Provided(eid)) => {
            is_relevant_expr(tcx, tcx.body_tables(eid), &tcx.hir.body(eid).value)
        },
        _ => false,
    }
}

fn is_relevant_block(tcx: TyCtxt, tables: &ty::TypeckTables, block: &Block) -> bool {
    if let Some(stmt) = block.stmts.first() {
        match stmt.node {
            StmtDecl(_, _) => true,
            StmtExpr(ref expr, _) | StmtSemi(ref expr, _) => is_relevant_expr(tcx, tables, expr),
        }
    } else {
        block
            .expr
            .as_ref()
            .map_or(false, |e| is_relevant_expr(tcx, tables, e))
    }
}

fn is_relevant_expr(tcx: TyCtxt, tables: &ty::TypeckTables, expr: &Expr) -> bool {
    match expr.node {
        ExprBlock(ref block) => is_relevant_block(tcx, tables, block),
        ExprRet(Some(ref e)) => is_relevant_expr(tcx, tables, e),
        ExprRet(None) | ExprBreak(_, None) => false,
        ExprCall(ref path_expr, _) => if let ExprPath(ref qpath) = path_expr.node {
            if let Some(fun_id) = opt_def_id(tables.qpath_def(qpath, path_expr.hir_id)) {
                !match_def_path(tcx, fun_id, &paths::BEGIN_PANIC)
            } else {
                true
            }
        } else {
            true
        },
        _ => true,
    }
}

fn check_attrs(cx: &LateContext, span: Span, name: &Name, attrs: &[Attribute]) {
    if in_macro(span) {
        return;
    }

    for attr in attrs {
        if attr.style == AttrStyle::Outer {
            if !is_present_in_source(cx, attr.span) {
                return;
            }

            let attr_to_item_span = Span::new(attr.span.lo(), span.lo(), span.ctxt());

            if let Some(snippet) = snippet_opt(cx, attr_to_item_span) {
                let lines = snippet.split('\n').collect::<Vec<_>>();
                if lines.iter().filter(|l| l.trim().is_empty()).count() > 1 {
                    span_lint(
                        cx,
                        EMPTY_LINE_AFTER_OUTER_ATTR,
                        attr_to_item_span,
                        &format!("Found an empty line after an outer attribute. Perhaps you forgot to add a '!' to make it an inner attribute?")
                        );

                }
            }
        }

        if let Some(ref values) = attr.meta_item_list() {
            if values.len() != 1 || attr.name().map_or(true, |n| n != "inline") {
                continue;
            }
            if is_word(&values[0], "always") {
                span_lint(
                    cx,
                    INLINE_ALWAYS,
                    attr.span,
                    &format!(
                        "you have declared `#[inline(always)]` on `{}`. This is usually a bad idea",
                        name
                    ),
                );
            }
        }
    }
}

fn check_semver(cx: &LateContext, span: Span, lit: &Lit) {
    if let LitKind::Str(ref is, _) = lit.node {
        if Version::parse(&is.as_str()).is_ok() {
            return;
        }
    }
    span_lint(
        cx,
        DEPRECATED_SEMVER,
        span,
        "the since field must contain a semver-compliant version",
    );
}

fn is_word(nmi: &NestedMetaItem, expected: &str) -> bool {
    if let NestedMetaItemKind::MetaItem(ref mi) = nmi.node {
        mi.is_word() && mi.name() == expected
    } else {
        false
    }
}

// If the snippet is empty, it's an attribute that was inserted during macro
// expansion and we want to ignore those, because they could come from external
// sources that the user has no control over.
// For some reason these attributes don't have any expansion info on them, so
// we have to check it this way until there is a better way.
fn is_present_in_source(cx: &LateContext, span: Span) -> bool {
    if let Some(snippet) = snippet_opt(cx, span) {
        if snippet.is_empty() {
            return false;
        }
    }
    true
}
<|endoftext|>


<commit_before>use ra_syntax::{
    ast::{self, NameOwner, VisibilityOwner},
    AstNode,
    SyntaxKind::{CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY},
    T,
};
use test_utils::mark;

use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists};

// Assist: change_visibility
//
// Adds or changes existing visibility specifier.
//
// ```
// <|>fn frobnicate() {}
// ```
// ->
// ```
// pub(crate) fn frobnicate() {}
// ```
pub(crate) fn change_visibility(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    if let Some(vis) = ctx.find_node_at_offset::<ast::Visibility>() {
        return change_vis(acc, vis);
    }
    add_vis(acc, ctx)
}

fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let item_keyword = ctx.token_at_offset().find(|leaf| {
        matches!(leaf.kind(), T![const] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait])
    });

    let (offset, target) = if let Some(keyword) = item_keyword {
        let parent = keyword.parent();
        let def_kws = vec![CONST_DEF, FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF];
        // Parent is not a definition, can't add visibility
        if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) {
            return None;
        }
        // Already have visibility, do nothing
        if parent.children().any(|child| child.kind() == VISIBILITY) {
            return None;
        }
        (vis_offset(&parent), keyword.text_range())
    } else if let Some(field_name) = ctx.find_node_at_offset::<ast::Name>() {
        let field = field_name.syntax().ancestors().find_map(ast::RecordFieldDef::cast)?;
        if field.name()? != field_name {
            mark::hit!(change_visibility_field_false_positive);
            return None;
        }
        if field.visibility().is_some() {
            return None;
        }
        (vis_offset(field.syntax()), field_name.syntax().text_range())
    } else if let Some(field) = ctx.find_node_at_offset::<ast::TupleFieldDef>() {
        if field.visibility().is_some() {
            return None;
        }
        (vis_offset(field.syntax()), field.syntax().text_range())
    } else {
        return None;
    };

    acc.add(
        AssistId("change_visibility", AssistKind::RefactorRewrite),
        "Change visibility to pub(crate)",
        target,
        |edit| {
            edit.insert(offset, "pub(crate) ");
        },
    )
}

fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> {
    if vis.syntax().text() == "pub" {
        let target = vis.syntax().text_range();
        return acc.add(
            AssistId("change_visibility", AssistKind::RefactorRewrite),
            "Change Visibility to pub(crate)",
            target,
            |edit| {
                edit.replace(vis.syntax().text_range(), "pub(crate)");
            },
        );
    }
    if vis.syntax().text() == "pub(crate)" {
        let target = vis.syntax().text_range();
        return acc.add(
            AssistId("change_visibility", AssistKind::RefactorRewrite),
            "Change visibility to pub",
            target,
            |edit| {
                edit.replace(vis.syntax().text_range(), "pub");
            },
        );
    }
    None
}

#[cfg(test)]
mod tests {
    use test_utils::mark;

    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};

    use super::*;

    #[test]
    fn change_visibility_adds_pub_crate_to_items() {
        check_assist(change_visibility, "<|>fn foo() {}", "pub(crate) fn foo() {}");
        check_assist(change_visibility, "f<|>n foo() {}", "pub(crate) fn foo() {}");
        check_assist(change_visibility, "<|>struct Foo {}", "pub(crate) struct Foo {}");
        check_assist(change_visibility, "<|>mod foo {}", "pub(crate) mod foo {}");
        check_assist(change_visibility, "<|>trait Foo {}", "pub(crate) trait Foo {}");
        check_assist(change_visibility, "m<|>od {}", "pub(crate) mod {}");
        check_assist(change_visibility, "unsafe f<|>n foo() {}", "pub(crate) unsafe fn foo() {}");
    }

    #[test]
    fn change_visibility_works_with_struct_fields() {
        check_assist(
            change_visibility,
            r"struct S { <|>field: u32 }",
            r"struct S { pub(crate) field: u32 }",
        );
        check_assist(change_visibility, r"struct S ( <|>u32 )", r"struct S ( pub(crate) u32 )");
    }

    #[test]
    fn change_visibility_field_false_positive() {
        mark::check!(change_visibility_field_false_positive);
        check_assist_not_applicable(
            change_visibility,
            r"struct S { field: [(); { let <|>x = ();}] }",
        )
    }

    #[test]
    fn change_visibility_pub_to_pub_crate() {
        check_assist(change_visibility, "<|>pub fn foo() {}", "pub(crate) fn foo() {}")
    }

    #[test]
    fn change_visibility_pub_crate_to_pub() {
        check_assist(change_visibility, "<|>pub(crate) fn foo() {}", "pub fn foo() {}")
    }

    #[test]
    fn change_visibility_const() {
        check_assist(change_visibility, "<|>const FOO = 3u8;", "pub(crate) const FOO = 3u8;");
    }

    #[test]
    fn change_visibility_handles_comment_attrs() {
        check_assist(
            change_visibility,
            r"
            /// docs

            // comments

            #[derive(Debug)]
            <|>struct Foo;
            ",
            r"
            /// docs

            // comments

            #[derive(Debug)]
            pub(crate) struct Foo;
            ",
        )
    }

    #[test]
    fn not_applicable_for_enum_variants() {
        check_assist_not_applicable(
            change_visibility,
            r"mod foo { pub enum Foo {Foo1} }
              fn main() { foo::Foo::Foo1<|> } ",
        );
    }

    #[test]
    fn change_visibility_target() {
        check_assist_target(change_visibility, "<|>fn foo() {}", "fn");
        check_assist_target(change_visibility, "pub(crate)<|> fn foo() {}", "pub(crate)");
        check_assist_target(change_visibility, "struct S { <|>field: u32 }", "field");
    }
}
<commit_msg>change vis works on statics<commit_after>use ra_syntax::{
    ast::{self, NameOwner, VisibilityOwner},
    AstNode,
    SyntaxKind::{
        CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STATIC_DEF, STRUCT_DEF, TRAIT_DEF, VISIBILITY,
    },
    T,
};
use test_utils::mark;

use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists};

// Assist: change_visibility
//
// Adds or changes existing visibility specifier.
//
// ```
// <|>fn frobnicate() {}
// ```
// ->
// ```
// pub(crate) fn frobnicate() {}
// ```
pub(crate) fn change_visibility(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    if let Some(vis) = ctx.find_node_at_offset::<ast::Visibility>() {
        return change_vis(acc, vis);
    }
    add_vis(acc, ctx)
}

fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let item_keyword = ctx.token_at_offset().find(|leaf| {
        matches!(
            leaf.kind(),
            T![const] | T![static] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait]
        )
    });

    let (offset, target) = if let Some(keyword) = item_keyword {
        let parent = keyword.parent();
        let def_kws = vec![CONST_DEF, STATIC_DEF, FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF];
        // Parent is not a definition, can't add visibility
        if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) {
            return None;
        }
        // Already have visibility, do nothing
        if parent.children().any(|child| child.kind() == VISIBILITY) {
            return None;
        }
        (vis_offset(&parent), keyword.text_range())
    } else if let Some(field_name) = ctx.find_node_at_offset::<ast::Name>() {
        let field = field_name.syntax().ancestors().find_map(ast::RecordFieldDef::cast)?;
        if field.name()? != field_name {
            mark::hit!(change_visibility_field_false_positive);
            return None;
        }
        if field.visibility().is_some() {
            return None;
        }
        (vis_offset(field.syntax()), field_name.syntax().text_range())
    } else if let Some(field) = ctx.find_node_at_offset::<ast::TupleFieldDef>() {
        if field.visibility().is_some() {
            return None;
        }
        (vis_offset(field.syntax()), field.syntax().text_range())
    } else {
        return None;
    };

    acc.add(
        AssistId("change_visibility", AssistKind::RefactorRewrite),
        "Change visibility to pub(crate)",
        target,
        |edit| {
            edit.insert(offset, "pub(crate) ");
        },
    )
}

fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> {
    if vis.syntax().text() == "pub" {
        let target = vis.syntax().text_range();
        return acc.add(
            AssistId("change_visibility", AssistKind::RefactorRewrite),
            "Change Visibility to pub(crate)",
            target,
            |edit| {
                edit.replace(vis.syntax().text_range(), "pub(crate)");
            },
        );
    }
    if vis.syntax().text() == "pub(crate)" {
        let target = vis.syntax().text_range();
        return acc.add(
            AssistId("change_visibility", AssistKind::RefactorRewrite),
            "Change visibility to pub",
            target,
            |edit| {
                edit.replace(vis.syntax().text_range(), "pub");
            },
        );
    }
    None
}

#[cfg(test)]
mod tests {
    use test_utils::mark;

    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};

    use super::*;

    #[test]
    fn change_visibility_adds_pub_crate_to_items() {
        check_assist(change_visibility, "<|>fn foo() {}", "pub(crate) fn foo() {}");
        check_assist(change_visibility, "f<|>n foo() {}", "pub(crate) fn foo() {}");
        check_assist(change_visibility, "<|>struct Foo {}", "pub(crate) struct Foo {}");
        check_assist(change_visibility, "<|>mod foo {}", "pub(crate) mod foo {}");
        check_assist(change_visibility, "<|>trait Foo {}", "pub(crate) trait Foo {}");
        check_assist(change_visibility, "m<|>od {}", "pub(crate) mod {}");
        check_assist(change_visibility, "unsafe f<|>n foo() {}", "pub(crate) unsafe fn foo() {}");
    }

    #[test]
    fn change_visibility_works_with_struct_fields() {
        check_assist(
            change_visibility,
            r"struct S { <|>field: u32 }",
            r"struct S { pub(crate) field: u32 }",
        );
        check_assist(change_visibility, r"struct S ( <|>u32 )", r"struct S ( pub(crate) u32 )");
    }

    #[test]
    fn change_visibility_field_false_positive() {
        mark::check!(change_visibility_field_false_positive);
        check_assist_not_applicable(
            change_visibility,
            r"struct S { field: [(); { let <|>x = ();}] }",
        )
    }

    #[test]
    fn change_visibility_pub_to_pub_crate() {
        check_assist(change_visibility, "<|>pub fn foo() {}", "pub(crate) fn foo() {}")
    }

    #[test]
    fn change_visibility_pub_crate_to_pub() {
        check_assist(change_visibility, "<|>pub(crate) fn foo() {}", "pub fn foo() {}")
    }

    #[test]
    fn change_visibility_const() {
        check_assist(change_visibility, "<|>const FOO = 3u8;", "pub(crate) const FOO = 3u8;");
    }

    #[test]
    fn change_visibility_static() {
        check_assist(change_visibility, "<|>static FOO = 3u8;", "pub(crate) static FOO = 3u8;");
    }

    #[test]
    fn change_visibility_handles_comment_attrs() {
        check_assist(
            change_visibility,
            r"
            /// docs

            // comments

            #[derive(Debug)]
            <|>struct Foo;
            ",
            r"
            /// docs

            // comments

            #[derive(Debug)]
            pub(crate) struct Foo;
            ",
        )
    }

    #[test]
    fn not_applicable_for_enum_variants() {
        check_assist_not_applicable(
            change_visibility,
            r"mod foo { pub enum Foo {Foo1} }
              fn main() { foo::Foo::Foo1<|> } ",
        );
    }

    #[test]
    fn change_visibility_target() {
        check_assist_target(change_visibility, "<|>fn foo() {}", "fn");
        check_assist_target(change_visibility, "pub(crate)<|> fn foo() {}", "pub(crate)");
        check_assist_target(change_visibility, "struct S { <|>field: u32 }", "field");
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate bitflags;

#[macro_use]
extern crate nom;

#[macro_use]
extern crate downcast_rs;

pub use aspect_ratio::{
    FitMode,
    AlignMode,
    Align,
    AspectRatio,
    ParseAspectRatioError,
    rsvg_aspect_ratio_parse,
    rsvg_aspect_ratio_compute
};

pub use bbox::{
    RsvgBbox,
    rsvg_bbox_init,
    rsvg_bbox_insert,
    rsvg_bbox_clip
};

pub use cnode::{
    rsvg_rust_cnode_new,
    rsvg_rust_cnode_get_impl
};

pub use gradient::{
    gradient_linear_new,
    gradient_radial_new,
    gradient_destroy,
    gradient_add_color_stop,
    gradient_resolve_fallbacks_and_set_pattern
};

pub use length::{
    LengthUnit,
    LengthDir,
    RsvgLength,
    rsvg_length_parse,
    rsvg_length_normalize,
    rsvg_length_hand_normalize,
};

pub use marker::{
    rsvg_node_marker_new,
};

pub use node::{
    rsvg_node_get_type,
    rsvg_node_get_parent,
    rsvg_node_ref,
    rsvg_node_unref,
    rsvg_node_is_same,
    rsvg_node_get_state,
    rsvg_node_add_child,
    rsvg_node_set_atts,
    rsvg_node_draw,
    rsvg_node_foreach_child,
};

pub use path_builder::{
    rsvg_path_builder_new,
    rsvg_path_builder_destroy,
    rsvg_path_builder_move_to,
    rsvg_path_builder_line_to,
    rsvg_path_builder_curve_to,
    rsvg_path_builder_close_path,
    rsvg_path_builder_arc,
    rsvg_path_builder_add_to_cairo_context
};

pub use path_parser::{
    rsvg_path_parser_from_str_into_builder
};

pub use pattern::{
    pattern_new,
    pattern_destroy,
    pattern_resolve_fallbacks_and_set_pattern,
};

pub use shapes::{
    rsvg_node_circle_new,
    rsvg_node_ellipse_new,
    rsvg_node_line_new,
    rsvg_node_path_new,
    rsvg_node_polygon_new,
    rsvg_node_polyline_new,
    rsvg_node_rect_new,
};
pub use viewbox::{
    RsvgViewBox
};

mod aspect_ratio;
mod bbox;
mod cnode;
mod drawing_ctx;
mod handle;
mod gradient;
mod length;
mod marker;
mod node;
mod parsers;
mod path_builder;
mod path_parser;
mod pattern;
mod property_bag;
mod state;
mod shapes;
mod strtod;
mod util;
mod viewbox;
<commit_msg>lib.rs: Don't include strtod.rs for now<commit_after>#[macro_use]
extern crate bitflags;

#[macro_use]
extern crate nom;

#[macro_use]
extern crate downcast_rs;

pub use aspect_ratio::{
    FitMode,
    AlignMode,
    Align,
    AspectRatio,
    ParseAspectRatioError,
    rsvg_aspect_ratio_parse,
    rsvg_aspect_ratio_compute
};

pub use bbox::{
    RsvgBbox,
    rsvg_bbox_init,
    rsvg_bbox_insert,
    rsvg_bbox_clip
};

pub use cnode::{
    rsvg_rust_cnode_new,
    rsvg_rust_cnode_get_impl
};

pub use gradient::{
    gradient_linear_new,
    gradient_radial_new,
    gradient_destroy,
    gradient_add_color_stop,
    gradient_resolve_fallbacks_and_set_pattern
};

pub use length::{
    LengthUnit,
    LengthDir,
    RsvgLength,
    rsvg_length_parse,
    rsvg_length_normalize,
    rsvg_length_hand_normalize,
};

pub use marker::{
    rsvg_node_marker_new,
};

pub use node::{
    rsvg_node_get_type,
    rsvg_node_get_parent,
    rsvg_node_ref,
    rsvg_node_unref,
    rsvg_node_is_same,
    rsvg_node_get_state,
    rsvg_node_add_child,
    rsvg_node_set_atts,
    rsvg_node_draw,
    rsvg_node_foreach_child,
};

pub use path_builder::{
    rsvg_path_builder_new,
    rsvg_path_builder_destroy,
    rsvg_path_builder_move_to,
    rsvg_path_builder_line_to,
    rsvg_path_builder_curve_to,
    rsvg_path_builder_close_path,
    rsvg_path_builder_arc,
    rsvg_path_builder_add_to_cairo_context
};

pub use path_parser::{
    rsvg_path_parser_from_str_into_builder
};

pub use pattern::{
    pattern_new,
    pattern_destroy,
    pattern_resolve_fallbacks_and_set_pattern,
};

pub use shapes::{
    rsvg_node_circle_new,
    rsvg_node_ellipse_new,
    rsvg_node_line_new,
    rsvg_node_path_new,
    rsvg_node_polygon_new,
    rsvg_node_polyline_new,
    rsvg_node_rect_new,
};
pub use viewbox::{
    RsvgViewBox
};

mod aspect_ratio;
mod bbox;
mod cnode;
mod drawing_ctx;
mod handle;
mod gradient;
mod length;
mod marker;
mod node;
mod parsers;
mod path_builder;
mod path_parser;
mod pattern;
mod property_bag;
mod state;
mod shapes;
mod util;
mod viewbox;
<|endoftext|>


<commit_before>use num::Num;
use ncast::*;
use ntrait::Float;
use funs::exp::Exp;
use funs::trig::*;
use matrix::Mat4;

pub fn mat4_from_rotation<T:Copy Num NumCast AngleConv Trig>(theta: T, axis: Vec3<T>) -> Mat4<T> {
    let rad = radians(&theta);
    let c:  T = cos(&rad);
    let s:  T = sin(&rad);
    let _0: T = cast(0);
    let _1: T = cast(1);
    let t:  T = _1 - c;

    Mat4::new(t * axis.x * axis.x + c,          t * axis.x * axis.y + s * axis.z, t * axis.x * axis.z - s * axis.y, _0,
              t * axis.x * axis.y - s * axis.z, t * axis.y * axis.y + c,          t * axis.y * axis.z + s * axis.x, _0,
              t * axis.x * axis.z - s - axis.y, t * axis.y * axis.z - s * axis.x, t * axis.z * axis.z + c,          _0,
              _0, _0, _0, _1)
}<commit_msg>Fix purity<commit_after>use num::Num;
use ncast::*;
use ntrait::Float;
use funs::exp::Exp;
use funs::trig::*;
use matrix::Mat4;

pub pure fn mat4_from_rotation<T:Copy Num NumCast AngleConv Trig>(theta: T, axis: Vec3<T>) -> Mat4<T> {
    let rad = radians(&theta);
    let c:  T = cos(&rad);
    let s:  T = sin(&rad);
    let _0: T = cast(0);
    let _1: T = cast(1);
    let t:  T = _1 - c;

    Mat4::new(t * axis.x * axis.x + c,          t * axis.x * axis.y + s * axis.z, t * axis.x * axis.z - s * axis.y, _0,
              t * axis.x * axis.y - s * axis.z, t * axis.y * axis.y + c,          t * axis.y * axis.z + s * axis.x, _0,
              t * axis.x * axis.z - s - axis.y, t * axis.y * axis.z - s * axis.x, t * axis.z * axis.z + c,          _0,
              _0, _0, _0, _1)
}<|endoftext|>


<commit_before>use std::io;
use std::rand;

fn my_random(min: uint, max: uint) -> uint {
    (rand::random::<uint>() %  max ) +  min
}

fn main() {
    println!("Guess the number!");

    let secret = my_random(1u, 200u);
    //println!("The secret number is: {}", secret);
    println!("Please input your guess.");

    loop {
        let input = io::stdin().read_line()
            .ok()
            .expect("Failed to read line");

        let input_num  = match from_str::<uint>(input.as_slice().trim()) {
            Some(num) => num,
            None => {
                println!("Please input a number!");
                continue;
            },
        };

        println!("You guessed: {}", input_num);
        match cmp(input_num, secret) {
            Less => println!("Too Small!"),
            Greater => println!("Too big!"),
            Equal => {
                println!("You win!");
                return;
            },
        }
    }
}

fn cmp(a: uint, b: uint) -> Ordering {
    if a < b { Less }
    else if a > b { Greater }
    else { Equal }
}
<commit_msg>fix guessing game example<commit_after>#![feature(rand)]
#![feature(old_io)]
#![allow(deprecated)]
use std::old_io as io;
use std::rand;
use std::cmp::Ordering;

fn my_random(min: usize, max: usize) -> usize {
    (rand::random::<usize>() %  max ) +  min
}

fn main() {
    println!("Guess the number!");

    let secret = my_random(1us, 200us);
    //println!("The secret number is: {}", secret);
    println!("Please input your guess, between 1 and 200");

    loop {
        let input = io::stdin().read_line()
            .ok()
            .expect("Failed to read line");

        let input_trim = input.trim();
        let input_parse = input_trim.parse::<usize>();
        let input_num  = match input_parse {
            Ok(num) => num,
            Err(_) => {
                println!("Please input a number!");
                continue;
            },
        };

        println!("You guessed: {}", input_num);
        match cmp(input_num, secret) {
            Ordering::Less => println!("Too Small!"),
            Ordering::Greater => println!("Too big!"),
            Ordering::Equal => {
                println!("You win!");
                return;
            },
        }
    }
}

fn cmp(a: usize, b: usize) -> Ordering {
    if a < b { Ordering::Less }
    else if a > b { Ordering::Greater }
    else { Ordering::Equal }
}
<|endoftext|>


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

use chrono::NaiveDateTime;
use diesel::prelude::*;

use crate::util::errors::{cargo_err, AppResult};

use crate::models::{Crate, Dependency, User, VersionOwnerAction};
use crate::schema::*;
use crate::views::{EncodableAuditAction, EncodableVersion, EncodableVersionLinks};

// Queryable has a custom implementation below
#[derive(Clone, Identifiable, Associations, Debug, Queryable, Deserialize, Serialize)]
#[belongs_to(Crate)]
pub struct Version {
    pub id: i32,
    pub crate_id: i32,
    pub num: semver::Version,
    pub updated_at: NaiveDateTime,
    pub created_at: NaiveDateTime,
    pub downloads: i32,
    pub features: serde_json::Value,
    pub yanked: bool,
    pub license: Option<String>,
    pub crate_size: Option<i32>,
    pub published_by: Option<i32>,
}

#[derive(Insertable, Debug)]
#[table_name = "versions"]
pub struct NewVersion {
    crate_id: i32,
    num: String,
    features: serde_json::Value,
    license: Option<String>,
    crate_size: Option<i32>,
    published_by: i32,
}

/// The highest version (semver order) and the most recently updated version.
/// Typically used for a single crate.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct TopVersions {
    pub highest: semver::Version,
    pub newest: semver::Version,
}

/// A default semver value, "0.0.0", for use in TopVersions
fn default_semver_version() -> semver::Version {
    semver::Version {
        major: 0,
        minor: 0,
        patch: 0,
        pre: vec![],
        build: vec![],
    }
}

impl Version {
    pub fn encodable(
        self,
        crate_name: &str,
        published_by: Option<User>,
        audit_actions: Vec<(VersionOwnerAction, User)>,
    ) -> EncodableVersion {
        let Version {
            id,
            num,
            updated_at,
            created_at,
            downloads,
            features,
            yanked,
            license,
            crate_size,
            ..
        } = self;
        let num = num.to_string();
        EncodableVersion {
            dl_path: format!("/api/v1/crates/{}/{}/download", crate_name, num),
            readme_path: format!("/api/v1/crates/{}/{}/readme", crate_name, num),
            num: num.clone(),
            id,
            krate: crate_name.to_string(),
            updated_at,
            created_at,
            downloads,
            features,
            yanked,
            license,
            links: EncodableVersionLinks {
                dependencies: format!("/api/v1/crates/{}/{}/dependencies", crate_name, num),
                version_downloads: format!("/api/v1/crates/{}/{}/downloads", crate_name, num),
                authors: format!("/api/v1/crates/{}/{}/authors", crate_name, num),
            },
            crate_size,
            published_by: published_by.map(User::into),
            audit_actions: audit_actions
                .into_iter()
                .map(|(audit_action, user)| EncodableAuditAction {
                    action: audit_action.action.into(),
                    user: user.into(),
                    time: audit_action.time,
                })
                .collect(),
        }
    }

    /// Returns (dependency, crate dependency name)
    pub fn dependencies(&self, conn: &PgConnection) -> QueryResult<Vec<(Dependency, String)>> {
        Dependency::belonging_to(self)
            .inner_join(crates::table)
            .select((dependencies::all_columns, crates::name))
            .order((dependencies::optional, crates::name))
            .load(conn)
    }

    /// Return both the newest (most recently updated) and the
    /// highest version (in semver order) for a collection of date/version pairs.
    pub fn top<T>(pairs: T) -> TopVersions
    where
        T: Clone + IntoIterator<Item = (NaiveDateTime, semver::Version)>,
    {
        TopVersions {
            newest: pairs
                .clone()
                .into_iter()
                .max()
                .unwrap_or((
                    NaiveDateTime::from_timestamp(0, 0),
                    default_semver_version(),
                ))
                .1,
            highest: pairs
                .into_iter()
                .map(|(_, v)| v)
                .max()
                .unwrap_or_else(default_semver_version),
        }
    }

    pub fn record_readme_rendering(version_id_: i32, conn: &PgConnection) -> QueryResult<usize> {
        use crate::schema::readme_renderings::dsl::*;
        use diesel::dsl::now;

        diesel::insert_into(readme_renderings)
            .values(version_id.eq(version_id_))
            .on_conflict(version_id)
            .do_update()
            .set(rendered_at.eq(now))
            .execute(conn)
    }

    /// Gets the User who ran `cargo publish` for this version, if recorded.
    /// Not for use when you have a group of versions you need the publishers for.
    pub fn published_by(&self, conn: &PgConnection) -> Option<User> {
        match self.published_by {
            Some(pb) => users::table.find(pb).first(conn).ok(),
            None => None,
        }
    }
}

impl NewVersion {
    pub fn new(
        crate_id: i32,
        num: &semver::Version,
        features: &HashMap<String, Vec<String>>,
        license: Option<String>,
        license_file: Option<&str>,
        crate_size: i32,
        published_by: i32,
    ) -> AppResult<Self> {
        let features = serde_json::to_value(features)?;

        let mut new_version = NewVersion {
            crate_id,
            num: num.to_string(),
            features,
            license,
            crate_size: Some(crate_size),
            published_by,
        };

        new_version.validate_license(license_file)?;

        Ok(new_version)
    }

    pub fn save(
        &self,
        conn: &PgConnection,
        authors: &[String],
        published_by_email: &str,
    ) -> AppResult<Version> {
        use crate::schema::version_authors::{name, version_id};
        use crate::schema::versions::dsl::*;
        use diesel::dsl::exists;
        use diesel::{insert_into, select};

        conn.transaction(|| {
            let already_uploaded = versions
                .filter(crate_id.eq(self.crate_id))
                .filter(num.eq(&self.num));
            if select(exists(already_uploaded)).get_result(conn)? {
                return Err(cargo_err(&format_args!(
                    "crate version `{}` is already \
                     uploaded",
                    self.num
                )));
            }

            let version: Version = insert_into(versions).values(self).get_result(conn)?;

            insert_into(versions_published_by::table)
                .values((
                    versions_published_by::version_id.eq(version.id),
                    versions_published_by::email.eq(published_by_email),
                ))
                .execute(conn)?;

            let new_authors = authors
                .iter()
                .map(|s| (version_id.eq(version.id), name.eq(s)))
                .collect::<Vec<_>>();

            insert_into(version_authors::table)
                .values(&new_authors)
                .execute(conn)?;
            Ok(version)
        })
    }

    fn validate_license(&mut self, license_file: Option<&str>) -> AppResult<()> {
        if let Some(ref license) = self.license {
            for part in license.split('/') {
                license_exprs::validate_license_expr(part).map_err(|e| {
                    cargo_err(&format_args!(
                        "{}; see http://opensource.org/licenses \
                         for options, and http://spdx.org/licenses/ \
                         for their identifiers",
                        e
                    ))
                })?;
            }
        } else if license_file.is_some() {
            // If no license is given, but a license file is given, flag this
            // crate as having a nonstandard license. Note that we don't
            // actually do anything else with license_file currently.
            self.license = Some(String::from("non-standard"));
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::{TopVersions, Version};
    use chrono::NaiveDateTime;

    #[track_caller]
    fn date(str: &str) -> NaiveDateTime {
        str.parse().unwrap()
    }

    #[track_caller]
    fn version(str: &str) -> semver::Version {
        semver::Version::parse(str).unwrap()
    }

    #[test]
    fn top_versions_empty() {
        let versions = vec![];
        assert_eq!(
            Version::top(versions),
            TopVersions {
                highest: version("0.0.0"),
                newest: version("0.0.0"),
            }
        );
    }

    #[test]
    fn top_versions_single() {
        let versions = vec![(date("2020-12-03T12:34:56"), version("1.0.0"))];
        assert_eq!(
            Version::top(versions),
            TopVersions {
                highest: version("1.0.0"),
                newest: version("1.0.0"),
            }
        );
    }

    #[test]
    fn top_versions_multiple() {
        let versions = vec![
            (date("2018-12-03T12:34:56"), version("1.0.0")),
            (date("2019-12-03T12:34:56"), version("2.0.0-alpha.1")),
            (date("2020-12-03T12:34:56"), version("1.1.0")),
        ];
        assert_eq!(
            Version::top(versions),
            TopVersions {
                highest: version("2.0.0-alpha.1"),
                newest: version("1.1.0"),
            }
        );
    }
}
<commit_msg>models/version: Extract `TopVersions::from_date_version_pairs()` constructor<commit_after>use std::collections::HashMap;

use chrono::NaiveDateTime;
use diesel::prelude::*;

use crate::util::errors::{cargo_err, AppResult};

use crate::models::{Crate, Dependency, User, VersionOwnerAction};
use crate::schema::*;
use crate::views::{EncodableAuditAction, EncodableVersion, EncodableVersionLinks};

// Queryable has a custom implementation below
#[derive(Clone, Identifiable, Associations, Debug, Queryable, Deserialize, Serialize)]
#[belongs_to(Crate)]
pub struct Version {
    pub id: i32,
    pub crate_id: i32,
    pub num: semver::Version,
    pub updated_at: NaiveDateTime,
    pub created_at: NaiveDateTime,
    pub downloads: i32,
    pub features: serde_json::Value,
    pub yanked: bool,
    pub license: Option<String>,
    pub crate_size: Option<i32>,
    pub published_by: Option<i32>,
}

#[derive(Insertable, Debug)]
#[table_name = "versions"]
pub struct NewVersion {
    crate_id: i32,
    num: String,
    features: serde_json::Value,
    license: Option<String>,
    crate_size: Option<i32>,
    published_by: i32,
}

/// The highest version (semver order) and the most recently updated version.
/// Typically used for a single crate.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct TopVersions {
    pub highest: semver::Version,
    pub newest: semver::Version,
}

impl TopVersions {
    /// Return both the newest (most recently updated) and the
    /// highest version (in semver order) for a collection of date/version pairs.
    pub fn from_date_version_pairs<T>(pairs: T) -> Self
    where
        T: Clone + IntoIterator<Item = (NaiveDateTime, semver::Version)>,
    {
        Self {
            newest: pairs
                .clone()
                .into_iter()
                .max()
                .unwrap_or((
                    NaiveDateTime::from_timestamp(0, 0),
                    default_semver_version(),
                ))
                .1,
            highest: pairs
                .into_iter()
                .map(|(_, v)| v)
                .max()
                .unwrap_or_else(default_semver_version),
        }
    }
}

/// A default semver value, "0.0.0", for use in TopVersions
fn default_semver_version() -> semver::Version {
    semver::Version {
        major: 0,
        minor: 0,
        patch: 0,
        pre: vec![],
        build: vec![],
    }
}

impl Version {
    pub fn encodable(
        self,
        crate_name: &str,
        published_by: Option<User>,
        audit_actions: Vec<(VersionOwnerAction, User)>,
    ) -> EncodableVersion {
        let Version {
            id,
            num,
            updated_at,
            created_at,
            downloads,
            features,
            yanked,
            license,
            crate_size,
            ..
        } = self;
        let num = num.to_string();
        EncodableVersion {
            dl_path: format!("/api/v1/crates/{}/{}/download", crate_name, num),
            readme_path: format!("/api/v1/crates/{}/{}/readme", crate_name, num),
            num: num.clone(),
            id,
            krate: crate_name.to_string(),
            updated_at,
            created_at,
            downloads,
            features,
            yanked,
            license,
            links: EncodableVersionLinks {
                dependencies: format!("/api/v1/crates/{}/{}/dependencies", crate_name, num),
                version_downloads: format!("/api/v1/crates/{}/{}/downloads", crate_name, num),
                authors: format!("/api/v1/crates/{}/{}/authors", crate_name, num),
            },
            crate_size,
            published_by: published_by.map(User::into),
            audit_actions: audit_actions
                .into_iter()
                .map(|(audit_action, user)| EncodableAuditAction {
                    action: audit_action.action.into(),
                    user: user.into(),
                    time: audit_action.time,
                })
                .collect(),
        }
    }

    /// Returns (dependency, crate dependency name)
    pub fn dependencies(&self, conn: &PgConnection) -> QueryResult<Vec<(Dependency, String)>> {
        Dependency::belonging_to(self)
            .inner_join(crates::table)
            .select((dependencies::all_columns, crates::name))
            .order((dependencies::optional, crates::name))
            .load(conn)
    }

    /// Return both the newest (most recently updated) and the
    /// highest version (in semver order) for a collection of date/version pairs.
    pub fn top<T>(pairs: T) -> TopVersions
    where
        T: Clone + IntoIterator<Item = (NaiveDateTime, semver::Version)>,
    {
        TopVersions::from_date_version_pairs(pairs)
    }

    pub fn record_readme_rendering(version_id_: i32, conn: &PgConnection) -> QueryResult<usize> {
        use crate::schema::readme_renderings::dsl::*;
        use diesel::dsl::now;

        diesel::insert_into(readme_renderings)
            .values(version_id.eq(version_id_))
            .on_conflict(version_id)
            .do_update()
            .set(rendered_at.eq(now))
            .execute(conn)
    }

    /// Gets the User who ran `cargo publish` for this version, if recorded.
    /// Not for use when you have a group of versions you need the publishers for.
    pub fn published_by(&self, conn: &PgConnection) -> Option<User> {
        match self.published_by {
            Some(pb) => users::table.find(pb).first(conn).ok(),
            None => None,
        }
    }
}

impl NewVersion {
    pub fn new(
        crate_id: i32,
        num: &semver::Version,
        features: &HashMap<String, Vec<String>>,
        license: Option<String>,
        license_file: Option<&str>,
        crate_size: i32,
        published_by: i32,
    ) -> AppResult<Self> {
        let features = serde_json::to_value(features)?;

        let mut new_version = NewVersion {
            crate_id,
            num: num.to_string(),
            features,
            license,
            crate_size: Some(crate_size),
            published_by,
        };

        new_version.validate_license(license_file)?;

        Ok(new_version)
    }

    pub fn save(
        &self,
        conn: &PgConnection,
        authors: &[String],
        published_by_email: &str,
    ) -> AppResult<Version> {
        use crate::schema::version_authors::{name, version_id};
        use crate::schema::versions::dsl::*;
        use diesel::dsl::exists;
        use diesel::{insert_into, select};

        conn.transaction(|| {
            let already_uploaded = versions
                .filter(crate_id.eq(self.crate_id))
                .filter(num.eq(&self.num));
            if select(exists(already_uploaded)).get_result(conn)? {
                return Err(cargo_err(&format_args!(
                    "crate version `{}` is already \
                     uploaded",
                    self.num
                )));
            }

            let version: Version = insert_into(versions).values(self).get_result(conn)?;

            insert_into(versions_published_by::table)
                .values((
                    versions_published_by::version_id.eq(version.id),
                    versions_published_by::email.eq(published_by_email),
                ))
                .execute(conn)?;

            let new_authors = authors
                .iter()
                .map(|s| (version_id.eq(version.id), name.eq(s)))
                .collect::<Vec<_>>();

            insert_into(version_authors::table)
                .values(&new_authors)
                .execute(conn)?;
            Ok(version)
        })
    }

    fn validate_license(&mut self, license_file: Option<&str>) -> AppResult<()> {
        if let Some(ref license) = self.license {
            for part in license.split('/') {
                license_exprs::validate_license_expr(part).map_err(|e| {
                    cargo_err(&format_args!(
                        "{}; see http://opensource.org/licenses \
                         for options, and http://spdx.org/licenses/ \
                         for their identifiers",
                        e
                    ))
                })?;
            }
        } else if license_file.is_some() {
            // If no license is given, but a license file is given, flag this
            // crate as having a nonstandard license. Note that we don't
            // actually do anything else with license_file currently.
            self.license = Some(String::from("non-standard"));
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::{TopVersions, Version};
    use chrono::NaiveDateTime;

    #[track_caller]
    fn date(str: &str) -> NaiveDateTime {
        str.parse().unwrap()
    }

    #[track_caller]
    fn version(str: &str) -> semver::Version {
        semver::Version::parse(str).unwrap()
    }

    #[test]
    fn top_versions_empty() {
        let versions = vec![];
        assert_eq!(
            Version::top(versions),
            TopVersions {
                highest: version("0.0.0"),
                newest: version("0.0.0"),
            }
        );
    }

    #[test]
    fn top_versions_single() {
        let versions = vec![(date("2020-12-03T12:34:56"), version("1.0.0"))];
        assert_eq!(
            Version::top(versions),
            TopVersions {
                highest: version("1.0.0"),
                newest: version("1.0.0"),
            }
        );
    }

    #[test]
    fn top_versions_multiple() {
        let versions = vec![
            (date("2018-12-03T12:34:56"), version("1.0.0")),
            (date("2019-12-03T12:34:56"), version("2.0.0-alpha.1")),
            (date("2020-12-03T12:34:56"), version("1.1.0")),
        ];
        assert_eq!(
            Version::top(versions),
            TopVersions {
                highest: version("2.0.0-alpha.1"),
                newest: version("1.1.0"),
            }
        );
    }
}
<|endoftext|>


<commit_before>macro_rules! newtype_clone (($newtype:ident) => (
        impl Clone for $newtype {
            fn clone(&self) -> $newtype {
                let &$newtype(v) = self;
                $newtype(v)
            }
        }

        ));

macro_rules! newtype_drop (($newtype:ident) => (
        impl Drop for $newtype {
            fn drop(&mut self) {
                use libc::size_t;
                use ffi;
                let &mut $newtype(ref mut v) = self;
                unsafe {
                    ffi::sodium_memzero(v.as_mut_ptr(), v.len() as size_t);
                }
            }
        }
        ));

macro_rules! newtype_impl (($newtype:ident, $len:expr) => (
    impl $newtype {
        /// `from_slice()` creates an object from a byte slice
        ///
        /// This function will fail and return None if the length of
        /// the byte-slice isn't equal to the length of the object
        pub fn from_slice(bs: &[u8]) -> Option<$newtype> {
            if bs.len() != $len {
                return None;
            }
            let mut n = $newtype([0; $len]);
            {
                let $newtype(ref mut b) = n;
                for (bi, &bsi) in b.iter_mut().zip(bs.iter()) {
                    *bi = bsi
                }
            }
            Some(n)
        }
    }
    impl PartialEq for $newtype {
        fn eq(&self, &$newtype(ref other): &$newtype) -> bool {
            use crypto::verify::safe_memcmp;
            let &$newtype(ref this) = self;
            safe_memcmp(this, other)
        }
    }
    impl Eq for $newtype {}
    impl rustc_serialize::Encodable for $newtype {
        fn encode<E: rustc_serialize::Encoder>(&self, encoder: &mut E)
                -> Result<(), E::Error> {
            encoder.emit_seq($len, |encoder| {
                for (i, e) in self[..].iter().enumerate() {
                    try!(encoder.emit_seq_elt(i, |encoder| e.encode(encoder)))
                }
                Ok(())
            })
        }
    }
    impl rustc_serialize::Decodable for $newtype {
        fn decode<D: rustc_serialize::Decoder>(decoder: &mut D)
                -> Result<$newtype, D::Error> {
            decoder.read_seq(|decoder, len| {
                if len != $len {
                    return Err(decoder.error(
                        &format!("Expecting array of length: {}, but found {}",
                                 $len, len)));
                }
                let mut arr = [0u8; $len];
                for (i, val) in arr.iter_mut().enumerate() {
                    *val = try!(decoder.read_seq_elt(i,
                        |decoder| rustc_serialize::Decodable::decode(decoder)));
                }
                Ok($newtype(arr))
            })
        }
    }
    /// Allows a user to access the byte contents of an object as a slice.
    ///
    /// WARNING: it might be tempting to do comparisons on objects
    /// by using `x[a..b] == y[a..b]`. This will open up for timing attacks
    /// when comparing for example authenticator tags. Because of this only
    /// use the comparison functions exposed by the sodiumoxide API.
    impl ::std::ops::Index<::std::ops::Range<usize>> for $newtype {
        type Output = [u8];
        fn index(&self, _index: ::std::ops::Range<usize>) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    /// Allows a user to access the byte contents of an object as a slice.
    ///
    /// WARNING: it might be tempting to do comparisons on objects
    /// by using `x[..b] == y[..b]`. This will open up for timing attacks
    /// when comparing for example authenticator tags. Because of this only
    /// use the comparison functions exposed by the sodiumoxide API.
    impl ::std::ops::Index<::std::ops::RangeTo<usize>> for $newtype {
        type Output = [u8];
        fn index(&self, _index: ::std::ops::RangeTo<usize>) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    /// Allows a user to access the byte contents of an object as a slice.
    ///
    /// WARNING: it might be tempting to do comparisons on objects
    /// by using `x[a..] == y[a..]`. This will open up for timing attacks
    /// when comparing for example authenticator tags. Because of this only
    /// use the comparison functions exposed by the sodiumoxide API.
    impl ::std::ops::Index<::std::ops::RangeFrom<usize>> for $newtype {
        type Output = [u8];
        fn index(&self, _index: ::std::ops::RangeFrom<usize>) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    /// Allows a user to access the byte contents of an object as a slice.
    ///
    /// WARNING: it might be tempting to do comparisons on objects
    /// by using `x[] == y[]`. This will open up for timing attacks
    /// when comparing for example authenticator tags. Because of this only
    /// use the comparison functions exposed by the sodiumoxide API.
    impl ::std::ops::Index<::std::ops::RangeFull> for $newtype {
        type Output = [u8];
        fn index(&self, _index: ::std::ops::RangeFull) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    ));
<commit_msg>Remove potential copy when deserializing newtypes<commit_after>macro_rules! newtype_clone (($newtype:ident) => (
        impl Clone for $newtype {
            fn clone(&self) -> $newtype {
                let &$newtype(v) = self;
                $newtype(v)
            }
        }

        ));

macro_rules! newtype_drop (($newtype:ident) => (
        impl Drop for $newtype {
            fn drop(&mut self) {
                use libc::size_t;
                use ffi;
                let &mut $newtype(ref mut v) = self;
                unsafe {
                    ffi::sodium_memzero(v.as_mut_ptr(), v.len() as size_t);
                }
            }
        }
        ));

macro_rules! newtype_impl (($newtype:ident, $len:expr) => (
    impl $newtype {
        /// `from_slice()` creates an object from a byte slice
        ///
        /// This function will fail and return None if the length of
        /// the byte-slice isn't equal to the length of the object
        pub fn from_slice(bs: &[u8]) -> Option<$newtype> {
            if bs.len() != $len {
                return None;
            }
            let mut n = $newtype([0; $len]);
            {
                let $newtype(ref mut b) = n;
                for (bi, &bsi) in b.iter_mut().zip(bs.iter()) {
                    *bi = bsi
                }
            }
            Some(n)
        }
    }
    impl PartialEq for $newtype {
        fn eq(&self, &$newtype(ref other): &$newtype) -> bool {
            use crypto::verify::safe_memcmp;
            let &$newtype(ref this) = self;
            safe_memcmp(this, other)
        }
    }
    impl Eq for $newtype {}
    impl rustc_serialize::Encodable for $newtype {
        fn encode<E: rustc_serialize::Encoder>(&self, encoder: &mut E)
                -> Result<(), E::Error> {
            encoder.emit_seq($len, |encoder| {
                for (i, e) in self[..].iter().enumerate() {
                    try!(encoder.emit_seq_elt(i, |encoder| e.encode(encoder)))
                }
                Ok(())
            })
        }
    }
    impl rustc_serialize::Decodable for $newtype {
        fn decode<D: rustc_serialize::Decoder>(decoder: &mut D)
                -> Result<$newtype, D::Error> {
            decoder.read_seq(|decoder, len| {
                if len != $len {
                    return Err(decoder.error(
                        &format!("Expecting array of length: {}, but found {}",
                                 $len, len)));
                }
                let mut res = $newtype([0; $len]);
                {
                    let $newtype(ref mut arr) = res;
                    for (i, val) in arr.iter_mut().enumerate() {
                        *val = try!(decoder.read_seq_elt(i,
                            |decoder| rustc_serialize::Decodable::decode(decoder)));
                    }
                }
                Ok(res)
            })
        }
    }
    /// Allows a user to access the byte contents of an object as a slice.
    ///
    /// WARNING: it might be tempting to do comparisons on objects
    /// by using `x[a..b] == y[a..b]`. This will open up for timing attacks
    /// when comparing for example authenticator tags. Because of this only
    /// use the comparison functions exposed by the sodiumoxide API.
    impl ::std::ops::Index<::std::ops::Range<usize>> for $newtype {
        type Output = [u8];
        fn index(&self, _index: ::std::ops::Range<usize>) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    /// Allows a user to access the byte contents of an object as a slice.
    ///
    /// WARNING: it might be tempting to do comparisons on objects
    /// by using `x[..b] == y[..b]`. This will open up for timing attacks
    /// when comparing for example authenticator tags. Because of this only
    /// use the comparison functions exposed by the sodiumoxide API.
    impl ::std::ops::Index<::std::ops::RangeTo<usize>> for $newtype {
        type Output = [u8];
        fn index(&self, _index: ::std::ops::RangeTo<usize>) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    /// Allows a user to access the byte contents of an object as a slice.
    ///
    /// WARNING: it might be tempting to do comparisons on objects
    /// by using `x[a..] == y[a..]`. This will open up for timing attacks
    /// when comparing for example authenticator tags. Because of this only
    /// use the comparison functions exposed by the sodiumoxide API.
    impl ::std::ops::Index<::std::ops::RangeFrom<usize>> for $newtype {
        type Output = [u8];
        fn index(&self, _index: ::std::ops::RangeFrom<usize>) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    /// Allows a user to access the byte contents of an object as a slice.
    ///
    /// WARNING: it might be tempting to do comparisons on objects
    /// by using `x[] == y[]`. This will open up for timing attacks
    /// when comparing for example authenticator tags. Because of this only
    /// use the comparison functions exposed by the sodiumoxide API.
    impl ::std::ops::Index<::std::ops::RangeFull> for $newtype {
        type Output = [u8];
        fn index(&self, _index: ::std::ops::RangeFull) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    ));
<|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 https://mozilla.org/MPL/2.0/. */

use crate::canvas_data::*;
use crate::ConstellationCanvasMsg;
use canvas_traits::canvas::*;
use crossbeam_channel::{select, unbounded, Sender};
use euclid::default::Size2D;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER;
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::thread;

pub enum AntialiasMode {
    Default,
    None,
}

pub struct CanvasPaintThread<'a> {
    canvases: HashMap<CanvasId, CanvasData<'a>>,
    next_canvas_id: CanvasId,
}

impl<'a> CanvasPaintThread<'a> {
    fn new() -> CanvasPaintThread<'a> {
        CanvasPaintThread {
            canvases: HashMap::new(),
            next_canvas_id: CanvasId(0),
        }
    }

    /// Creates a new `CanvasPaintThread` and returns an `IpcSender` to
    /// communicate with it.
    pub fn start() -> (Sender<ConstellationCanvasMsg>, IpcSender<CanvasMsg>) {
        let (ipc_sender, ipc_receiver) = ipc::channel::<CanvasMsg>().unwrap();
        let msg_receiver = ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(ipc_receiver);
        let (create_sender, create_receiver) = unbounded();
        thread::Builder::new()
            .name("CanvasThread".to_owned())
            .spawn(move || {
                let mut canvas_paint_thread = CanvasPaintThread::new();
                loop {
                    select! {
                        recv(msg_receiver) -> msg => {
                            match msg {
                                Ok(CanvasMsg::Canvas2d(message, canvas_id)) => {
                                    canvas_paint_thread.process_canvas_2d_message(message, canvas_id);
                                },
                                Ok(CanvasMsg::Close(canvas_id)) => {
                                    canvas_paint_thread.canvases.remove(&canvas_id);
                                },
                                Ok(CanvasMsg::Recreate(size, canvas_id)) => {
                                    canvas_paint_thread.canvas(canvas_id).recreate(size);
                                },
                                Ok(CanvasMsg::FromScript(message, canvas_id)) => match message {
                                    FromScriptMsg::SendPixels(chan) => {
                                        canvas_paint_thread.canvas(canvas_id).send_pixels(chan);
                                    },
                                },
                                Ok(CanvasMsg::FromLayout(message, canvas_id)) => match message {
                                    FromLayoutMsg::SendData(chan) => {
                                        canvas_paint_thread.canvas(canvas_id).send_data(chan);
                                    },
                                },
                                Err(e) => {
                                    warn!("Error on CanvasPaintThread receive ({})", e);
                                },
                            }
                        }
                        recv(create_receiver) -> msg => {
                            match msg {
                                Ok(ConstellationCanvasMsg::Create {
                                    id_sender: creator,
                                    size,
                                    webrender_sender: webrenderer_api_sender,
                                    antialias
                                }) => {
                                    let canvas_id = canvas_paint_thread.create_canvas(
                                        size,
                                        webrenderer_api_sender,
                                        antialias,
                                    );
                                    creator.send(canvas_id).unwrap();
                                },
                                Ok(ConstellationCanvasMsg::Exit) => break,
                                Err(e) => {
                                    warn!("Error on CanvasPaintThread receive ({})", e);
                                },
                            }
                        }
                    }
                }
            })
            .expect("Thread spawning failed");

        (create_sender, ipc_sender)
    }

    pub fn create_canvas(
        &mut self,
        size: Size2D<u64>,
        webrender_api_sender: webrender_api::RenderApiSender,
        antialias: bool,
    ) -> CanvasId {
        let antialias = if antialias {
            AntialiasMode::Default
        } else {
            AntialiasMode::None
        };

        let canvas_id = self.next_canvas_id.clone();
        self.next_canvas_id.0 += 1;

        let canvas_data = CanvasData::new(size, webrender_api_sender, antialias, canvas_id.clone());
        self.canvases.insert(canvas_id.clone(), canvas_data);

        canvas_id
    }

    fn process_canvas_2d_message(&mut self, message: Canvas2dMsg, canvas_id: CanvasId) {
        match message {
            Canvas2dMsg::FillText(text, x, y, max_width, style) => {
                self.canvas(canvas_id).set_fill_style(style);
                self.canvas(canvas_id).fill_text(text, x, y, max_width);
            },
            Canvas2dMsg::FillRect(rect, style) => {
                self.canvas(canvas_id).set_fill_style(style);
                self.canvas(canvas_id).fill_rect(&rect);
            },
            Canvas2dMsg::StrokeRect(rect, style) => {
                self.canvas(canvas_id).set_stroke_style(style);
                self.canvas(canvas_id).stroke_rect(&rect);
            },
            Canvas2dMsg::ClearRect(ref rect) => self.canvas(canvas_id).clear_rect(rect),
            Canvas2dMsg::BeginPath => self.canvas(canvas_id).begin_path(),
            Canvas2dMsg::ClosePath => self.canvas(canvas_id).close_path(),
            Canvas2dMsg::Fill(style) => {
                self.canvas(canvas_id).set_fill_style(style);
                self.canvas(canvas_id).fill();
            },
            Canvas2dMsg::Stroke(style) => {
                self.canvas(canvas_id).set_stroke_style(style);
                self.canvas(canvas_id).stroke();
            },
            Canvas2dMsg::Clip => self.canvas(canvas_id).clip(),
            Canvas2dMsg::IsPointInPath(x, y, fill_rule, chan) => self
                .canvas(canvas_id)
                .is_point_in_path(x, y, fill_rule, chan),
            Canvas2dMsg::DrawImage(
                imagedata,
                image_size,
                dest_rect,
                source_rect,
                smoothing_enabled,
            ) => {
                let data = imagedata.map_or_else(
                    || vec![0; image_size.width as usize * image_size.height as usize * 4],
                    |bytes| bytes.into_vec(),
                );
                self.canvas(canvas_id).draw_image(
                    data,
                    image_size,
                    dest_rect,
                    source_rect,
                    smoothing_enabled,
                )
            },
            Canvas2dMsg::DrawImageInOther(
                other_canvas_id,
                image_size,
                dest_rect,
                source_rect,
                smoothing,
            ) => {
                let image_data = self
                    .canvas(canvas_id)
                    .read_pixels(source_rect.to_u64(), image_size.to_u64());
                self.canvas(other_canvas_id).draw_image(
                    image_data.into(),
                    source_rect.size,
                    dest_rect,
                    source_rect,
                    smoothing,
                );
            },
            Canvas2dMsg::MoveTo(ref point) => self.canvas(canvas_id).move_to(point),
            Canvas2dMsg::LineTo(ref point) => self.canvas(canvas_id).line_to(point),
            Canvas2dMsg::Rect(ref rect) => self.canvas(canvas_id).rect(rect),
            Canvas2dMsg::QuadraticCurveTo(ref cp, ref pt) => {
                self.canvas(canvas_id).quadratic_curve_to(cp, pt)
            },
            Canvas2dMsg::BezierCurveTo(ref cp1, ref cp2, ref pt) => {
                self.canvas(canvas_id).bezier_curve_to(cp1, cp2, pt)
            },
            Canvas2dMsg::Arc(ref center, radius, start, end, ccw) => {
                self.canvas(canvas_id).arc(center, radius, start, end, ccw)
            },
            Canvas2dMsg::ArcTo(ref cp1, ref cp2, radius) => {
                self.canvas(canvas_id).arc_to(cp1, cp2, radius)
            },
            Canvas2dMsg::Ellipse(ref center, radius_x, radius_y, rotation, start, end, ccw) => self
                .canvas(canvas_id)
                .ellipse(center, radius_x, radius_y, rotation, start, end, ccw),
            Canvas2dMsg::RestoreContext => self.canvas(canvas_id).restore_context_state(),
            Canvas2dMsg::SaveContext => self.canvas(canvas_id).save_context_state(),
            Canvas2dMsg::SetLineWidth(width) => self.canvas(canvas_id).set_line_width(width),
            Canvas2dMsg::SetLineCap(cap) => self.canvas(canvas_id).set_line_cap(cap),
            Canvas2dMsg::SetLineJoin(join) => self.canvas(canvas_id).set_line_join(join),
            Canvas2dMsg::SetMiterLimit(limit) => self.canvas(canvas_id).set_miter_limit(limit),
            Canvas2dMsg::SetTransform(ref matrix) => self.canvas(canvas_id).set_transform(matrix),
            Canvas2dMsg::SetGlobalAlpha(alpha) => self.canvas(canvas_id).set_global_alpha(alpha),
            Canvas2dMsg::SetGlobalComposition(op) => {
                self.canvas(canvas_id).set_global_composition(op)
            },
            Canvas2dMsg::GetImageData(dest_rect, canvas_size, sender) => {
                let pixels = self.canvas(canvas_id).read_pixels(dest_rect, canvas_size);
                sender.send(&pixels).unwrap();
            },
            Canvas2dMsg::PutImageData(rect, receiver) => {
                self.canvas(canvas_id)
                    .put_image_data(receiver.recv().unwrap(), rect);
            },
            Canvas2dMsg::SetShadowOffsetX(value) => {
                self.canvas(canvas_id).set_shadow_offset_x(value)
            },
            Canvas2dMsg::SetShadowOffsetY(value) => {
                self.canvas(canvas_id).set_shadow_offset_y(value)
            },
            Canvas2dMsg::SetShadowBlur(value) => self.canvas(canvas_id).set_shadow_blur(value),
            Canvas2dMsg::SetShadowColor(color) => self.canvas(canvas_id).set_shadow_color(color),
        }
    }

    fn canvas(&mut self, canvas_id: CanvasId) -> &mut CanvasData<'a> {
        self.canvases.get_mut(&canvas_id).expect("Bogus canvas id")
    }
}
<commit_msg>Auto merge of #25665 - servo:jdm-patch-35, r=jdm<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 https://mozilla.org/MPL/2.0/. */

use crate::canvas_data::*;
use crate::ConstellationCanvasMsg;
use canvas_traits::canvas::*;
use crossbeam_channel::{select, unbounded, Sender};
use euclid::default::Size2D;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER;
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::thread;

pub enum AntialiasMode {
    Default,
    None,
}

pub struct CanvasPaintThread<'a> {
    canvases: HashMap<CanvasId, CanvasData<'a>>,
    next_canvas_id: CanvasId,
}

impl<'a> CanvasPaintThread<'a> {
    fn new() -> CanvasPaintThread<'a> {
        CanvasPaintThread {
            canvases: HashMap::new(),
            next_canvas_id: CanvasId(0),
        }
    }

    /// Creates a new `CanvasPaintThread` and returns an `IpcSender` to
    /// communicate with it.
    pub fn start() -> (Sender<ConstellationCanvasMsg>, IpcSender<CanvasMsg>) {
        let (ipc_sender, ipc_receiver) = ipc::channel::<CanvasMsg>().unwrap();
        let msg_receiver = ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(ipc_receiver);
        let (create_sender, create_receiver) = unbounded();
        thread::Builder::new()
            .name("CanvasThread".to_owned())
            .spawn(move || {
                let mut canvas_paint_thread = CanvasPaintThread::new();
                loop {
                    select! {
                        recv(msg_receiver) -> msg => {
                            match msg {
                                Ok(CanvasMsg::Canvas2d(message, canvas_id)) => {
                                    canvas_paint_thread.process_canvas_2d_message(message, canvas_id);
                                },
                                Ok(CanvasMsg::Close(canvas_id)) => {
                                    canvas_paint_thread.canvases.remove(&canvas_id);
                                },
                                Ok(CanvasMsg::Recreate(size, canvas_id)) => {
                                    canvas_paint_thread.canvas(canvas_id).recreate(size);
                                },
                                Ok(CanvasMsg::FromScript(message, canvas_id)) => match message {
                                    FromScriptMsg::SendPixels(chan) => {
                                        canvas_paint_thread.canvas(canvas_id).send_pixels(chan);
                                    },
                                },
                                Ok(CanvasMsg::FromLayout(message, canvas_id)) => match message {
                                    FromLayoutMsg::SendData(chan) => {
                                        canvas_paint_thread.canvas(canvas_id).send_data(chan);
                                    },
                                },
                                Err(e) => {
                                    warn!("Error on CanvasPaintThread receive ({})", e);
                                },
                            }
                        }
                        recv(create_receiver) -> msg => {
                            match msg {
                                Ok(ConstellationCanvasMsg::Create {
                                    id_sender: creator,
                                    size,
                                    webrender_sender: webrenderer_api_sender,
                                    antialias
                                }) => {
                                    let canvas_id = canvas_paint_thread.create_canvas(
                                        size,
                                        webrenderer_api_sender,
                                        antialias,
                                    );
                                    creator.send(canvas_id).unwrap();
                                },
                                Ok(ConstellationCanvasMsg::Exit) => break,
                                Err(e) => {
                                    warn!("Error on CanvasPaintThread receive ({})", e);
                                    break;
                                },
                            }
                        }
                    }
                }
            })
            .expect("Thread spawning failed");

        (create_sender, ipc_sender)
    }

    pub fn create_canvas(
        &mut self,
        size: Size2D<u64>,
        webrender_api_sender: webrender_api::RenderApiSender,
        antialias: bool,
    ) -> CanvasId {
        let antialias = if antialias {
            AntialiasMode::Default
        } else {
            AntialiasMode::None
        };

        let canvas_id = self.next_canvas_id.clone();
        self.next_canvas_id.0 += 1;

        let canvas_data = CanvasData::new(size, webrender_api_sender, antialias, canvas_id.clone());
        self.canvases.insert(canvas_id.clone(), canvas_data);

        canvas_id
    }

    fn process_canvas_2d_message(&mut self, message: Canvas2dMsg, canvas_id: CanvasId) {
        match message {
            Canvas2dMsg::FillText(text, x, y, max_width, style) => {
                self.canvas(canvas_id).set_fill_style(style);
                self.canvas(canvas_id).fill_text(text, x, y, max_width);
            },
            Canvas2dMsg::FillRect(rect, style) => {
                self.canvas(canvas_id).set_fill_style(style);
                self.canvas(canvas_id).fill_rect(&rect);
            },
            Canvas2dMsg::StrokeRect(rect, style) => {
                self.canvas(canvas_id).set_stroke_style(style);
                self.canvas(canvas_id).stroke_rect(&rect);
            },
            Canvas2dMsg::ClearRect(ref rect) => self.canvas(canvas_id).clear_rect(rect),
            Canvas2dMsg::BeginPath => self.canvas(canvas_id).begin_path(),
            Canvas2dMsg::ClosePath => self.canvas(canvas_id).close_path(),
            Canvas2dMsg::Fill(style) => {
                self.canvas(canvas_id).set_fill_style(style);
                self.canvas(canvas_id).fill();
            },
            Canvas2dMsg::Stroke(style) => {
                self.canvas(canvas_id).set_stroke_style(style);
                self.canvas(canvas_id).stroke();
            },
            Canvas2dMsg::Clip => self.canvas(canvas_id).clip(),
            Canvas2dMsg::IsPointInPath(x, y, fill_rule, chan) => self
                .canvas(canvas_id)
                .is_point_in_path(x, y, fill_rule, chan),
            Canvas2dMsg::DrawImage(
                imagedata,
                image_size,
                dest_rect,
                source_rect,
                smoothing_enabled,
            ) => {
                let data = imagedata.map_or_else(
                    || vec![0; image_size.width as usize * image_size.height as usize * 4],
                    |bytes| bytes.into_vec(),
                );
                self.canvas(canvas_id).draw_image(
                    data,
                    image_size,
                    dest_rect,
                    source_rect,
                    smoothing_enabled,
                )
            },
            Canvas2dMsg::DrawImageInOther(
                other_canvas_id,
                image_size,
                dest_rect,
                source_rect,
                smoothing,
            ) => {
                let image_data = self
                    .canvas(canvas_id)
                    .read_pixels(source_rect.to_u64(), image_size.to_u64());
                self.canvas(other_canvas_id).draw_image(
                    image_data.into(),
                    source_rect.size,
                    dest_rect,
                    source_rect,
                    smoothing,
                );
            },
            Canvas2dMsg::MoveTo(ref point) => self.canvas(canvas_id).move_to(point),
            Canvas2dMsg::LineTo(ref point) => self.canvas(canvas_id).line_to(point),
            Canvas2dMsg::Rect(ref rect) => self.canvas(canvas_id).rect(rect),
            Canvas2dMsg::QuadraticCurveTo(ref cp, ref pt) => {
                self.canvas(canvas_id).quadratic_curve_to(cp, pt)
            },
            Canvas2dMsg::BezierCurveTo(ref cp1, ref cp2, ref pt) => {
                self.canvas(canvas_id).bezier_curve_to(cp1, cp2, pt)
            },
            Canvas2dMsg::Arc(ref center, radius, start, end, ccw) => {
                self.canvas(canvas_id).arc(center, radius, start, end, ccw)
            },
            Canvas2dMsg::ArcTo(ref cp1, ref cp2, radius) => {
                self.canvas(canvas_id).arc_to(cp1, cp2, radius)
            },
            Canvas2dMsg::Ellipse(ref center, radius_x, radius_y, rotation, start, end, ccw) => self
                .canvas(canvas_id)
                .ellipse(center, radius_x, radius_y, rotation, start, end, ccw),
            Canvas2dMsg::RestoreContext => self.canvas(canvas_id).restore_context_state(),
            Canvas2dMsg::SaveContext => self.canvas(canvas_id).save_context_state(),
            Canvas2dMsg::SetLineWidth(width) => self.canvas(canvas_id).set_line_width(width),
            Canvas2dMsg::SetLineCap(cap) => self.canvas(canvas_id).set_line_cap(cap),
            Canvas2dMsg::SetLineJoin(join) => self.canvas(canvas_id).set_line_join(join),
            Canvas2dMsg::SetMiterLimit(limit) => self.canvas(canvas_id).set_miter_limit(limit),
            Canvas2dMsg::SetTransform(ref matrix) => self.canvas(canvas_id).set_transform(matrix),
            Canvas2dMsg::SetGlobalAlpha(alpha) => self.canvas(canvas_id).set_global_alpha(alpha),
            Canvas2dMsg::SetGlobalComposition(op) => {
                self.canvas(canvas_id).set_global_composition(op)
            },
            Canvas2dMsg::GetImageData(dest_rect, canvas_size, sender) => {
                let pixels = self.canvas(canvas_id).read_pixels(dest_rect, canvas_size);
                sender.send(&pixels).unwrap();
            },
            Canvas2dMsg::PutImageData(rect, receiver) => {
                self.canvas(canvas_id)
                    .put_image_data(receiver.recv().unwrap(), rect);
            },
            Canvas2dMsg::SetShadowOffsetX(value) => {
                self.canvas(canvas_id).set_shadow_offset_x(value)
            },
            Canvas2dMsg::SetShadowOffsetY(value) => {
                self.canvas(canvas_id).set_shadow_offset_y(value)
            },
            Canvas2dMsg::SetShadowBlur(value) => self.canvas(canvas_id).set_shadow_blur(value),
            Canvas2dMsg::SetShadowColor(color) => self.canvas(canvas_id).set_shadow_color(color),
        }
    }

    fn canvas(&mut self, canvas_id: CanvasId) -> &mut CanvasData<'a> {
        self.canvases.get_mut(&canvas_id).expect("Bogus canvas id")
    }
}
<|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/. */

//! The bulk of the HTML parser integration is in `script::parse::html`.
//! This module is mostly about its interaction with DOM memory management.

use document_loader::LoadType;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::ServoHTMLParserBinding;
use dom::bindings::codegen::InheritTypes::NodeCast;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, Root};
use dom::bindings::refcounted::Trusted;
use dom::bindings::trace::JSTraceable;
use dom::bindings::utils::{Reflector, reflect_dom_object};
use dom::document::Document;
use dom::node::{Node, window_from_node};
use dom::text::Text;
use dom::window::Window;
use encoding::all::UTF_8;
use encoding::types::{DecoderTrap, Encoding};
use html5ever::tokenizer;
use html5ever::tree_builder;
use html5ever::tree_builder::{NodeOrText, TreeBuilder, TreeBuilderOpts};
use hyper::header::ContentType;
use hyper::mime::{Mime, SubLevel, TopLevel};
use js::jsapi::JSTracer;
use msg::constellation_msg::{PipelineId, SubpageId};
use net_traits::{AsyncResponseListener, Metadata};
use network_listener::PreInvoke;
use parse::Parser;
use script_task::{ScriptChan, ScriptTask};
use std::cell::Cell;
use std::default::Default;
use url::Url;

#[must_root]
#[derive(JSTraceable, HeapSizeOf)]
pub struct Sink {
    pub base_url: Option<Url>,
    pub document: JS<Document>,
}

impl Sink {
    #[allow(unrooted_must_root)] // method is only run at parse time
    pub fn get_or_create(&self, child: NodeOrText<JS<Node>>) -> Root<Node> {
        match child {
            NodeOrText::AppendNode(n) => n.root(),
            NodeOrText::AppendText(t) => {
                let doc = self.document.root();
                let text = Text::new(t.into(), &doc);
                NodeCast::from_root(text)
            }
        }
    }
}

/// FragmentContext is used only to pass this group of related values
/// into functions.
#[derive(Copy, Clone)]
pub struct FragmentContext<'a> {
    pub context_elem: &'a Node,
    pub form_elem: Option<&'a Node>,
}

pub type Tokenizer = tokenizer::Tokenizer<TreeBuilder<JS<Node>, Sink>>;

/// The context required for asynchronously fetching a document and parsing it progressively.
pub struct ParserContext {
    /// The parser that initiated the request.
    parser: Option<Trusted<ServoHTMLParser>>,
    /// Is this document a synthesized document for a single image?
    is_image_document: bool,
    /// The pipeline associated with this document.
    id: PipelineId,
    /// The subpage associated with this document.
    subpage: Option<SubpageId>,
    /// The target event loop for the response notifications.
    script_chan: Box