<commit_before>use ra_syntax::{
    ast::{self, NameOwner, VisibilityOwner},
    AstNode,
    SyntaxKind::{
        ATTR, COMMENT, CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY,
        WHITESPACE,
    },
    SyntaxNode, TextSize, T,
};

use crate::{Assist, AssistCtx, AssistId};
use test_utils::tested_by;

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

fn add_vis(ctx: AssistCtx) -> Option<Assist> {
    let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() {
        T![const] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait] => true,
        _ => false,
    });

    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 {
        let field_name: ast::Name = ctx.find_node_at_offset()?;
        let field = field_name.syntax().ancestors().find_map(ast::RecordFieldDef::cast)?;
        if field.name()? != field_name {
            tested_by!(change_visibility_field_false_positive);
            return None;
        }
        if field.visibility().is_some() {
            return None;
        }
        (vis_offset(field.syntax()), field_name.syntax().text_range())
    };

    ctx.add_assist(AssistId("change_visibility"), "Change visibility to pub(crate)", |edit| {
        edit.target(target);
        edit.insert(offset, "pub(crate) ");
        edit.set_cursor(offset);
    })
}

fn vis_offset(node: &SyntaxNode) -> TextSize {
    node.children_with_tokens()
        .skip_while(|it| match it.kind() {
            WHITESPACE | COMMENT | ATTR => true,
            _ => false,
        })
        .next()
        .map(|it| it.text_range().start())
        .unwrap_or_else(|| node.text_range().start())
}

fn change_vis(ctx: AssistCtx, vis: ast::Visibility) -> Option<Assist> {
    if vis.syntax().text() == "pub" {
        return ctx.add_assist(
            AssistId("change_visibility"),
            "Change Visibility to pub(crate)",
            |edit| {
                edit.target(vis.syntax().text_range());
                edit.replace(vis.syntax().text_range(), "pub(crate)");
                edit.set_cursor(vis.syntax().text_range().start())
            },
        );
    }
    if vis.syntax().text() == "pub(crate)" {
        return ctx.add_assist(AssistId("change_visibility"), "Change visibility to pub", |edit| {
            edit.target(vis.syntax().text_range());
            edit.replace(vis.syntax().text_range(), "pub");
            edit.set_cursor(vis.syntax().text_range().start());
        });
    }
    None
}

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

    use crate::helpers::{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 }",
        )
    }

    #[test]
    fn change_visibility_field_false_positive() {
        covers!(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 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>Make `change_visibility` assist work for tuple struct field visibility<commit_after>use ra_syntax::{
    ast::{self, NameOwner, VisibilityOwner},
    AstNode,
    SyntaxKind::{
        ATTR, COMMENT, CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY,
        WHITESPACE,
    },
    SyntaxNode, TextSize, T,
};

use crate::{Assist, AssistCtx, AssistId};
use test_utils::tested_by;

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

fn add_vis(ctx: AssistCtx) -> Option<Assist> {
    let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() {
        T![const] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait] => true,
        _ => false,
    });

    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 {
            tested_by!(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;
    };

    ctx.add_assist(AssistId("change_visibility"), "Change visibility to pub(crate)", |edit| {
        edit.target(target);
        edit.insert(offset, "pub(crate) ");
        edit.set_cursor(offset);
    })
}

fn vis_offset(node: &SyntaxNode) -> TextSize {
    node.children_with_tokens()
        .skip_while(|it| match it.kind() {
            WHITESPACE | COMMENT | ATTR => true,
            _ => false,
        })
        .next()
        .map(|it| it.text_range().start())
        .unwrap_or_else(|| node.text_range().start())
}

fn change_vis(ctx: AssistCtx, vis: ast::Visibility) -> Option<Assist> {
    if vis.syntax().text() == "pub" {
        return ctx.add_assist(
            AssistId("change_visibility"),
            "Change Visibility to pub(crate)",
            |edit| {
                edit.target(vis.syntax().text_range());
                edit.replace(vis.syntax().text_range(), "pub(crate)");
                edit.set_cursor(vis.syntax().text_range().start())
            },
        );
    }
    if vis.syntax().text() == "pub(crate)" {
        return ctx.add_assist(AssistId("change_visibility"), "Change visibility to pub", |edit| {
            edit.target(vis.syntax().text_range());
            edit.replace(vis.syntax().text_range(), "pub");
            edit.set_cursor(vis.syntax().text_range().start());
        });
    }
    None
}

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

    use crate::helpers::{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() {
        covers!(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 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>//! FIXME: write short doc here

use crate::{
    completion::{
        CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
    },
    display::FunctionSignature,
};

use hir::{self, Docs, HasSource};
use ra_syntax::{
    ast::{self, edit},
    AstNode, SyntaxKind, TextRange,
};

use ra_assists::utils::get_missing_impl_items;

pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
    // it is possible to have a parent `fn` and `impl` block. Ignore completion
    // attempts from within a `fn` block.
    if ctx.function_syntax.is_some() {
        return;
    }

    if let Some(ref impl_block) = ctx.impl_block {
        for item in get_missing_impl_items(ctx.db, &ctx.analyzer, impl_block) {
            match item {
                hir::AssocItem::Function(f) => add_function_impl(acc, ctx, &f),
                hir::AssocItem::TypeAlias(t) => add_type_alias_impl(acc, ctx, &t),
                hir::AssocItem::Const(c) => add_const_impl(acc, ctx, &c),
            }
        }
    }
}

fn add_function_impl(acc: &mut Completions, ctx: &CompletionContext, func: &hir::Function) {
    let display = FunctionSignature::from_hir(ctx.db, func.clone());

    let func_name = func.name(ctx.db);

    let label = if func.params(ctx.db).len() > 0 {
        format!("fn {}(..)", func_name.to_string())
    } else {
        format!("fn {}()", func_name.to_string())
    };

    let builder = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label.clone())
        .lookup_by(label)
        .set_documentation(func.docs(ctx.db));

    let completion_kind = if func.has_self_param(ctx.db) {
        CompletionItemKind::Method
    } else {
        CompletionItemKind::Function
    };

    let snippet = format!("{} {{}}", display);

    builder.insert_text(snippet).kind(completion_kind).add_to(acc);
}

fn add_type_alias_impl(
    acc: &mut Completions,
    ctx: &CompletionContext,
    type_alias: &hir::TypeAlias,
) {
    let snippet = format!("type {} = ", type_alias.name(ctx.db).to_string());

    CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
        .insert_text(snippet)
        .kind(CompletionItemKind::TypeAlias)
        .set_documentation(type_alias.docs(ctx.db))
        .add_to(acc);
}

fn add_const_impl(acc: &mut Completions, ctx: &CompletionContext, const_: &hir::Const) {
    let snippet = make_const_compl_syntax(&const_.source(ctx.db).value);

    CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
        .insert_text(snippet)
        .kind(CompletionItemKind::Const)
        .set_documentation(const_.docs(ctx.db))
        .add_to(acc);
}

fn make_const_compl_syntax(const_: &ast::ConstDef) -> String {
    let const_ = edit::strip_attrs_and_docs(const_);

    let const_start = const_.syntax().text_range().start();
    let const_end = const_.syntax().text_range().end();

    let start =
        const_.syntax().first_child_or_token().map_or(const_start, |f| f.text_range().start());

    let end = const_
        .syntax()
        .children_with_tokens()
        .find(|s| s.kind() == SyntaxKind::SEMI || s.kind() == SyntaxKind::EQ)
        .map_or(const_end, |f| f.text_range().start());

    let len = end - start;
    let range = TextRange::from_to(0.into(), len);

    let syntax = const_.syntax().text().slice(range).to_string();

    format!("{} = ", syntax.trim_end())
}

#[cfg(test)]
mod tests {
    use crate::completion::{do_completion, CompletionItem, CompletionKind};
    use insta::assert_debug_snapshot;

    fn complete(code: &str) -> Vec<CompletionItem> {
        do_completion(code, CompletionKind::Magic)
    }

    #[test]
    fn single_function() {
        let completions = complete(
            r"
            trait Test {
                fn foo();
            }

            struct T1;

            impl Test for T1 {
                <|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [138; 138),
                delete: [138; 138),
                insert: "fn foo() {}",
                kind: Function,
            },
        ]
        "###);
    }

    #[test]
    fn hide_implemented_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo();
                fn bar();
            }

            struct T1;

            impl Test for T1 {
                fn foo() {}

                <|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn bar()",
                source_range: [193; 193),
                delete: [193; 193),
                insert: "fn bar() {}",
                kind: Function,
            },
        ]
        "###);
    }

    #[test]
    fn generic_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo<T>();
            }

            struct T1;

            impl Test for T1 {
                <|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [141; 141),
                delete: [141; 141),
                insert: "fn foo<T>() {}",
                kind: Function,
            },
        ]
        "###);
    }

    #[test]
    fn generic_constrait_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo<T>() where T: Into<String>;
            }

            struct T1;

            impl Test for T1 {
                <|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [163; 163),
                delete: [163; 163),
                insert: "fn foo<T>()\nwhere T: Into<String> {}",
                kind: Function,
            },
        ]
        "###);
    }

    #[test]
    fn associated_type() {
        let completions = complete(
            r"
            trait Test {
                type SomeType;
            }

            impl Test for () {
                <|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "type SomeType = ",
                source_range: [119; 119),
                delete: [119; 119),
                insert: "type SomeType = ",
                kind: TypeAlias,
            },
        ]
        "###);
    }

    #[test]
    fn associated_const() {
        let completions = complete(
            r"
            trait Test {
                const SOME_CONST: u16;
            }

            impl Test for () {
                <|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "const SOME_CONST: u16 = ",
                source_range: [127; 127),
                delete: [127; 127),
                insert: "const SOME_CONST: u16 = ",
                kind: Const,
            },
        ]
        "###);
    }

    #[test]
    fn associated_const_with_default() {
        let completions = complete(
            r"
            trait Test {
                const SOME_CONST: u16 = 42;
            }

            impl Test for () {
                <|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "const SOME_CONST: u16 = ",
                source_range: [132; 132),
                delete: [132; 132),
                insert: "const SOME_CONST: u16 = ",
                kind: Const,
            },
        ]
        "###);
    }
}
<commit_msg>Started to refactor the trigger of the trait_impl completion.<commit_after>//! FIXME: write short doc here

use crate::{
    completion::{
        CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
    },
    display::FunctionSignature,
};

use hir::{self, Docs, HasSource};
use ra_syntax::{
    ast::{self, edit},
    AstNode, SyntaxKind, TextRange,
};

use ra_assists::utils::get_missing_impl_items;

pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
    let trigger = ctx.token
        .ancestors()
        .find(|p| match p.kind() {
            SyntaxKind::FN_DEF |
            SyntaxKind::TYPE_ALIAS_DEF |
            SyntaxKind::CONST_DEF |
            SyntaxKind::ITEM_LIST => true,
            _ => false
        });

    let impl_block = trigger
        .as_ref()
        .and_then(|node| node.parent())
        .and_then(|node| node.parent())
        .and_then(|node| ast::ImplBlock::cast(node));

    if let (Some(trigger), Some(impl_block)) = (trigger, impl_block) {
        match trigger.kind() {
            SyntaxKind::FN_DEF => {
                for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block)
                    .iter()
                    .filter_map(|item| {
                        match item {
                            hir::AssocItem::Function(fn_item) => Some(fn_item),
                            _ => None
                        }
                    })
                {
                    add_function_impl(acc, ctx, &missing_fn);
                }
            },

            SyntaxKind::TYPE_ALIAS_DEF => {
                for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block)
                    .iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::TypeAlias(type_item) => Some(type_item),
                        _ => None
                    })
                {
                    add_type_alias_impl(acc, ctx, &missing_fn);
                }
            },

            SyntaxKind::CONST_DEF => {
                for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block)
                    .iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::Const(const_item) => Some(const_item),
                        _ => None
                    })
                {
                    add_const_impl(acc, ctx, &missing_fn);
                }
            },

            _ => {}
        }
    }
}

fn add_function_impl(acc: &mut Completions, ctx: &CompletionContext, func: &hir::Function) {
    let display = FunctionSignature::from_hir(ctx.db, func.clone());

    let func_name = func.name(ctx.db);

    let label = if func.params(ctx.db).len() > 0 {
        format!("fn {}(..)", func_name.to_string())
    } else {
        format!("fn {}()", func_name.to_string())
    };

    let builder = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label.clone())
        .lookup_by(label)
        .set_documentation(func.docs(ctx.db));

    let completion_kind = if func.has_self_param(ctx.db) {
        CompletionItemKind::Method
    } else {
        CompletionItemKind::Function
    };

    let snippet = format!("{} {{}}", display);

    builder.insert_text(snippet).kind(completion_kind).add_to(acc);
}

fn add_type_alias_impl(
    acc: &mut Completions,
    ctx: &CompletionContext,
    type_alias: &hir::TypeAlias,
) {
    let snippet = format!("type {} = ", type_alias.name(ctx.db).to_string());

    CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
        .insert_text(snippet)
        .kind(CompletionItemKind::TypeAlias)
        .set_documentation(type_alias.docs(ctx.db))
        .add_to(acc);
}

fn add_const_impl(acc: &mut Completions, ctx: &CompletionContext, const_: &hir::Const) {
    let snippet = make_const_compl_syntax(&const_.source(ctx.db).value);

    CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
        .insert_text(snippet)
        .kind(CompletionItemKind::Const)
        .set_documentation(const_.docs(ctx.db))
        .add_to(acc);
}

fn make_const_compl_syntax(const_: &ast::ConstDef) -> String {
    let const_ = edit::strip_attrs_and_docs(const_);

    let const_start = const_.syntax().text_range().start();
    let const_end = const_.syntax().text_range().end();

    let start =
        const_.syntax().first_child_or_token().map_or(const_start, |f| f.text_range().start());

    let end = const_
        .syntax()
        .children_with_tokens()
        .find(|s| s.kind() == SyntaxKind::SEMI || s.kind() == SyntaxKind::EQ)
        .map_or(const_end, |f| f.text_range().start());

    let len = end - start;
    let range = TextRange::from_to(0.into(), len);

    let syntax = const_.syntax().text().slice(range).to_string();

    format!("{} = ", syntax.trim_end())
}

#[cfg(test)]
mod tests {
    use crate::completion::{do_completion, CompletionItem, CompletionKind};
    use insta::assert_debug_snapshot;

    fn complete(code: &str) -> Vec<CompletionItem> {
        do_completion(code, CompletionKind::Magic)
    }

    #[test]
    fn single_function() {
        let completions = complete(
            r"
            trait Test {
                fn foo();
            }

            struct T1;

            impl Test for T1 {
                fn<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [140; 140),
                delete: [140; 140),
                insert: "fn foo() {}",
                kind: Function,
            },
        ]
        "###);
    }

    #[test]
    fn hide_implemented_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo();
                fn bar();
            }

            struct T1;

            impl Test for T1 {
                fn foo() {}

                fn<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn bar()",
                source_range: [195; 195),
                delete: [195; 195),
                insert: "fn bar() {}",
                kind: Function,
            },
        ]
        "###);
    }

    #[test]
    fn generic_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo<T>();
            }

            struct T1;

            impl Test for T1 {
                fn<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [143; 143),
                delete: [143; 143),
                insert: "fn foo<T>() {}",
                kind: Function,
            },
        ]
        "###);
    }

    #[test]
    fn generic_constrait_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo<T>() where T: Into<String>;
            }

            struct T1;

            impl Test for T1 {
                fn<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [165; 165),
                delete: [165; 165),
                insert: "fn foo<T>()\nwhere T: Into<String> {}",
                kind: Function,
            },
        ]
        "###);
    }

    #[test]
    fn associated_type() {
        let completions = complete(
            r"
            trait Test {
                type SomeType;
            }

            impl Test for () {
                type<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "type SomeType = ",
                source_range: [123; 123),
                delete: [123; 123),
                insert: "type SomeType = ",
                kind: TypeAlias,
            },
        ]
        "###);
    }

    #[test]
    fn associated_const() {
        let completions = complete(
            r"
            trait Test {
                const SOME_CONST: u16;
            }

            impl Test for () {
                const<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "const SOME_CONST: u16 = ",
                source_range: [132; 132),
                delete: [132; 132),
                insert: "const SOME_CONST: u16 = ",
                kind: Const,
            },
        ]
        "###);
    }

    #[test]
    fn associated_const_with_default() {
        let completions = complete(
            r"
            trait Test {
                const SOME_CONST: u16 = 42;
            }

            impl Test for () {
                const<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "const SOME_CONST: u16 = ",
                source_range: [137; 137),
                delete: [137; 137),
                insert: "const SOME_CONST: u16 = ",
                kind: Const,
            },
        ]
        "###);
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::io::BufReader;
use std::fs::File;

use types::*;
use serde_json;

// configuration for extension display names and for the "Target of" section
#[derive(Deserialize, Clone, Debug)]
pub struct ExtensionDisplayNames {
    pub rel_name: String, // name of extension relation
    pub display_name: String, // text to display
    pub if_descendent_of: Option<String>, // None if applies to any extension
    pub reciprocal_display: Option<String>, // None if reciprocal shouldn't be displayed
}

// "interesting parents" are those stored in the JSON in the TermShort structs
#[derive(Deserialize, Clone, Debug, PartialEq, Eq, Hash)]
pub struct InterestingParent {
    pub termid: String,
    pub rel_name: String,
}

// the order of relations within an extension:
#[derive(Deserialize, Clone, Debug)]
pub struct RelationOrder {
    // put the relations in this order in the displayed extensions:
    pub relation_order: Vec<String>,
    // except for these reactions which should always come last:
    pub always_last: Vec<String>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct TermFilterCategory {
    pub display_name: String,
    // this category matches these terms and their descendants
    pub ancestors: Vec<String>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct FilterConfig {
    pub filter_name: String,
    pub display_name: String,
    #[serde(skip_serializing_if="Vec::is_empty", default)]
    pub term_categories: Vec<TermFilterCategory>
}

#[derive(Deserialize, Clone, Debug)]
pub struct SplitByParentsConfig {
    pub termids: Vec<String>,
    pub display_name: String,
}

#[derive(Deserialize, Clone, Debug)]
pub struct CvConfig {
    pub feature_type: String,
    // filtering configured per CV
    #[serde(skip_serializing_if="Vec::is_empty", default)]
    pub filters: Vec<FilterConfig>,
    // config for splitting cv annotation tables into sub-sections
    // based on ancestry
    #[serde(skip_serializing_if="Vec::is_empty", default)]
    pub split_by_parents: Vec<SplitByParentsConfig>,
    // relations to not show in the summary
    #[serde(skip_serializing_if="Vec::is_empty", default)]
    pub summary_relations_to_hide: Vec<String>,
    // relations where the range is a gene ID to display like:
    //   has substrate pom1, cdc1 involved in negative regulation of ...
    // rather than as two lines
    #[serde(skip_serializing_if="Vec::is_empty", default)]
    pub summary_relation_ranges_to_collect: Vec<String>,
}

pub type ShortEvidenceCode = String;
pub type LongEvidenceCode = String;

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct ConfigOrganism {
    pub taxonid: OrganismTaxonId,
    pub genus: String,
    pub species: String,
}

impl ConfigOrganism {
    pub fn full_name(&self) -> String {
        self.genus.clone() + "_" + self.species.as_str()
    }
}

#[derive(Deserialize, Clone, Debug)]
pub struct ViabilityTerms {
    pub viable: String,
    pub inviable: String,
}

#[derive(Deserialize, Clone, Debug)]
pub struct TermAndName {
    pub termid: String,
    pub name: String,
}

#[derive(Deserialize, Clone, Debug)]
pub struct InterPro {
    pub dbnames_to_filter: Vec<String>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct ServerSubsetConfig {
    pub prefixes_to_remove: Vec<String>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct ServerConfig {
    pub subsets: ServerSubsetConfig,
}

#[derive(Deserialize, Clone, Debug)]
pub struct Config {
    pub load_organism_taxonid: OrganismTaxonId,
    pub organisms: Vec<ConfigOrganism>,
    pub api_seq_chunk_sizes: Vec<usize>,
    pub extension_display_names: Vec<ExtensionDisplayNames>,
    pub extension_relation_order: RelationOrder,
    pub evidence_types: HashMap<ShortEvidenceCode, LongEvidenceCode>,
    pub cv_config: HashMap<CvName, CvConfig>,
// when creating a TermShort struct, for each of these termids if the term has
// an "interesting parent" using the given rel_name, we store it in the
// interesting_parents field of the TermShort
    pub interesting_parents: Vec<InterestingParent>,
    pub viability_terms: ViabilityTerms,
    pub go_slim_terms: Vec<TermAndName>,
    pub interpro: InterPro,
    pub server: ServerConfig,
}

impl Config {

    pub fn read(config_file_name: &str) -> Config {
        let file = match File::open(config_file_name) {
            Ok(file) => file,
            Err(err) => {
                panic!("Failed to read {}: {}\n", config_file_name, err)
            }
        };
        let reader = BufReader::new(file);

        match serde_json::from_reader(reader) {
            Ok(config) => config,
            Err(err) => {
                panic!("failed to parse {}: {}", config_file_name, err)
            },
        }
    }

    pub fn cv_config_by_name(&self, cv_name: &str) -> CvConfig {
        if let Some(config) = self.cv_config.get(cv_name) {
            config.clone()
        } else {
            CvConfig {
                feature_type: "gene".into(),
                filters: vec![],
                split_by_parents: vec![],
                summary_relations_to_hide: vec![],
                summary_relation_ranges_to_collect: vec![],
            }
        }
    }
}

pub const POMBASE_ANN_EXT_TERM_CV_NAME: &str = "PomBase annotation extension terms";
pub const ANNOTATION_EXT_REL_PREFIX: &str = "annotation_extension_relation-";

pub const DB_NAME: &str = "PomBase";

pub enum FeatureRelAnnotationType {
    Interaction,
    Ortholog,
    Paralog,
}
pub struct FeatureRelConfig {
    pub rel_type_name: &'static str,
    pub annotation_type: FeatureRelAnnotationType,
}
pub const FEATURE_REL_CONFIGS: [FeatureRelConfig; 4] =
    [
        FeatureRelConfig {
            rel_type_name: "interacts_physically",
            annotation_type: FeatureRelAnnotationType::Interaction,
        },
        FeatureRelConfig {
            rel_type_name: "interacts_genetically",
            annotation_type: FeatureRelAnnotationType::Interaction,
        },
        FeatureRelConfig {
            rel_type_name: "orthologous_to",
            annotation_type: FeatureRelAnnotationType::Ortholog,
        },
        FeatureRelConfig {
            rel_type_name: "paralogous_to",
            annotation_type: FeatureRelAnnotationType::Paralog,
        },
    ];

// relations to use when copy annotation to parents (ie. adding the
// annotation of child terms to parents)
pub const DESCENDANT_REL_NAMES: [&str; 7] =
    ["is_a", "part_of", "regulates", "positively_regulates", "negatively_regulates",
     "has_part", "output_of"];
// only consider has_part relations for these ontologies:
pub const HAS_PART_CV_NAMES: [&str; 1] = ["fission_yeast_phenotype"];

// number of genes before (and after) to add to the gene_neighbourhood field
pub const GENE_NEIGHBOURHOOD_DISTANCE: usize = 5;

pub const TRANSCRIPT_FEATURE_TYPES: [&str; 6] =
    ["snRNA", "rRNA", "mRNA", "snoRNA", "ncRNA", "tRNA"];
pub const TRANSCRIPT_PART_TYPES: [&str; 3] =
    ["five_prime_UTR", "exon", "three_prime_UTR"];

<commit_msg>Add Config.load_organism() method<commit_after>use std::collections::HashMap;
use std::io::BufReader;
use std::fs::File;

use types::*;
use serde_json;

// configuration for extension display names and for the "Target of" section
#[derive(Deserialize, Clone, Debug)]
pub struct ExtensionDisplayNames {
    pub rel_name: String, // name of extension relation
    pub display_name: String, // text to display
    pub if_descendent_of: Option<String>, // None if applies to any extension
    pub reciprocal_display: Option<String>, // None if reciprocal shouldn't be displayed
}

// "interesting parents" are those stored in the JSON in the TermShort structs
#[derive(Deserialize, Clone, Debug, PartialEq, Eq, Hash)]
pub struct InterestingParent {
    pub termid: String,
    pub rel_name: String,
}

// the order of relations within an extension:
#[derive(Deserialize, Clone, Debug)]
pub struct RelationOrder {
    // put the relations in this order in the displayed extensions:
    pub relation_order: Vec<String>,
    // except for these reactions which should always come last:
    pub always_last: Vec<String>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct TermFilterCategory {
    pub display_name: String,
    // this category matches these terms and their descendants
    pub ancestors: Vec<String>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct FilterConfig {
    pub filter_name: String,
    pub display_name: String,
    #[serde(skip_serializing_if="Vec::is_empty", default)]
    pub term_categories: Vec<TermFilterCategory>
}

#[derive(Deserialize, Clone, Debug)]
pub struct SplitByParentsConfig {
    pub termids: Vec<String>,
    pub display_name: String,
}

#[derive(Deserialize, Clone, Debug)]
pub struct CvConfig {
    pub feature_type: String,
    // filtering configured per CV
    #[serde(skip_serializing_if="Vec::is_empty", default)]
    pub filters: Vec<FilterConfig>,
    // config for splitting cv annotation tables into sub-sections
    // based on ancestry
    #[serde(skip_serializing_if="Vec::is_empty", default)]
    pub split_by_parents: Vec<SplitByParentsConfig>,
    // relations to not show in the summary
    #[serde(skip_serializing_if="Vec::is_empty", default)]
    pub summary_relations_to_hide: Vec<String>,
    // relations where the range is a gene ID to display like:
    //   has substrate pom1, cdc1 involved in negative regulation of ...
    // rather than as two lines
    #[serde(skip_serializing_if="Vec::is_empty", default)]
    pub summary_relation_ranges_to_collect: Vec<String>,
}

pub type ShortEvidenceCode = String;
pub type LongEvidenceCode = String;

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct ConfigOrganism {
    pub taxonid: OrganismTaxonId,
    pub genus: String,
    pub species: String,
}

impl ConfigOrganism {
    pub fn full_name(&self) -> String {
        self.genus.clone() + "_" + self.species.as_str()
    }
}

#[derive(Deserialize, Clone, Debug)]
pub struct ViabilityTerms {
    pub viable: String,
    pub inviable: String,
}

#[derive(Deserialize, Clone, Debug)]
pub struct TermAndName {
    pub termid: String,
    pub name: String,
}

#[derive(Deserialize, Clone, Debug)]
pub struct InterPro {
    pub dbnames_to_filter: Vec<String>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct ServerSubsetConfig {
    pub prefixes_to_remove: Vec<String>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct ServerConfig {
    pub subsets: ServerSubsetConfig,
}

#[derive(Deserialize, Clone, Debug)]
pub struct Config {
    pub load_organism_taxonid: OrganismTaxonId,
    pub organisms: Vec<ConfigOrganism>,
    pub api_seq_chunk_sizes: Vec<usize>,
    pub extension_display_names: Vec<ExtensionDisplayNames>,
    pub extension_relation_order: RelationOrder,
    pub evidence_types: HashMap<ShortEvidenceCode, LongEvidenceCode>,
    pub cv_config: HashMap<CvName, CvConfig>,
// when creating a TermShort struct, for each of these termids if the term has
// an "interesting parent" using the given rel_name, we store it in the
// interesting_parents field of the TermShort
    pub interesting_parents: Vec<InterestingParent>,
    pub viability_terms: ViabilityTerms,
    pub go_slim_terms: Vec<TermAndName>,
    pub interpro: InterPro,
    pub server: ServerConfig,
}

impl Config {

    pub fn read(config_file_name: &str) -> Config {
        let file = match File::open(config_file_name) {
            Ok(file) => file,
            Err(err) => {
                panic!("Failed to read {}: {}\n", config_file_name, err)
            }
        };
        let reader = BufReader::new(file);

        match serde_json::from_reader(reader) {
            Ok(config) => config,
            Err(err) => {
                panic!("failed to parse {}: {}", config_file_name, err)
            },
        }
    }

    pub fn cv_config_by_name(&self, cv_name: &str) -> CvConfig {
        if let Some(config) = self.cv_config.get(cv_name) {
            config.clone()
        } else {
            CvConfig {
                feature_type: "gene".into(),
                filters: vec![],
                split_by_parents: vec![],
                summary_relations_to_hide: vec![],
                summary_relation_ranges_to_collect: vec![],
            }
        }
    }

    pub fn load_organism(&self) -> ConfigOrganism {
        for org in &self.organisms {
            if org.taxonid == self.load_organism_taxonid {
                return org.clone();
            }
        }

        panic!("can't find configuration for load_organism_taxonid: {}",
               self.load_organism_taxonid);
    }
}

pub const POMBASE_ANN_EXT_TERM_CV_NAME: &str = "PomBase annotation extension terms";
pub const ANNOTATION_EXT_REL_PREFIX: &str = "annotation_extension_relation-";

pub const DB_NAME: &str = "PomBase";

pub enum FeatureRelAnnotationType {
    Interaction,
    Ortholog,
    Paralog,
}
pub struct FeatureRelConfig {
    pub rel_type_name: &'static str,
    pub annotation_type: FeatureRelAnnotationType,
}
pub const FEATURE_REL_CONFIGS: [FeatureRelConfig; 4] =
    [
        FeatureRelConfig {
            rel_type_name: "interacts_physically",
            annotation_type: FeatureRelAnnotationType::Interaction,
        },
        FeatureRelConfig {
            rel_type_name: "interacts_genetically",
            annotation_type: FeatureRelAnnotationType::Interaction,
        },
        FeatureRelConfig {
            rel_type_name: "orthologous_to",
            annotation_type: FeatureRelAnnotationType::Ortholog,
        },
        FeatureRelConfig {
            rel_type_name: "paralogous_to",
            annotation_type: FeatureRelAnnotationType::Paralog,
        },
    ];

// relations to use when copy annotation to parents (ie. adding the
// annotation of child terms to parents)
pub const DESCENDANT_REL_NAMES: [&str; 7] =
    ["is_a", "part_of", "regulates", "positively_regulates", "negatively_regulates",
     "has_part", "output_of"];
// only consider has_part relations for these ontologies:
pub const HAS_PART_CV_NAMES: [&str; 1] = ["fission_yeast_phenotype"];

// number of genes before (and after) to add to the gene_neighbourhood field
pub const GENE_NEIGHBOURHOOD_DISTANCE: usize = 5;

pub const TRANSCRIPT_FEATURE_TYPES: [&str; 6] =
    ["snRNA", "rRNA", "mRNA", "snoRNA", "ncRNA", "tRNA"];
pub const TRANSCRIPT_PART_TYPES: [&str; 3] =
    ["five_prime_UTR", "exon", "three_prime_UTR"];

<|endoftext|>


<commit_before>use tls::*;

pub enum StateChangeError {
    InvalidTransition,
    ParseError,
}

#[derive(Copy,Clone,Debug,PartialEq)]
pub enum TlsState {
    None,
    ClientHello,
    AskResumeSession,
    ResumeSession,
    ServerHello,
    Certificate,
    ServerKeyExchange,
    ServerHelloDone,
    ClientKeyExchange,
    ClientChangeCipherSpec,

    CRCertRequest,
    CRHelloDone,
    CRCert,
    CRClientKeyExchange,
    CRCertVerify,

    NoCertSKE,
    NoCertHelloDone,
    NoCertCKE,

    SessionEncrypted,

    Alert,

    Invalid,
}

pub fn tls_state_transition_handshake(state: TlsState, msg: &TlsMessageHandshake) -> Result<TlsState,StateChangeError> {
    match (state,msg) {
        (TlsState::None,             &TlsMessageHandshake::ClientHello(ref msg)) => {
            match msg.session_id {
                Some(_) => Ok(TlsState::AskResumeSession),
                _       => Ok(TlsState::ClientHello)
            }
        },
        // Server certificate
        (TlsState::ClientHello,      &TlsMessageHandshake::ServerHello(_))       => Ok(TlsState::ServerHello),
        (TlsState::ServerHello,      &TlsMessageHandshake::Certificate(_))       => Ok(TlsState::Certificate),
        // Server certificate, no client certificate requested
        (TlsState::Certificate,      &TlsMessageHandshake::ServerKeyExchange(_)) => Ok(TlsState::ServerKeyExchange),
        (TlsState::ServerKeyExchange,&TlsMessageHandshake::ServerDone(_))        => Ok(TlsState::ServerHelloDone),
        (TlsState::ServerHelloDone  ,&TlsMessageHandshake::ClientKeyExchange(_)) => Ok(TlsState::ClientKeyExchange),
        // Server certificate, client certificate requested
        (TlsState::Certificate,      &TlsMessageHandshake::CertificateRequest(_))=> Ok(TlsState::CRCertRequest),
        (TlsState::ServerKeyExchange,&TlsMessageHandshake::CertificateRequest(_))=> Ok(TlsState::CRCertRequest),
        (TlsState::CRCertRequest,    &TlsMessageHandshake::ServerDone(_))        => Ok(TlsState::CRHelloDone),
        (TlsState::CRHelloDone,      &TlsMessageHandshake::Certificate(_))       => Ok(TlsState::CRCert),
        (TlsState::CRCert,           &TlsMessageHandshake::ClientKeyExchange(_)) => Ok(TlsState::CRClientKeyExchange),
        (TlsState::CRClientKeyExchange, &TlsMessageHandshake::CertificateVerify(_)) => Ok(TlsState::CRCertVerify),
        // Server has no certificate (but accepts anonymous)
        (TlsState::ServerHello,      &TlsMessageHandshake::ServerKeyExchange(_)) => Ok(TlsState::NoCertSKE),
        (TlsState::NoCertSKE,        &TlsMessageHandshake::ServerDone(_))        => Ok(TlsState::NoCertHelloDone),
        (TlsState::NoCertHelloDone,  &TlsMessageHandshake::ClientKeyExchange(_)) => Ok(TlsState::NoCertCKE),
        // Resuming session
        (TlsState::AskResumeSession, &TlsMessageHandshake::ServerHello(_))       => Ok(TlsState::ResumeSession),
        // Hello requests must be accepted at any time (except start), but ignored [RFC5246] 7.4.1.1
        (TlsState::None,             &TlsMessageHandshake::HelloRequest)         => Err(StateChangeError::InvalidTransition),
        (s,                          &TlsMessageHandshake::HelloRequest)         => Ok(s),
        // All other transitions are considered invalid
        _ => Err(StateChangeError::InvalidTransition),
    }
}

pub fn tls_state_transition(state: TlsState, msg: &TlsMessage) -> Result<TlsState,StateChangeError> {
    match (state,msg) {
        (TlsState::Invalid,_) => Ok(TlsState::Invalid),
        (_,&TlsMessage::Handshake(ref m)) => tls_state_transition_handshake(state,m),
        // Server certificate
        (TlsState::ClientKeyExchange,     &TlsMessage::ChangeCipherSpec) => Ok(TlsState::ClientChangeCipherSpec),
        (TlsState::ClientChangeCipherSpec,&TlsMessage::ChangeCipherSpec) => Ok(TlsState::SessionEncrypted),
        // Server certificate, client certificate requested
        (TlsState::CRClientKeyExchange,   &TlsMessage::ChangeCipherSpec) => Ok(TlsState::ClientChangeCipherSpec),
        (TlsState::CRCertVerify,          &TlsMessage::ChangeCipherSpec) => Ok(TlsState::ClientChangeCipherSpec),
        // No server certificate
        (TlsState::NoCertCKE,             &TlsMessage::ChangeCipherSpec) => Ok(TlsState::ClientChangeCipherSpec),
        // Resume session
        (TlsState::ResumeSession,         &TlsMessage::ChangeCipherSpec) => Ok(TlsState::ClientChangeCipherSpec),
        (_,_) => Err(StateChangeError::InvalidTransition),
    }
}
<commit_msg>Add CertificateStatus state<commit_after>use tls::*;

pub enum StateChangeError {
    InvalidTransition,
    ParseError,
}

#[derive(Copy,Clone,Debug,PartialEq)]
pub enum TlsState {
    None,
    ClientHello,
    AskResumeSession,
    ResumeSession,
    ServerHello,
    Certificate,
    CertificateSt,
    ServerKeyExchange,
    ServerHelloDone,
    ClientKeyExchange,
    ClientChangeCipherSpec,

    CRCertRequest,
    CRHelloDone,
    CRCert,
    CRClientKeyExchange,
    CRCertVerify,

    NoCertSKE,
    NoCertHelloDone,
    NoCertCKE,

    SessionEncrypted,

    Alert,

    Invalid,
}

pub fn tls_state_transition_handshake(state: TlsState, msg: &TlsMessageHandshake) -> Result<TlsState,StateChangeError> {
    match (state,msg) {
        (TlsState::None,             &TlsMessageHandshake::ClientHello(ref msg)) => {
            match msg.session_id {
                Some(_) => Ok(TlsState::AskResumeSession),
                _       => Ok(TlsState::ClientHello)
            }
        },
        // Server certificate
        (TlsState::ClientHello,      &TlsMessageHandshake::ServerHello(_))       => Ok(TlsState::ServerHello),
        (TlsState::ServerHello,      &TlsMessageHandshake::Certificate(_))       => Ok(TlsState::Certificate),
        // Server certificate, no client certificate requested
        (TlsState::Certificate,      &TlsMessageHandshake::ServerKeyExchange(_)) => Ok(TlsState::ServerKeyExchange),
        (TlsState::Certificate,      &TlsMessageHandshake::CertificateStatus(_)) => Ok(TlsState::CertificateSt),
        (TlsState::CertificateSt,    &TlsMessageHandshake::ServerKeyExchange(_)) => Ok(TlsState::ServerKeyExchange),
        (TlsState::ServerKeyExchange,&TlsMessageHandshake::ServerDone(_))        => Ok(TlsState::ServerHelloDone),
        (TlsState::ServerHelloDone  ,&TlsMessageHandshake::ClientKeyExchange(_)) => Ok(TlsState::ClientKeyExchange),
        // Server certificate, client certificate requested
        (TlsState::Certificate,      &TlsMessageHandshake::CertificateRequest(_))=> Ok(TlsState::CRCertRequest),
        (TlsState::ServerKeyExchange,&TlsMessageHandshake::CertificateRequest(_))=> Ok(TlsState::CRCertRequest),
        (TlsState::CRCertRequest,    &TlsMessageHandshake::ServerDone(_))        => Ok(TlsState::CRHelloDone),
        (TlsState::CRHelloDone,      &TlsMessageHandshake::Certificate(_))       => Ok(TlsState::CRCert),
        (TlsState::CRCert,           &TlsMessageHandshake::ClientKeyExchange(_)) => Ok(TlsState::CRClientKeyExchange),
        (TlsState::CRClientKeyExchange, &TlsMessageHandshake::CertificateVerify(_)) => Ok(TlsState::CRCertVerify),
        // Server has no certificate (but accepts anonymous)
        (TlsState::ServerHello,      &TlsMessageHandshake::ServerKeyExchange(_)) => Ok(TlsState::NoCertSKE),
        (TlsState::NoCertSKE,        &TlsMessageHandshake::ServerDone(_))        => Ok(TlsState::NoCertHelloDone),
        (TlsState::NoCertHelloDone,  &TlsMessageHandshake::ClientKeyExchange(_)) => Ok(TlsState::NoCertCKE),
        // Resuming session
        (TlsState::AskResumeSession, &TlsMessageHandshake::ServerHello(_))       => Ok(TlsState::ResumeSession),
        // Hello requests must be accepted at any time (except start), but ignored [RFC5246] 7.4.1.1
        (TlsState::None,             &TlsMessageHandshake::HelloRequest)         => Err(StateChangeError::InvalidTransition),
        (s,                          &TlsMessageHandshake::HelloRequest)         => Ok(s),
        // All other transitions are considered invalid
        _ => Err(StateChangeError::InvalidTransition),
    }
}

pub fn tls_state_transition(state: TlsState, msg: &TlsMessage) -> Result<TlsState,StateChangeError> {
    match (state,msg) {
        (TlsState::Invalid,_) => Ok(TlsState::Invalid),
        (_,&TlsMessage::Handshake(ref m)) => tls_state_transition_handshake(state,m),
        // Server certificate
        (TlsState::ClientKeyExchange,     &TlsMessage::ChangeCipherSpec) => Ok(TlsState::ClientChangeCipherSpec),
        (TlsState::ClientChangeCipherSpec,&TlsMessage::ChangeCipherSpec) => Ok(TlsState::SessionEncrypted),
        // Server certificate, client certificate requested
        (TlsState::CRClientKeyExchange,   &TlsMessage::ChangeCipherSpec) => Ok(TlsState::ClientChangeCipherSpec),
        (TlsState::CRCertVerify,          &TlsMessage::ChangeCipherSpec) => Ok(TlsState::ClientChangeCipherSpec),
        // No server certificate
        (TlsState::NoCertCKE,             &TlsMessage::ChangeCipherSpec) => Ok(TlsState::ClientChangeCipherSpec),
        // Resume session
        (TlsState::ResumeSession,         &TlsMessage::ChangeCipherSpec) => Ok(TlsState::ClientChangeCipherSpec),
        (_,_) => Err(StateChangeError::InvalidTransition),
    }
}
<|endoftext|>


<commit_before>//! Two-dimensional penetration depth queries using the Expanding Polytope Algorithm.

use std::cmp::Ordering;
use std::collections::BinaryHeap;

use na::{self, Unit};
use simba::scalar::RealField;

use crate::math::{Isometry, Point, Vector};
use crate::query::algorithms::{
    gjk, special_support_maps::ConstantOrigin, CSOPoint, VoronoiSimplex,
};
use crate::shape::SupportMap;
use crate::utils;

#[derive(Copy, Clone, PartialEq)]
struct FaceId<N: RealField> {
    id: usize,
    neg_dist: N,
}

impl<N: RealField> FaceId<N> {
    fn new(id: usize, neg_dist: N) -> Option<Self> {
        if neg_dist > gjk::eps_tol() {
            //            println!(
            //                "EPA: the origin was outside of the CSO: {} > tolerence ({})",
            //                neg_dist,
            //                gjk::eps_tol::<N>()
            //            );
            None
        } else {
            Some(FaceId { id, neg_dist })
        }
    }
}

impl<N: RealField> Eq for FaceId<N> {}

impl<N: RealField> PartialOrd for FaceId<N> {
    #[inline]
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.neg_dist.partial_cmp(&other.neg_dist)
    }
}

impl<N: RealField> Ord for FaceId<N> {
    #[inline]
    fn cmp(&self, other: &Self) -> Ordering {
        if self.neg_dist < other.neg_dist {
            Ordering::Less
        } else if self.neg_dist > other.neg_dist {
            Ordering::Greater
        } else {
            Ordering::Equal
        }
    }
}

#[derive(Clone, Debug)]
struct Face<N: RealField> {
    pts: [usize; 2],
    normal: Unit<Vector<N>>,
    proj: Point<N>,
    bcoords: [N; 2],
    deleted: bool,
}

impl<N: RealField> Face<N> {
    pub fn new(vertices: &[CSOPoint<N>], pts: [usize; 2]) -> (Self, bool) {
        if let Some((proj, bcoords)) =
            project_origin(&vertices[pts[0]].point, &vertices[pts[1]].point)
        {
            (Self::new_with_proj(vertices, proj, bcoords, pts), true)
        } else {
            (
                Self::new_with_proj(vertices, Point::origin(), [N::zero(); 2], pts),
                false,
            )
        }
    }

    pub fn new_with_proj(
        vertices: &[CSOPoint<N>],
        proj: Point<N>,
        bcoords: [N; 2],
        pts: [usize; 2],
    ) -> Self {
        let normal;
        let deleted;

        if let Some(n) = utils::ccw_face_normal([&vertices[pts[0]].point, &vertices[pts[1]].point])
        {
            normal = n;
            deleted = false;
        } else {
            normal = Unit::new_unchecked(na::zero());
            deleted = true;
        }

        Face {
            pts,
            normal,
            proj,
            bcoords,
            deleted,
        }
    }

    pub fn closest_points(&self, vertices: &[CSOPoint<N>]) -> (Point<N>, Point<N>) {
        (
            vertices[self.pts[0]].orig1 * self.bcoords[0]
                + vertices[self.pts[1]].orig1.coords * self.bcoords[1],
            vertices[self.pts[0]].orig2 * self.bcoords[0]
                + vertices[self.pts[1]].orig2.coords * self.bcoords[1],
        )
    }
}

/// The Expanding Polytope Algorithm in 2D.
pub struct EPA<N: RealField> {
    vertices: Vec<CSOPoint<N>>,
    faces: Vec<Face<N>>,
    heap: BinaryHeap<FaceId<N>>,
}

impl<N: RealField> EPA<N> {
    /// Creates a new instance of the 2D Expanding Polytope Algorithm.
    pub fn new() -> Self {
        EPA {
            vertices: Vec::new(),
            faces: Vec::new(),
            heap: BinaryHeap::new(),
        }
    }

    fn reset(&mut self) {
        self.vertices.clear();
        self.faces.clear();
        self.heap.clear();
    }

    /// Projects the origin on boundary the given shape.
    ///
    /// The origin is assumed to be inside of the shape. If it is outside, use
    /// the GJK algorithm instead.
    /// Return `None` if the origin is not inside of the shape or if
    /// the EPA algorithm failed to compute the projection.
    pub fn project_origin<G: ?Sized>(
        &mut self,
        m: &Isometry<N>,
        g: &G,
        simplex: &VoronoiSimplex<N>,
    ) -> Option<Point<N>>
    where
        G: SupportMap<N>,
    {
        self.closest_points(m, g, &Isometry::identity(), &ConstantOrigin, simplex)
            .map(|(p, _, _)| p)
    }

    /// Projects the origin on a shape unsing the EPA algorithm.
    ///
    /// The origin is assumed to be located inside of the shape.
    /// Returns `None` if the EPA fails to converge or if `g1` and `g2` are not penetrating.
    pub fn closest_points<G1: ?Sized, G2: ?Sized>(
        &mut self,
        m1: &Isometry<N>,
        g1: &G1,
        m2: &Isometry<N>,
        g2: &G2,
        simplex: &VoronoiSimplex<N>,
    ) -> Option<(Point<N>, Point<N>, Unit<Vector<N>>)>
    where
        G1: SupportMap<N>,
        G2: SupportMap<N>,
    {
        let _eps = N::default_epsilon();
        let _eps_tol = _eps * na::convert(100.0f64);

        self.reset();

        /*
         * Initialization.
         */
        for i in 0..simplex.dimension() + 1 {
            self.vertices.push(*simplex.point(i));
        }

        if simplex.dimension() == 0 {
            let mut n: Vector<N> = na::zero();
            n[1] = na::one();
            return Some((Point::origin(), Point::origin(), Unit::new_unchecked(n)));
        } else if simplex.dimension() == 2 {
            let dp1 = self.vertices[1] - self.vertices[0];
            let dp2 = self.vertices[2] - self.vertices[0];

            if dp1.perp(&dp2) < na::zero() {
                self.vertices.swap(1, 2)
            }

            let pts1 = [0, 1];
            let pts2 = [1, 2];
            let pts3 = [2, 0];

            let (face1, proj_is_inside1) = Face::new(&self.vertices, pts1);
            let (face2, proj_is_inside2) = Face::new(&self.vertices, pts2);
            let (face3, proj_is_inside3) = Face::new(&self.vertices, pts3);

            self.faces.push(face1);
            self.faces.push(face2);
            self.faces.push(face3);

            if proj_is_inside1 {
                let dist1 = self.faces[0].normal.dot(&self.vertices[0].point.coords);
                self.heap.push(FaceId::new(0, -dist1)?);
            }

            if proj_is_inside2 {
                let dist2 = self.faces[1].normal.dot(&self.vertices[1].point.coords);
                self.heap.push(FaceId::new(1, -dist2)?);
            }

            if proj_is_inside3 {
                let dist3 = self.faces[2].normal.dot(&self.vertices[2].point.coords);
                self.heap.push(FaceId::new(2, -dist3)?);
            }
        } else {
            let pts1 = [0, 1];
            let pts2 = [1, 0];

            self.faces.push(Face::new_with_proj(
                &self.vertices,
                Point::origin(),
                [N::one(), N::zero()],
                pts1,
            ));
            self.faces.push(Face::new_with_proj(
                &self.vertices,
                Point::origin(),
                [N::one(), N::zero()],
                pts2,
            ));

            let dist1 = self.faces[0].normal.dot(&self.vertices[0].point.coords);
            let dist2 = self.faces[1].normal.dot(&self.vertices[1].point.coords);

            self.heap.push(FaceId::new(0, dist1)?);
            self.heap.push(FaceId::new(1, dist2)?);
        }

        let mut niter = 0;
        let mut max_dist = N::max_value();
        let mut best_face_id = *self.heap.peek().unwrap();

        /*
         * Run the expansion.
         */
        while let Some(face_id) = self.heap.pop() {
            // Create new faces.
            let face = self.faces[face_id.id].clone();

            if face.deleted {
                continue;
            }

            let cso_point = CSOPoint::from_shapes(m1, g1, m2, g2, &face.normal);
            let support_point_id = self.vertices.len();
            self.vertices.push(cso_point);

            let candidate_max_dist = cso_point.point.coords.dot(&face.normal);

            if candidate_max_dist < max_dist {
                best_face_id = face_id;
                max_dist = candidate_max_dist;
            }

            let curr_dist = -face_id.neg_dist;

            if max_dist - curr_dist < _eps_tol {
                let best_face = &self.faces[best_face_id.id];
                let cpts = best_face.closest_points(&self.vertices);
                return Some((cpts.0, cpts.1, best_face.normal));
            }

            let pts1 = [face.pts[0], support_point_id];
            let pts2 = [support_point_id, face.pts[1]];

            let new_faces = [
                Face::new(&self.vertices, pts1),
                Face::new(&self.vertices, pts2),
            ];

            for f in new_faces.iter() {
                if f.1 {
                    let dist = f.0.normal.dot(&f.0.proj.coords);
                    if dist < curr_dist {
                        // FIXME: if we reach this point, there were issues due to
                        // numerical errors.
                        let cpts = f.0.closest_points(&self.vertices);
                        return Some((cpts.0, cpts.1, f.0.normal));
                    }

                    if !f.0.deleted {
                        self.heap.push(FaceId::new(self.faces.len(), -dist)?);
                    }
                }

                self.faces.push(f.0.clone());
            }

            niter += 1;
            if niter > 10000 {
                //                println!("EPA did not converge after 1000 iterations… stopping the iterations.");
                return None;
            }
        }

        let best_face = &self.faces[best_face_id.id];
        let cpts = best_face.closest_points(&self.vertices);
        return Some((cpts.0, cpts.1, best_face.normal));
    }
}

fn project_origin<N: RealField>(a: &Point<N>, b: &Point<N>) -> Option<(Point<N>, [N; 2])> {
    let ab = *b - *a;
    let ap = -a.coords;
    let ab_ap = ab.dot(&ap);
    let sqnab = ab.norm_squared();

    if sqnab == na::zero() {
        return None;
    }

    let position_on_segment;

    let _eps: N = gjk::eps_tol();

    if ab_ap < -_eps || ab_ap > sqnab + _eps {
        // Voronoï region of vertex 'a' or 'b'.
        None
    } else {
        // Voronoï region of the segment interior.
        position_on_segment = ab_ap / sqnab;

        let res = *a + ab * position_on_segment;

        Some((res, [N::one() - position_on_segment, position_on_segment]))
    }
}
<commit_msg>EPA2: extract a valid contact normal for the vertex-vertex case.<commit_after>//! Two-dimensional penetration depth queries using the Expanding Polytope Algorithm.

use std::cmp::Ordering;
use std::collections::BinaryHeap;

use na::{self, Unit};
use simba::scalar::RealField;

use crate::math::{Isometry, Point, Vector};
use crate::query::algorithms::{
    gjk, special_support_maps::ConstantOrigin, CSOPoint, VoronoiSimplex,
};
use crate::shape::SupportMap;
use crate::utils;

#[derive(Copy, Clone, PartialEq)]
struct FaceId<N: RealField> {
    id: usize,
    neg_dist: N,
}

impl<N: RealField> FaceId<N> {
    fn new(id: usize, neg_dist: N) -> Option<Self> {
        if neg_dist > gjk::eps_tol() {
            //            println!(
            //                "EPA: the origin was outside of the CSO: {} > tolerence ({})",
            //                neg_dist,
            //                gjk::eps_tol::<N>()
            //            );
            None
        } else {
            Some(FaceId { id, neg_dist })
        }
    }
}

impl<N: RealField> Eq for FaceId<N> {}

impl<N: RealField> PartialOrd for FaceId<N> {
    #[inline]
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.neg_dist.partial_cmp(&other.neg_dist)
    }
}

impl<N: RealField> Ord for FaceId<N> {
    #[inline]
    fn cmp(&self, other: &Self) -> Ordering {
        if self.neg_dist < other.neg_dist {
            Ordering::Less
        } else if self.neg_dist > other.neg_dist {
            Ordering::Greater
        } else {
            Ordering::Equal
        }
    }
}

#[derive(Clone, Debug)]
struct Face<N: RealField> {
    pts: [usize; 2],
    normal: Unit<Vector<N>>,
    proj: Point<N>,
    bcoords: [N; 2],
    deleted: bool,
}

impl<N: RealField> Face<N> {
    pub fn new(vertices: &[CSOPoint<N>], pts: [usize; 2]) -> (Self, bool) {
        if let Some((proj, bcoords)) =
            project_origin(&vertices[pts[0]].point, &vertices[pts[1]].point)
        {
            (Self::new_with_proj(vertices, proj, bcoords, pts), true)
        } else {
            (
                Self::new_with_proj(vertices, Point::origin(), [N::zero(); 2], pts),
                false,
            )
        }
    }

    pub fn new_with_proj(
        vertices: &[CSOPoint<N>],
        proj: Point<N>,
        bcoords: [N; 2],
        pts: [usize; 2],
    ) -> Self {
        let normal;
        let deleted;

        if let Some(n) = utils::ccw_face_normal([&vertices[pts[0]].point, &vertices[pts[1]].point])
        {
            normal = n;
            deleted = false;
        } else {
            normal = Unit::new_unchecked(na::zero());
            deleted = true;
        }

        Face {
            pts,
            normal,
            proj,
            bcoords,
            deleted,
        }
    }

    pub fn closest_points(&self, vertices: &[CSOPoint<N>]) -> (Point<N>, Point<N>) {
        (
            vertices[self.pts[0]].orig1 * self.bcoords[0]
                + vertices[self.pts[1]].orig1.coords * self.bcoords[1],
            vertices[self.pts[0]].orig2 * self.bcoords[0]
                + vertices[self.pts[1]].orig2.coords * self.bcoords[1],
        )
    }
}

/// The Expanding Polytope Algorithm in 2D.
pub struct EPA<N: RealField> {
    vertices: Vec<CSOPoint<N>>,
    faces: Vec<Face<N>>,
    heap: BinaryHeap<FaceId<N>>,
}

impl<N: RealField> EPA<N> {
    /// Creates a new instance of the 2D Expanding Polytope Algorithm.
    pub fn new() -> Self {
        EPA {
            vertices: Vec::new(),
            faces: Vec::new(),
            heap: BinaryHeap::new(),
        }
    }

    fn reset(&mut self) {
        self.vertices.clear();
        self.faces.clear();
        self.heap.clear();
    }

    /// Projects the origin on boundary the given shape.
    ///
    /// The origin is assumed to be inside of the shape. If it is outside, use
    /// the GJK algorithm instead.
    /// Return `None` if the origin is not inside of the shape or if
    /// the EPA algorithm failed to compute the projection.
    pub fn project_origin<G: ?Sized>(
        &mut self,
        m: &Isometry<N>,
        g: &G,
        simplex: &VoronoiSimplex<N>,
    ) -> Option<Point<N>>
    where
        G: SupportMap<N>,
    {
        self.closest_points(m, g, &Isometry::identity(), &ConstantOrigin, simplex)
            .map(|(p, _, _)| p)
    }

    /// Projects the origin on a shape unsing the EPA algorithm.
    ///
    /// The origin is assumed to be located inside of the shape.
    /// Returns `None` if the EPA fails to converge or if `g1` and `g2` are not penetrating.
    pub fn closest_points<G1: ?Sized, G2: ?Sized>(
        &mut self,
        m1: &Isometry<N>,
        g1: &G1,
        m2: &Isometry<N>,
        g2: &G2,
        simplex: &VoronoiSimplex<N>,
    ) -> Option<(Point<N>, Point<N>, Unit<Vector<N>>)>
    where
        G1: SupportMap<N>,
        G2: SupportMap<N>,
    {
        let _eps = N::default_epsilon();
        let _eps_tol = _eps * na::convert(100.0f64);

        self.reset();

        /*
         * Initialization.
         */
        for i in 0..simplex.dimension() + 1 {
            self.vertices.push(*simplex.point(i));
        }

        if simplex.dimension() == 0 {
            const MAX_ITERS: usize = 100; // If there is no convergence, just use whatever direction was extracted so fare

            // The contact is vertex-vertex.
            // We need to determine a valid normal that lies
            // on both vertices' normal cone.
            let mut n = Vector::y_axis();

            // First, find a vector on the first vertex tangent cone.
            let orig1 = self.vertices[0].orig1;
            for _ in 0..MAX_ITERS {
                let supp1 = g1.support_point(m1, &n);
                if let Some(tangent) = Unit::try_new(supp1 - orig1, _eps_tol) {
                    if n.dot(&tangent) < _eps_tol {
                        break;
                    }

                    n = Unit::new_unchecked(Vector::new(-tangent.y, tangent.x));
                } else {
                    break;
                }
            }

            // Second, ensure the direction lies on the second vertex's tangent cone.
            let orig2 = self.vertices[0].orig2;
            for _ in 0..MAX_ITERS {
                let supp2 = g2.support_point(m2, &-n);
                if let Some(tangent) = Unit::try_new(supp2 - orig2, _eps_tol) {
                    if (-n).dot(&tangent) < _eps_tol {
                        break;
                    }

                    n = Unit::new_unchecked(Vector::new(-tangent.y, tangent.x));
                } else {
                    break;
                }
            }

            return Some((Point::origin(), Point::origin(), n));
        } else if simplex.dimension() == 2 {
            let dp1 = self.vertices[1] - self.vertices[0];
            let dp2 = self.vertices[2] - self.vertices[0];

            if dp1.perp(&dp2) < na::zero() {
                self.vertices.swap(1, 2)
            }

            let pts1 = [0, 1];
            let pts2 = [1, 2];
            let pts3 = [2, 0];

            let (face1, proj_is_inside1) = Face::new(&self.vertices, pts1);
            let (face2, proj_is_inside2) = Face::new(&self.vertices, pts2);
            let (face3, proj_is_inside3) = Face::new(&self.vertices, pts3);

            self.faces.push(face1);
            self.faces.push(face2);
            self.faces.push(face3);

            if proj_is_inside1 {
                let dist1 = self.faces[0].normal.dot(&self.vertices[0].point.coords);
                self.heap.push(FaceId::new(0, -dist1)?);
            }

            if proj_is_inside2 {
                let dist2 = self.faces[1].normal.dot(&self.vertices[1].point.coords);
                self.heap.push(FaceId::new(1, -dist2)?);
            }

            if proj_is_inside3 {
                let dist3 = self.faces[2].normal.dot(&self.vertices[2].point.coords);
                self.heap.push(FaceId::new(2, -dist3)?);
            }
        } else {
            let pts1 = [0, 1];
            let pts2 = [1, 0];

            self.faces.push(Face::new_with_proj(
                &self.vertices,
                Point::origin(),
                [N::one(), N::zero()],
                pts1,
            ));
            self.faces.push(Face::new_with_proj(
                &self.vertices,
                Point::origin(),
                [N::one(), N::zero()],
                pts2,
            ));

            let dist1 = self.faces[0].normal.dot(&self.vertices[0].point.coords);
            let dist2 = self.faces[1].normal.dot(&self.vertices[1].point.coords);

            self.heap.push(FaceId::new(0, dist1)?);
            self.heap.push(FaceId::new(1, dist2)?);
        }

        let mut niter = 0;
        let mut max_dist = N::max_value();
        let mut best_face_id = *self.heap.peek().unwrap();

        /*
         * Run the expansion.
         */
        while let Some(face_id) = self.heap.pop() {
            // Create new faces.
            let face = self.faces[face_id.id].clone();

            if face.deleted {
                continue;
            }

            let cso_point = CSOPoint::from_shapes(m1, g1, m2, g2, &face.normal);
            let support_point_id = self.vertices.len();
            self.vertices.push(cso_point);

            let candidate_max_dist = cso_point.point.coords.dot(&face.normal);

            if candidate_max_dist < max_dist {
                best_face_id = face_id;
                max_dist = candidate_max_dist;
            }

            let curr_dist = -face_id.neg_dist;

            if max_dist - curr_dist < _eps_tol {
                let best_face = &self.faces[best_face_id.id];
                let cpts = best_face.closest_points(&self.vertices);
                return Some((cpts.0, cpts.1, best_face.normal));
            }

            let pts1 = [face.pts[0], support_point_id];
            let pts2 = [support_point_id, face.pts[1]];

            let new_faces = [
                Face::new(&self.vertices, pts1),
                Face::new(&self.vertices, pts2),
            ];

            for f in new_faces.iter() {
                if f.1 {
                    let dist = f.0.normal.dot(&f.0.proj.coords);
                    if dist < curr_dist {
                        // FIXME: if we reach this point, there were issues due to
                        // numerical errors.
                        let cpts = f.0.closest_points(&self.vertices);
                        return Some((cpts.0, cpts.1, f.0.normal));
                    }

                    if !f.0.deleted {
                        self.heap.push(FaceId::new(self.faces.len(), -dist)?);
                    }
                }

                self.faces.push(f.0.clone());
            }

            niter += 1;
            if niter > 10000 {
                //                println!("EPA did not converge after 1000 iterations… stopping the iterations.");
                return None;
            }
        }

        let best_face = &self.faces[best_face_id.id];
        let cpts = best_face.closest_points(&self.vertices);
        return Some((cpts.0, cpts.1, best_face.normal));
    }
}

fn project_origin<N: RealField>(a: &Point<N>, b: &Point<N>) -> Option<(Point<N>, [N; 2])> {
    let ab = *b - *a;
    let ap = -a.coords;
    let ab_ap = ab.dot(&ap);
    let sqnab = ab.norm_squared();

    if sqnab == na::zero() {
        return None;
    }

    let position_on_segment;

    let _eps: N = gjk::eps_tol();

    if ab_ap < -_eps || ab_ap > sqnab + _eps {
        // Voronoï region of vertex 'a' or 'b'.
        None
    } else {
        // Voronoï region of the segment interior.
        position_on_segment = ab_ap / sqnab;

        let res = *a + ab * position_on_segment;

        Some((res, [N::one() - position_on_segment, position_on_segment]))
    }
}
<|endoftext|>


<commit_before>/// eventbox is a simple abstract of event handling
///
/// The concept is:
///
/// An eventbox stores a vector of events, the order does not mather.
///
/// 1. the sender and receiver of a/some events share an eventbox
/// 2. when some event happans, the sender push the event/value into the eventbox.
/// 3. Meanwhile the receiver is waiting(blocked).
/// 4. When some event happen, eventbox will notify the receiver.
///
/// # Examples
/// ```
/// use std::sync::Arc;
/// use std::thread;
/// use fzf_rs::util::eventbox::EventBox;
/// let mut eb = Arc::new(EventBox::new());
/// let mut eb2 = eb.clone();
///
/// thread::spawn(move || {
///     eb2.set(10, Box::new(20));
/// });
///
/// let val: i32 = *eb.wait_for(10).downcast().unwrap();
/// assert_eq!(20, val);
/// ```

use std::sync::{Condvar, Mutex};
use std::collections::HashMap;
use std::any::Any;
use std::mem;
use std::hash::Hash;

pub type Value = Box<Any + 'static + Send>;
pub type Events<T> = HashMap<T, Value>;

struct EventData<T> {
    events: Events<T>,
    ignore: Events<T>,
}

pub struct EventBox<T> {
    mutex: Mutex<EventData<T>>,
    cond: Condvar,
}

impl<T: Hash + Eq + Copy> EventBox<T> {
    pub fn new() -> Self {
        EventBox {
            mutex: Mutex::new(EventData{events: HashMap::new(), ignore: HashMap::new()}),
            cond: Condvar::new(),
        }
    }

    /// wait: wait for an event(any) to fire
    /// if any event is triggered, run callback on events vector
    pub fn wait(&self) -> Events<T> {
        let mut data = self.mutex.lock().unwrap();
        let events = mem::replace(&mut data.events, HashMap::new());
        let num_of_events = events.len();
        if num_of_events == 0 {
            let _ = self.cond.wait(data);
        }
        events
    }

    /// set: fires an event
    pub fn set(&self, e: T, value: Value) {
        let mut data = self.mutex.lock().unwrap();
        {
            let val = data.events.entry(e).or_insert(Box::new(0));
            *val = value;
        }
        if !data.ignore.contains_key(&e) {
            self.cond.notify_all();
        }
    }

    /// clear the event map
    pub fn clear(&self) {
        let mut data = self.mutex.lock().unwrap();
        data.events.clear();
    }

    // peek at the event box to check whether event had been set or not
    pub fn peek(&self, event: T) -> bool {
        let data = self.mutex.lock().unwrap();
        data.events.contains_key(&event)
    }

    // remove events from ignore table
    pub fn watch(&self, events: &Vec<T>) {
        let mut data = self.mutex.lock().unwrap();
        for e in events {
            data.ignore.remove(e);
        }
    }

    // add events from ignore table
    pub fn unwatch(&self, events: &Vec<T>) {
        let mut data = self.mutex.lock().unwrap();
        for e in events {
            data.ignore.insert(*e, Box::new(true));
        }
    }

    pub fn wait_for(&self, event: T) -> Value {
        'event_found: loop {
            for (e, val) in self.wait() {
                if e == event {
                    return val
                }
            }
        }
    }

    pub fn is_empty(&self) -> bool {
        let data = self.mutex.lock().unwrap();
        data.events.len() == 0
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::thread;
    use std::sync::{Arc, Mutex};
    use std::time::Duration;

    #[test]
    fn test_wait() {
        const NUM_OF_EVENTS: i32 = 4;

        // create `NUM_OF_EVENTS` threads that set the return value to
        // their thread number, the sum up the value and compare it in
        // the main thread.

        let eb = Arc::new(EventBox::new());
        let counter = Arc::new(Mutex::new(0));
        for i in 1..(NUM_OF_EVENTS+1) {
            let eb_clone = eb.clone();
            let counter_clone = counter.clone();
            thread::spawn(move || {
                eb_clone.set(i, Box::new(i));
                let mut count = counter_clone.lock().unwrap();
                *count += 1;
            });
        }

        // wait till all events are set
        loop {
            thread::sleep(Duration::from_millis(100));
            let count = counter.lock().unwrap();
            if *count == NUM_OF_EVENTS {
                break;
            }
        }

        let mut total: i32 = 0;
        for (_, val) in eb.wait() {
            total += *val.downcast().unwrap();
        }

        assert_eq!((1..(NUM_OF_EVENTS+1)).fold(0, |x, acc| acc+x), total);
    }

    #[test]
    fn test_wait_for() {
        let eb = Arc::new(EventBox::new());
        let eb2 = eb.clone();

        thread::spawn(move || {
            eb2.set(10, Box::new(20));
        });

        let val: i32 = *eb.wait_for(10).downcast().unwrap();
        assert_eq!(20, val);
    }

    #[test]
    fn test_unwatch_set() {
        const NUM_OF_EVENTS: i32 = 4;
        let eb = Arc::new(EventBox::new());

        // this time, we ignore event NO. NUM_OF_EVENTS
        // note that unwatch will not trigger the event notification, but the
        // value are actually set.
        eb.unwatch(&vec![NUM_OF_EVENTS]);

        let counter = Arc::new(Mutex::new(0));
        for i in 1..(NUM_OF_EVENTS+1) {
            let eb_clone = eb.clone();
            let counter_clone = counter.clone();
            thread::spawn(move || {
                eb_clone.set(i, Box::new(i));
                let mut count = counter_clone.lock().unwrap();
                *count += 1;
            });
        }

        // wait till all events are set
        loop {
            thread::sleep(Duration::from_millis(100));
            let count = counter.lock().unwrap();
            if *count == NUM_OF_EVENTS {
                break;
            }
        }

        let mut total: i32 = 0;
        for (_, val) in eb.wait() {
            total += *val.downcast().unwrap();
        }

        assert_eq!((1..(NUM_OF_EVENTS+1)).fold(0, |x, acc| acc+x), total);
    }

    #[test]
    fn test_unwatch_notify() {
        // unwatched event will not trigger notification

        let eb = Arc::new(EventBox::new());

        eb.unwatch(&vec![1]);

        let eb_clone1 = eb.clone();

        let which_one = Arc::new(Mutex::new(1));
        let which_one_clone = which_one.clone();

        let wait = thread::spawn(move || {
            for (_, _) in eb.wait() {
                let mut data = which_one.lock().unwrap();
                assert_eq!(2, *data);
            }
        });

        thread::spawn(move || {
            eb_clone1.set(1, Box::new(1));

            // to ensure that the `wait` in main thread have time to trigger.
            // of course, the expected behavior is that it will not.
            thread::sleep(Duration::from_millis(100));

            let mut data = which_one_clone.lock().unwrap();
            *data = 2;
            eb_clone1.set(2, Box::new(2));
        });

        wait.join();
    }
}
<commit_msg>[eventbox] fix: wait() will return empty events.<commit_after>/// eventbox is a simple abstract of event handling
///
/// The concept is:
///
/// An eventbox stores a vector of events, the order does not mather.
///
/// 1. the sender and receiver of a/some events share an eventbox
/// 2. when some event happans, the sender push the event/value into the eventbox.
/// 3. Meanwhile the receiver is waiting(blocked).
/// 4. When some event happen, eventbox will notify the receiver.
///
/// # Examples
/// ```
/// use std::sync::Arc;
/// use std::thread;
/// use fzf_rs::util::eventbox::EventBox;
/// let mut eb = Arc::new(EventBox::new());
/// let mut eb2 = eb.clone();
///
/// thread::spawn(move || {
///     eb2.set(10, Box::new(20));
/// });
///
/// let val: i32 = *eb.wait_for(10).downcast().unwrap();
/// assert_eq!(20, val);
/// ```

use std::sync::{Condvar, Mutex};
use std::collections::HashMap;
use std::any::Any;
use std::mem;
use std::hash::Hash;

pub type Value = Box<Any + 'static + Send>;
pub type Events<T> = HashMap<T, Value>;

struct EventData<T> {
    events: Events<T>,
    ignore: Events<T>,
}

pub struct EventBox<T> {
    mutex: Mutex<EventData<T>>,
    cond: Condvar,
}

impl<T: Hash + Eq + Copy> EventBox<T> {
    pub fn new() -> Self {
        EventBox {
            mutex: Mutex::new(EventData{events: HashMap::new(), ignore: HashMap::new()}),
            cond: Condvar::new(),
        }
    }

    /// wait: wait for an event(any) to fire
    /// if any event is triggered, run callback on events vector
    pub fn wait(&self) -> Events<T> {
        let mut data = self.mutex.lock().unwrap();
        let events = mem::replace(&mut data.events, HashMap::new());
        let num_of_events = events.len();
        if num_of_events == 0 {
            let _ = self.cond.wait(data);
            let mut data = self.mutex.lock().unwrap();
            mem::replace(&mut data.events, HashMap::new())
        } else {
            events
        }
    }

    /// set: fires an event
    pub fn set(&self, e: T, value: Value) {
        let mut data = self.mutex.lock().unwrap();
        {
            let val = data.events.entry(e).or_insert(Box::new(0));
            *val = value;
        }
        if !data.ignore.contains_key(&e) {
            self.cond.notify_all();
        }
    }

    /// clear the event map
    pub fn clear(&self) {
        let mut data = self.mutex.lock().unwrap();
        data.events.clear();
    }

    // peek at the event box to check whether event had been set or not
    pub fn peek(&self, event: T) -> bool {
        let data = self.mutex.lock().unwrap();
        data.events.contains_key(&event)
    }

    // remove events from ignore table
    pub fn watch(&self, events: &Vec<T>) {
        let mut data = self.mutex.lock().unwrap();
        for e in events {
            data.ignore.remove(e);
        }
    }

    // add events from ignore table
    pub fn unwatch(&self, events: &Vec<T>) {
        let mut data = self.mutex.lock().unwrap();
        for e in events {
            data.ignore.insert(*e, Box::new(true));
        }
    }

    pub fn wait_for(&self, event: T) -> Value {
        'event_found: loop {
            for (e, val) in self.wait() {
                if e == event {
                    return val
                }
            }
        }
    }

    pub fn is_empty(&self) -> bool {
        let data = self.mutex.lock().unwrap();
        data.events.len() == 0
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::thread;
    use std::sync::{Arc, Mutex};
    use std::time::Duration;

    #[test]
    fn test_wait() {
        const NUM_OF_EVENTS: i32 = 4;

        // create `NUM_OF_EVENTS` threads that set the return value to
        // their thread number, the sum up the value and compare it in
        // the main thread.

        let eb = Arc::new(EventBox::new());
        let counter = Arc::new(Mutex::new(0));
        for i in 1..(NUM_OF_EVENTS+1) {
            let eb_clone = eb.clone();
            let counter_clone = counter.clone();
            thread::spawn(move || {
                eb_clone.set(i, Box::new(i));
                let mut count = counter_clone.lock().unwrap();
                *count += 1;
            });
        }

        // wait till all events are set
        loop {
            thread::sleep(Duration::from_millis(100));
            let count = counter.lock().unwrap();
            if *count == NUM_OF_EVENTS {
                break;
            }
        }

        let mut total: i32 = 0;
        for (_, val) in eb.wait() {
            total += *val.downcast().unwrap();
        }

        assert_eq!((1..(NUM_OF_EVENTS+1)).fold(0, |x, acc| acc+x), total);
    }

    #[test]
    fn test_wait_for() {
        let eb = Arc::new(EventBox::new());
        let eb2 = eb.clone();

        thread::spawn(move || {
            eb2.set(10, Box::new(20));
        });

        let val: i32 = *eb.wait_for(10).downcast().unwrap();
        assert_eq!(20, val);
    }

    #[test]
    fn test_unwatch_set() {
        const NUM_OF_EVENTS: i32 = 4;
        let eb = Arc::new(EventBox::new());

        // this time, we ignore event NO. NUM_OF_EVENTS
        // note that unwatch will not trigger the event notification, but the
        // value are actually set.
        eb.unwatch(&vec![NUM_OF_EVENTS]);

        let counter = Arc::new(Mutex::new(0));
        for i in 1..(NUM_OF_EVENTS+1) {
            let eb_clone = eb.clone();
            let counter_clone = counter.clone();
            thread::spawn(move || {
                eb_clone.set(i, Box::new(i));
                let mut count = counter_clone.lock().unwrap();
                *count += 1;
            });
        }

        // wait till all events are set
        loop {
            thread::sleep(Duration::from_millis(100));
            let count = counter.lock().unwrap();
            if *count == NUM_OF_EVENTS {
                break;
            }
        }

        let mut total: i32 = 0;
        for (_, val) in eb.wait() {
            total += *val.downcast().unwrap();
        }

        assert_eq!((1..(NUM_OF_EVENTS+1)).fold(0, |x, acc| acc+x), total);
    }

    #[test]
    fn test_unwatch_notify() {
        // unwatched event will not trigger notification

        let eb = Arc::new(EventBox::new());

        eb.unwatch(&vec![1]);

        let eb_clone1 = eb.clone();

        let which_one = Arc::new(Mutex::new(1));
        let which_one_clone = which_one.clone();

        let wait = thread::spawn(move || {
            for (_, _) in eb.wait() {
                let mut data = which_one.lock().unwrap();
                assert_eq!(2, *data);
            }
        });

        thread::spawn(move || {
            eb_clone1.set(1, Box::new(1));

            // to ensure that the `wait` in main thread have time to trigger.
            // of course, the expected behavior is that it will not.
            thread::sleep(Duration::from_millis(100));

            let mut data = which_one_clone.lock().unwrap();
            *data = 2;
            eb_clone1.set(2, Box::new(2));
        });

        wait.join();
    }
}
<|endoftext|>