<commit_before>//! Completion for associated items in a trait implementation.
//!
//! This module adds the completion items related to implementing associated
//! items within a `impl Trait for Struct` block. The current context node
//! must be within either a `FN`, `TYPE_ALIAS`, or `CONST` node
//! and an direct child of an `IMPL`.
//!
//! # Examples
//!
//! Considering the following trait `impl`:
//!
//! ```ignore
//! trait SomeTrait {
//!     fn foo();
//! }
//!
//! impl SomeTrait for () {
//!     fn f<|>
//! }
//! ```
//!
//! may result in the completion of the following method:
//!
//! ```ignore
//! # trait SomeTrait {
//! #    fn foo();
//! # }
//!
//! impl SomeTrait for () {
//!     fn foo() {}<|>
//! }
//! ```

use assists::utils::get_missing_assoc_items;
use hir::{self, Docs, HasSource};
use syntax::{
    ast::{self, edit, Impl},
    AstNode, SyntaxKind, SyntaxNode, TextRange, T,
};
use text_edit::TextEdit;

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

pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
    if let Some((trigger, impl_def)) = completion_match(ctx) {
        match trigger.kind() {
            SyntaxKind::NAME_REF => get_missing_assoc_items(&ctx.sema, &impl_def)
                .into_iter()
                .for_each(|item| match item {
                    hir::AssocItem::Function(fn_item) => {
                        add_function_impl(&trigger, acc, ctx, fn_item)
                    }
                    hir::AssocItem::TypeAlias(type_item) => {
                        add_type_alias_impl(&trigger, acc, ctx, type_item)
                    }
                    hir::AssocItem::Const(const_item) => {
                        add_const_impl(&trigger, acc, ctx, const_item)
                    }
                }),

            SyntaxKind::FN => {
                for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def)
                    .into_iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::Function(fn_item) => Some(fn_item),
                        _ => None,
                    })
                {
                    add_function_impl(&trigger, acc, ctx, missing_fn);
                }
            }

            SyntaxKind::TYPE_ALIAS => {
                for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def)
                    .into_iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::TypeAlias(type_item) => Some(type_item),
                        _ => None,
                    })
                {
                    add_type_alias_impl(&trigger, acc, ctx, missing_fn);
                }
            }

            SyntaxKind::CONST => {
                for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def)
                    .into_iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::Const(const_item) => Some(const_item),
                        _ => None,
                    })
                {
                    add_const_impl(&trigger, acc, ctx, missing_fn);
                }
            }

            _ => {}
        }
    }
}

fn completion_match(ctx: &CompletionContext) -> Option<(SyntaxNode, Impl)> {
    let (trigger, impl_def_offset) = ctx.token.ancestors().find_map(|p| match p.kind() {
        SyntaxKind::FN | SyntaxKind::TYPE_ALIAS | SyntaxKind::CONST | SyntaxKind::BLOCK_EXPR => {
            Some((p, 2))
        }
        SyntaxKind::NAME_REF => Some((p, 5)),
        _ => None,
    })?;
    let impl_def = (0..impl_def_offset - 1)
        .try_fold(trigger.parent()?, |t, _| t.parent())
        .and_then(ast::Impl::cast)?;
    Some((trigger, impl_def))
}

fn add_function_impl(
    fn_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    func: hir::Function,
) {
    let fn_name = func.name(ctx.db).to_string();

    let label = if !func.params(ctx.db).is_empty() {
        format!("fn {}(..)", fn_name)
    } else {
        format!("fn {}()", fn_name)
    };

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

    let completion_kind = if func.has_self_param(ctx.db) {
        CompletionItemKind::Method
    } else {
        CompletionItemKind::Function
    };
    let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end());

    let function_decl = function_declaration(&func.source(ctx.db).value);
    match ctx.config.snippet_cap {
        Some(cap) => {
            let snippet = format!("{} {{\n    $0\n}}", function_decl);
            builder.snippet_edit(cap, TextEdit::replace(range, snippet))
        }
        None => {
            let header = format!("{} {{", function_decl);
            builder.text_edit(TextEdit::replace(range, header))
        }
    }
    .kind(completion_kind)
    .add_to(acc);
}

fn add_type_alias_impl(
    type_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    type_alias: hir::TypeAlias,
) {
    let alias_name = type_alias.name(ctx.db).to_string();

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

    let range = TextRange::new(type_def_node.text_range().start(), ctx.source_range().end());

    CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
        .text_edit(TextEdit::replace(range, snippet))
        .lookup_by(alias_name)
        .kind(CompletionItemKind::TypeAlias)
        .set_documentation(type_alias.docs(ctx.db))
        .add_to(acc);
}

fn add_const_impl(
    const_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    const_: hir::Const,
) {
    let const_name = const_.name(ctx.db).map(|n| n.to_string());

    if let Some(const_name) = const_name {
        let snippet = make_const_compl_syntax(&const_.source(ctx.db).value);

        let range = TextRange::new(const_def_node.text_range().start(), ctx.source_range().end());

        CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
            .text_edit(TextEdit::replace(range, snippet))
            .lookup_by(const_name)
            .kind(CompletionItemKind::Const)
            .set_documentation(const_.docs(ctx.db))
            .add_to(acc);
    }
}

fn make_const_compl_syntax(const_: &ast::Const) -> String {
    let const_ = edit::remove_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() == T![;] || s.kind() == T![=])
        .map_or(const_end, |f| f.text_range().start());

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

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

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

#[cfg(test)]
mod tests {
    use expect::{expect, Expect};

    use crate::completion::{
        test_utils::{check_edit, completion_list},
        CompletionKind,
    };

    fn check(ra_fixture: &str, expect: Expect) {
        let actual = completion_list(ra_fixture, CompletionKind::Magic);
        expect.assert_eq(&actual)
    }

    #[test]
    fn name_ref_function_type_const() {
        check(
            r#"
trait Test {
    type TestType;
    const TEST_CONST: u16;
    fn test();
}
struct T;

impl Test for T {
    t<|>
}
"#,
            expect![["
ct const TEST_CONST: u16 = \n\
fn fn test()
ta type TestType = \n\
            "]],
        );
    }

    #[test]
    fn no_nested_fn_completions() {
        check(
            r"
trait Test {
    fn test();
    fn test2();
}
struct T;

impl Test for T {
    fn test() {
        t<|>
    }
}
",
            expect![[""]],
        );
    }

    #[test]
    fn name_ref_single_function() {
        check_edit(
            "test",
            r#"
trait Test {
    fn test();
}
struct T;

impl Test for T {
    t<|>
}
"#,
            r#"
trait Test {
    fn test();
}
struct T;

impl Test for T {
    fn test() {
    $0
}
}
"#,
        );
    }

    #[test]
    fn single_function() {
        check_edit(
            "test",
            r#"
trait Test {
    fn test();
}
struct T;

impl Test for T {
    fn t<|>
}
"#,
            r#"
trait Test {
    fn test();
}
struct T;

impl Test for T {
    fn test() {
    $0
}
}
"#,
        );
    }

    #[test]
    fn hide_implemented_fn() {
        check(
            r#"
trait Test {
    fn foo();
    fn foo_bar();
}
struct T;

impl Test for T {
    fn foo() {}
    fn f<|>
}
"#,
            expect![[r#"
                fn fn foo_bar()
            "#]],
        );
    }

    #[test]
    fn generic_fn() {
        check_edit(
            "foo",
            r#"
trait Test {
    fn foo<T>();
}
struct T;

impl Test for T {
    fn f<|>
}
"#,
            r#"
trait Test {
    fn foo<T>();
}
struct T;

impl Test for T {
    fn foo<T>() {
    $0
}
}
"#,
        );
        check_edit(
            "foo",
            r#"
trait Test {
    fn foo<T>() where T: Into<String>;
}
struct T;

impl Test for T {
    fn f<|>
}
"#,
            r#"
trait Test {
    fn foo<T>() where T: Into<String>;
}
struct T;

impl Test for T {
    fn foo<T>()
where T: Into<String> {
    $0
}
}
"#,
        );
    }

    #[test]
    fn associated_type() {
        check_edit(
            "SomeType",
            r#"
trait Test {
    type SomeType;
}

impl Test for () {
    type S<|>
}
"#,
            "
trait Test {
    type SomeType;
}

impl Test for () {
    type SomeType = \n\
}
",
        );
    }

    #[test]
    fn associated_const() {
        check_edit(
            "SOME_CONST",
            r#"
trait Test {
    const SOME_CONST: u16;
}

impl Test for () {
    const S<|>
}
"#,
            "
trait Test {
    const SOME_CONST: u16;
}

impl Test for () {
    const SOME_CONST: u16 = \n\
}
",
        );

        check_edit(
            "SOME_CONST",
            r#"
trait Test {
    const SOME_CONST: u16 = 92;
}

impl Test for () {
    const S<|>
}
"#,
            "
trait Test {
    const SOME_CONST: u16 = 92;
}

impl Test for () {
    const SOME_CONST: u16 = \n\
}
",
        );
    }
}
<commit_msg>Minor<commit_after>//! Completion for associated items in a trait implementation.
//!
//! This module adds the completion items related to implementing associated
//! items within a `impl Trait for Struct` block. The current context node
//! must be within either a `FN`, `TYPE_ALIAS`, or `CONST` node
//! and an direct child of an `IMPL`.
//!
//! # Examples
//!
//! Considering the following trait `impl`:
//!
//! ```ignore
//! trait SomeTrait {
//!     fn foo();
//! }
//!
//! impl SomeTrait for () {
//!     fn f<|>
//! }
//! ```
//!
//! may result in the completion of the following method:
//!
//! ```ignore
//! # trait SomeTrait {
//! #    fn foo();
//! # }
//!
//! impl SomeTrait for () {
//!     fn foo() {}<|>
//! }
//! ```

use assists::utils::get_missing_assoc_items;
use hir::{self, Docs, HasSource};
use syntax::{
    ast::{self, edit, Impl},
    AstNode, SyntaxKind, SyntaxNode, TextRange, T,
};
use text_edit::TextEdit;

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

pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
    if let Some((trigger, impl_def)) = completion_match(ctx) {
        match trigger.kind() {
            SyntaxKind::NAME_REF => get_missing_assoc_items(&ctx.sema, &impl_def)
                .into_iter()
                .for_each(|item| match item {
                    hir::AssocItem::Function(fn_item) => {
                        add_function_impl(&trigger, acc, ctx, fn_item)
                    }
                    hir::AssocItem::TypeAlias(type_item) => {
                        add_type_alias_impl(&trigger, acc, ctx, type_item)
                    }
                    hir::AssocItem::Const(const_item) => {
                        add_const_impl(&trigger, acc, ctx, const_item)
                    }
                }),

            SyntaxKind::FN => {
                for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def)
                    .into_iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::Function(fn_item) => Some(fn_item),
                        _ => None,
                    })
                {
                    add_function_impl(&trigger, acc, ctx, missing_fn);
                }
            }

            SyntaxKind::TYPE_ALIAS => {
                for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def)
                    .into_iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::TypeAlias(type_item) => Some(type_item),
                        _ => None,
                    })
                {
                    add_type_alias_impl(&trigger, acc, ctx, missing_fn);
                }
            }

            SyntaxKind::CONST => {
                for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def)
                    .into_iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::Const(const_item) => Some(const_item),
                        _ => None,
                    })
                {
                    add_const_impl(&trigger, acc, ctx, missing_fn);
                }
            }

            _ => {}
        }
    }
}

fn completion_match(ctx: &CompletionContext) -> Option<(SyntaxNode, Impl)> {
    let (trigger, impl_def_offset) = ctx.token.ancestors().find_map(|p| match p.kind() {
        SyntaxKind::FN | SyntaxKind::TYPE_ALIAS | SyntaxKind::CONST | SyntaxKind::BLOCK_EXPR => {
            Some((p, 2))
        }
        SyntaxKind::NAME_REF => Some((p, 5)),
        _ => None,
    })?;
    let impl_def = (0..impl_def_offset - 1)
        .try_fold(trigger.parent()?, |t, _| t.parent())
        .and_then(ast::Impl::cast)?;
    Some((trigger, impl_def))
}

fn add_function_impl(
    fn_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    func: hir::Function,
) {
    let fn_name = func.name(ctx.db).to_string();

    let label = if func.params(ctx.db).is_empty() {
        format!("fn {}()", fn_name)
    } else {
        format!("fn {}(..)", fn_name)
    };

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

    let completion_kind = if func.has_self_param(ctx.db) {
        CompletionItemKind::Method
    } else {
        CompletionItemKind::Function
    };
    let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end());

    let function_decl = function_declaration(&func.source(ctx.db).value);
    match ctx.config.snippet_cap {
        Some(cap) => {
            let snippet = format!("{} {{\n    $0\n}}", function_decl);
            builder.snippet_edit(cap, TextEdit::replace(range, snippet))
        }
        None => {
            let header = format!("{} {{", function_decl);
            builder.text_edit(TextEdit::replace(range, header))
        }
    }
    .kind(completion_kind)
    .add_to(acc);
}

fn add_type_alias_impl(
    type_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    type_alias: hir::TypeAlias,
) {
    let alias_name = type_alias.name(ctx.db).to_string();

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

    let range = TextRange::new(type_def_node.text_range().start(), ctx.source_range().end());

    CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
        .text_edit(TextEdit::replace(range, snippet))
        .lookup_by(alias_name)
        .kind(CompletionItemKind::TypeAlias)
        .set_documentation(type_alias.docs(ctx.db))
        .add_to(acc);
}

fn add_const_impl(
    const_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    const_: hir::Const,
) {
    let const_name = const_.name(ctx.db).map(|n| n.to_string());

    if let Some(const_name) = const_name {
        let snippet = make_const_compl_syntax(&const_.source(ctx.db).value);

        let range = TextRange::new(const_def_node.text_range().start(), ctx.source_range().end());

        CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
            .text_edit(TextEdit::replace(range, snippet))
            .lookup_by(const_name)
            .kind(CompletionItemKind::Const)
            .set_documentation(const_.docs(ctx.db))
            .add_to(acc);
    }
}

fn make_const_compl_syntax(const_: &ast::Const) -> String {
    let const_ = edit::remove_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() == T![;] || s.kind() == T![=])
        .map_or(const_end, |f| f.text_range().start());

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

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

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

#[cfg(test)]
mod tests {
    use expect::{expect, Expect};

    use crate::completion::{
        test_utils::{check_edit, completion_list},
        CompletionKind,
    };

    fn check(ra_fixture: &str, expect: Expect) {
        let actual = completion_list(ra_fixture, CompletionKind::Magic);
        expect.assert_eq(&actual)
    }

    #[test]
    fn name_ref_function_type_const() {
        check(
            r#"
trait Test {
    type TestType;
    const TEST_CONST: u16;
    fn test();
}
struct T;

impl Test for T {
    t<|>
}
"#,
            expect![["
ct const TEST_CONST: u16 = \n\
fn fn test()
ta type TestType = \n\
            "]],
        );
    }

    #[test]
    fn no_nested_fn_completions() {
        check(
            r"
trait Test {
    fn test();
    fn test2();
}
struct T;

impl Test for T {
    fn test() {
        t<|>
    }
}
",
            expect![[""]],
        );
    }

    #[test]
    fn name_ref_single_function() {
        check_edit(
            "test",
            r#"
trait Test {
    fn test();
}
struct T;

impl Test for T {
    t<|>
}
"#,
            r#"
trait Test {
    fn test();
}
struct T;

impl Test for T {
    fn test() {
    $0
}
}
"#,
        );
    }

    #[test]
    fn single_function() {
        check_edit(
            "test",
            r#"
trait Test {
    fn test();
}
struct T;

impl Test for T {
    fn t<|>
}
"#,
            r#"
trait Test {
    fn test();
}
struct T;

impl Test for T {
    fn test() {
    $0
}
}
"#,
        );
    }

    #[test]
    fn hide_implemented_fn() {
        check(
            r#"
trait Test {
    fn foo();
    fn foo_bar();
}
struct T;

impl Test for T {
    fn foo() {}
    fn f<|>
}
"#,
            expect![[r#"
                fn fn foo_bar()
            "#]],
        );
    }

    #[test]
    fn generic_fn() {
        check_edit(
            "foo",
            r#"
trait Test {
    fn foo<T>();
}
struct T;

impl Test for T {
    fn f<|>
}
"#,
            r#"
trait Test {
    fn foo<T>();
}
struct T;

impl Test for T {
    fn foo<T>() {
    $0
}
}
"#,
        );
        check_edit(
            "foo",
            r#"
trait Test {
    fn foo<T>() where T: Into<String>;
}
struct T;

impl Test for T {
    fn f<|>
}
"#,
            r#"
trait Test {
    fn foo<T>() where T: Into<String>;
}
struct T;

impl Test for T {
    fn foo<T>()
where T: Into<String> {
    $0
}
}
"#,
        );
    }

    #[test]
    fn associated_type() {
        check_edit(
            "SomeType",
            r#"
trait Test {
    type SomeType;
}

impl Test for () {
    type S<|>
}
"#,
            "
trait Test {
    type SomeType;
}

impl Test for () {
    type SomeType = \n\
}
",
        );
    }

    #[test]
    fn associated_const() {
        check_edit(
            "SOME_CONST",
            r#"
trait Test {
    const SOME_CONST: u16;
}

impl Test for () {
    const S<|>
}
"#,
            "
trait Test {
    const SOME_CONST: u16;
}

impl Test for () {
    const SOME_CONST: u16 = \n\
}
",
        );

        check_edit(
            "SOME_CONST",
            r#"
trait Test {
    const SOME_CONST: u16 = 92;
}

impl Test for () {
    const S<|>
}
"#,
            "
trait Test {
    const SOME_CONST: u16 = 92;
}

impl Test for () {
    const SOME_CONST: u16 = \n\
}
",
        );
    }
}
<|endoftext|>


<commit_before>/// External linking is a complex implementation to be able to serve a clean and easy-to-use
/// interface.
///
/// Internally, there are no such things as "external links" (plural). Each Entry in the store can
/// only have _one_ external link.
///
/// This library does the following therefor: It allows you to have several external links with one
/// entry, which are internally one file in the store for each link, linked with "internal
/// linking".
///
/// This helps us greatly with deduplication of URLs.
///

use std::convert::Into;
use std::ops::Deref;

use libimagstore::store::Entry;
use libimagstore::store::EntryHeader;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagstore::storeid::StoreId;

use error::LinkError as LE;
use error::LinkErrorKind as LEK;
use result::Result;
use internal::InternalLinker;

use toml::Value;
use toml::Table;
use url::Url;

/// "Link" Type, just an abstraction over FileLockEntry to have some convenience internally.
struct Link<'a> {
    link: FileLockEntry<'a>
}

impl<'a> Link<'a> {

    pub fn new(fle: FileLockEntry<'a>) -> Link<'a> {
        Link { link: fle }
    }

    /// For interal use only. Load an Link from a store id, if this is actually a Link
    fn retrieve(store: &'a Store, id: StoreId) -> Result<Option<Link<'a>>> {
        store.retrieve(id)
            .map(|fle| {
                if let Some(_) = Link::get_link_uri_from_filelockentry(&fle) {
                    Some(Link {
                        link: fle
                    })
                } else {
                    None
                }
            })
            .map_err(|e| LE::new(LEK::StoreReadError, Some(Box::new(e))))
    }

    /// Get a link Url object from a FileLockEntry, ignore errors.
    fn get_link_uri_from_filelockentry(file: &FileLockEntry<'a>) -> Option<Url> {
        file.deref()
            .get_header()
            .read("imag.content.uri")
            .ok()
            .and_then(|opt| {
                match opt {
                    Some(Value::String(s)) => Url::parse(&s[..]).ok(),
                    _ => None
                }
            })
    }

    pub fn get_url(&self) -> Result<Option<Url>> {
        let opt = self.link
            .deref()
            .get_header()
            .read("imag.content.uri");

        match opt {
            Ok(Some(Value::String(s))) => {
                Url::parse(&s[..])
                     .map(|s| Some(s))
                     .map_err(|e| LE::new(LEK::EntryHeaderReadError, Some(Box::new(e))))
            },
            Ok(None) => Ok(None),
            _ => Err(LE::new(LEK::EntryHeaderReadError, None))
        }
    }

}

pub trait ExternalLinker : InternalLinker {

    /// Get the external links from the implementor object
    fn get_external_links(&self) -> Result<Vec<Url>>;

    /// Set the external links for the implementor object
    fn set_external_links(&mut self, links: Vec<Url>) -> Result<Vec<Url>>;

    /// Add an external link to the implementor object
    fn add_external_link(&mut self, link: Url) -> Result<()>;

    /// Remove an external link from the implementor object
    fn remove_external_link(&mut self, link: Url) -> Result<()>;

}

/// Implement ExternalLinker for Entry, hiding the fact that there is no such thing as an external
/// link in an entry, but internal links to other entries which serve as external links, as one
/// entry in the store can only have one external link.
impl ExternalLinker for Entry {

    /// Get the external links from the implementor object
    fn get_external_links(&self) -> Result<Vec<Url>> {
        // Iterate through all internal links and filter for FileLockEntries which live in
        // /link/external/<SHA> -> load these files and get the external link from their headers,
        // put them into the return vector.
        unimplemented!()
    }

    /// Set the external links for the implementor object
    fn set_external_links(&mut self, links: Vec<Url>) -> Result<Vec<Url>> {
        // Take all the links, generate a SHA sum out of each one, filter out the already existing
        // store entries and store the other URIs in the header of one FileLockEntry each, in
        // the path /link/external/<SHA of the URL>
        unimplemented!()
    }

    /// Add an external link to the implementor object
    fn add_external_link(&mut self, link: Url) -> Result<()> {
        // get external links, add this one, save them
        unimplemented!()
    }

    /// Remove an external link from the implementor object
    fn remove_external_link(&mut self, link: Url) -> Result<()> {
        // get external links, remove this one, save them
        unimplemented!()
    }

}

<commit_msg>Implement get_external_links()<commit_after>/// External linking is a complex implementation to be able to serve a clean and easy-to-use
/// interface.
///
/// Internally, there are no such things as "external links" (plural). Each Entry in the store can
/// only have _one_ external link.
///
/// This library does the following therefor: It allows you to have several external links with one
/// entry, which are internally one file in the store for each link, linked with "internal
/// linking".
///
/// This helps us greatly with deduplication of URLs.
///

use std::convert::Into;
use std::ops::Deref;

use libimagstore::store::Entry;
use libimagstore::store::EntryHeader;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagstore::storeid::StoreId;

use error::LinkError as LE;
use error::LinkErrorKind as LEK;
use result::Result;
use internal::InternalLinker;

use toml::Value;
use toml::Table;
use url::Url;

/// "Link" Type, just an abstraction over FileLockEntry to have some convenience internally.
struct Link<'a> {
    link: FileLockEntry<'a>
}

impl<'a> Link<'a> {

    pub fn new(fle: FileLockEntry<'a>) -> Link<'a> {
        Link { link: fle }
    }

    /// For interal use only. Load an Link from a store id, if this is actually a Link
    fn retrieve(store: &'a Store, id: StoreId) -> Result<Option<Link<'a>>> {
        store.retrieve(id)
            .map(|fle| {
                if let Some(_) = Link::get_link_uri_from_filelockentry(&fle) {
                    Some(Link {
                        link: fle
                    })
                } else {
                    None
                }
            })
            .map_err(|e| LE::new(LEK::StoreReadError, Some(Box::new(e))))
    }

    /// Get a link Url object from a FileLockEntry, ignore errors.
    fn get_link_uri_from_filelockentry(file: &FileLockEntry<'a>) -> Option<Url> {
        file.deref()
            .get_header()
            .read("imag.content.uri")
            .ok()
            .and_then(|opt| {
                match opt {
                    Some(Value::String(s)) => Url::parse(&s[..]).ok(),
                    _ => None
                }
            })
    }

    pub fn get_url(&self) -> Result<Option<Url>> {
        let opt = self.link
            .deref()
            .get_header()
            .read("imag.content.uri");

        match opt {
            Ok(Some(Value::String(s))) => {
                Url::parse(&s[..])
                     .map(|s| Some(s))
                     .map_err(|e| LE::new(LEK::EntryHeaderReadError, Some(Box::new(e))))
            },
            Ok(None) => Ok(None),
            _ => Err(LE::new(LEK::EntryHeaderReadError, None))
        }
    }

}

pub trait ExternalLinker : InternalLinker {

    /// Get the external links from the implementor object
    fn get_external_links(&self, store: &Store) -> Result<Vec<Url>>;

    /// Set the external links for the implementor object
    fn set_external_links(&mut self, links: Vec<Url>) -> Result<Vec<Url>>;

    /// Add an external link to the implementor object
    fn add_external_link(&mut self, link: Url) -> Result<()>;

    /// Remove an external link from the implementor object
    fn remove_external_link(&mut self, link: Url) -> Result<()>;

}

/// Check whether the StoreId starts with `/link/external/`
fn is_link_store_id(id: &StoreId) -> bool {
    id.starts_with("/link/external/")
}

fn get_external_link_from_file(entry: &FileLockEntry) -> Result<Url> {
    Link::get_link_uri_from_filelockentry(entry) // TODO: Do not hide error by using this function
        .ok_or(LE::new(LEK::StoreReadError, None))
}

/// Implement ExternalLinker for Entry, hiding the fact that there is no such thing as an external
/// link in an entry, but internal links to other entries which serve as external links, as one
/// entry in the store can only have one external link.
impl ExternalLinker for Entry {

    /// Get the external links from the implementor object
    fn get_external_links(&self, store: &Store) -> Result<Vec<Url>> {
        // Iterate through all internal links and filter for FileLockEntries which live in
        // /link/external/<SHA> -> load these files and get the external link from their headers,
        // put them into the return vector.
        self.get_internal_links()
            .map(|vect| {
                vect.into_iter()
                    .filter(is_link_store_id)
                    .map(|id| {
                        match store.retrieve(id) {
                            Ok(f) => get_external_link_from_file(&f),
                            Err(e) => Err(LE::new(LEK::StoreReadError, Some(Box::new(e)))),
                        }
                    })
                    .filter_map(|x| x.ok()) // TODO: Do not ignore error here
                    .collect()
            })
            .map_err(|e| LE::new(LEK::StoreReadError, Some(Box::new(e))))
    }

    /// Set the external links for the implementor object
    fn set_external_links(&mut self, links: Vec<Url>) -> Result<Vec<Url>> {
        // Take all the links, generate a SHA sum out of each one, filter out the already existing
        // store entries and store the other URIs in the header of one FileLockEntry each, in
        // the path /link/external/<SHA of the URL>
        unimplemented!()
    }

    /// Add an external link to the implementor object
    fn add_external_link(&mut self, link: Url) -> Result<()> {
        // get external links, add this one, save them
        unimplemented!()
    }

    /// Remove an external link from the implementor object
    fn remove_external_link(&mut self, link: Url) -> Result<()> {
        // get external links, remove this one, save them
        unimplemented!()
    }

}

<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::path::Path;
use std::borrow::Borrow;
use std::ops::Deref;

use semver::Version;
use std::fmt::{Display, Debug, Formatter};
use std::fmt::Error as FmtError;
use std::result::Result as RResult;

use error::StoreErrorKind as SEK;
use store::Result;
use store::Store;

/// The Index into the Store
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
pub struct StoreId {
    store_location: PathBuf,
    id: PathBuf,
}

impl StoreId {

    pub fn storified(self, store: &Store) -> StoreId {
        if self.starts_with(store.path()) {
            debug!("Not storifying {:?}, because it is already.", self);
            self
        } else {
            debug!("Create new store id out of: {:?} and {:?}", store.path(), self);
            let mut new_id = store.path().clone();
            new_id.push(self);
            debug!("Created: '{:?}'", new_id);
            StoreId::from(new_id)
        }
    }

}

impl Into<PathBuf> for StoreId {

    fn into(self) -> PathBuf {
        self.0
    }

}

impl Display for StoreId {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        match self.0.to_str() {
            Some(s) => write!(fmt, "{}", s),
            None    => write!(fmt, "{}", self.0.to_string_lossy()),
        }
    }

}

impl Deref for StoreId {
    type Target = PathBuf;

    fn deref(&self) -> &PathBuf {
        &self.0
    }

}

impl From<PathBuf> for StoreId {

    fn from(pb: PathBuf) -> StoreId {
        StoreId(pb)
    }

}

impl From<String> for StoreId {

    fn from(string: String) -> StoreId {
        StoreId(string.into())
    }

}

impl AsRef<Path> for StoreId {

    fn as_ref(&self) -> &Path {
        self.0.as_ref()
    }

}

impl Borrow<Path> for StoreId {

    fn borrow(&self) -> &Path {
        self.0.borrow()
    }

}

/// This Trait allows you to convert various representations to a single one
/// suitable for usage in the Store
pub trait IntoStoreId {
    fn into_storeid(self) -> StoreId;
}

impl IntoStoreId for PathBuf {
    fn into_storeid(self) -> StoreId {
        StoreId(self)
    }
}

impl IntoStoreId for StoreId {
    fn into_storeid(self) -> StoreId {
        self
    }
}

pub fn build_entry_path(store: &Store, path_elem: &str) -> Result<PathBuf> {
    debug!("Checking path element for version");
    if path_elem.split('~').last().map_or(false, |v| Version::parse(v).is_err()) {
        debug!("Version cannot be parsed from {:?}", path_elem);
        debug!("Path does not contain version!");
        return Err(SEK::StorePathLacksVersion.into());
    }
    debug!("Version checking succeeded");

    debug!("Building path from {:?}", path_elem);
    let mut path = store.path().clone();

    if path_elem.starts_with('/') {
        path.push(&path_elem[1..]);
    } else {
        path.push(path_elem);
    }

    Ok(path)
}

#[macro_export]
macro_rules! module_entry_path_mod {
    ($name:expr, $version:expr) => (
        #[deny(missing_docs,
                missing_copy_implementations,
                trivial_casts, trivial_numeric_casts,
                unsafe_code,
                unstable_features,
                unused_import_braces, unused_qualifications,
                unused_imports)]
        /// A helper module to create valid module entry paths
        pub mod module_path {
            use semver::Version;
            use std::convert::AsRef;
            use std::path::Path;
            use std::path::PathBuf;

            use $crate::storeid::StoreId;

            /// A Struct giving you the ability to choose store entries assigned
            /// to it.
            ///
            /// It is created through a call to `new`.
            pub struct ModuleEntryPath(PathBuf);

            impl ModuleEntryPath {
                /// Path has to be a valid UTF-8 string or this will panic!
                pub fn new<P: AsRef<Path>>(pa: P) -> ModuleEntryPath {
                    let mut path = PathBuf::new();
                    path.push(format!("{}", $name));
                    path.push(pa.as_ref().clone());
                    let version = Version::parse($version).unwrap();
                    let name = pa.as_ref().file_name().unwrap()
                        .to_str().unwrap();
                    path.set_file_name(format!("{}~{}",
                                               name,
                                               version));
                    ModuleEntryPath(path)
                }
            }

            impl $crate::storeid::IntoStoreId for ModuleEntryPath {
                fn into_storeid(self) -> $crate::storeid::StoreId {
                    StoreId::from(self.0)
                }
            }
        }
    )
}

pub struct StoreIdIterator {
    iter: Box<Iterator<Item = StoreId>>,
}

impl Debug for StoreIdIterator {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "StoreIdIterator")
    }

}

impl StoreIdIterator {

    pub fn new(iter: Box<Iterator<Item = StoreId>>) -> StoreIdIterator {
        StoreIdIterator {
            iter: iter,
        }
    }

}

impl Iterator for StoreIdIterator {
    type Item = StoreId;

    fn next(&mut self) -> Option<StoreId> {
        self.iter.next()
    }

}

#[cfg(test)]
mod test {

    use storeid::IntoStoreId;

    module_entry_path_mod!("test", "0.2.0-alpha+leet1337");

    #[test]
    fn correct_path() {
        let p = module_path::ModuleEntryPath::new("test");

        assert_eq!(p.into_storeid().to_str().unwrap(), "test/test~0.2.0-alpha+leet1337");
    }

}
<commit_msg>Rewrite StoreId::storified()<commit_after>use std::path::PathBuf;
use std::path::Path;
use std::borrow::Borrow;
use std::ops::Deref;

use semver::Version;
use std::fmt::{Display, Debug, Formatter};
use std::fmt::Error as FmtError;
use std::result::Result as RResult;

use error::StoreErrorKind as SEK;
use store::Result;
use store::Store;

/// The Index into the Store
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
pub struct StoreId {
    store_location: PathBuf,
    id: PathBuf,
}

impl StoreId {

    pub fn storified(self, store: &Store) -> StoreId {
        if self.starts_with(store.path()) {
            debug!("Not storifying {:?}, because it is already.", self);
            self
        } else {
            debug!("Create new store id out of: {:?} and {:?}", store.path(), self.id);

            let new_id = StoreId { store_location: store.path().clone(), self.id };

            debug!("Created: '{:?}'", new_id);
            new_id
        }
    }

}

impl Into<PathBuf> for StoreId {

    fn into(self) -> PathBuf {
        self.0
    }

}

impl Display for StoreId {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        match self.0.to_str() {
            Some(s) => write!(fmt, "{}", s),
            None    => write!(fmt, "{}", self.0.to_string_lossy()),
        }
    }

}

impl Deref for StoreId {
    type Target = PathBuf;

    fn deref(&self) -> &PathBuf {
        &self.0
    }

}

impl From<PathBuf> for StoreId {

    fn from(pb: PathBuf) -> StoreId {
        StoreId(pb)
    }

}

impl From<String> for StoreId {

    fn from(string: String) -> StoreId {
        StoreId(string.into())
    }

}

impl AsRef<Path> for StoreId {

    fn as_ref(&self) -> &Path {
        self.0.as_ref()
    }

}

impl Borrow<Path> for StoreId {

    fn borrow(&self) -> &Path {
        self.0.borrow()
    }

}

/// This Trait allows you to convert various representations to a single one
/// suitable for usage in the Store
pub trait IntoStoreId {
    fn into_storeid(self) -> StoreId;
}

impl IntoStoreId for PathBuf {
    fn into_storeid(self) -> StoreId {
        StoreId(self)
    }
}

impl IntoStoreId for StoreId {
    fn into_storeid(self) -> StoreId {
        self
    }
}

pub fn build_entry_path(store: &Store, path_elem: &str) -> Result<PathBuf> {
    debug!("Checking path element for version");
    if path_elem.split('~').last().map_or(false, |v| Version::parse(v).is_err()) {
        debug!("Version cannot be parsed from {:?}", path_elem);
        debug!("Path does not contain version!");
        return Err(SEK::StorePathLacksVersion.into());
    }
    debug!("Version checking succeeded");

    debug!("Building path from {:?}", path_elem);
    let mut path = store.path().clone();

    if path_elem.starts_with('/') {
        path.push(&path_elem[1..]);
    } else {
        path.push(path_elem);
    }

    Ok(path)
}

#[macro_export]
macro_rules! module_entry_path_mod {
    ($name:expr, $version:expr) => (
        #[deny(missing_docs,
                missing_copy_implementations,
                trivial_casts, trivial_numeric_casts,
                unsafe_code,
                unstable_features,
                unused_import_braces, unused_qualifications,
                unused_imports)]
        /// A helper module to create valid module entry paths
        pub mod module_path {
            use semver::Version;
            use std::convert::AsRef;
            use std::path::Path;
            use std::path::PathBuf;

            use $crate::storeid::StoreId;

            /// A Struct giving you the ability to choose store entries assigned
            /// to it.
            ///
            /// It is created through a call to `new`.
            pub struct ModuleEntryPath(PathBuf);

            impl ModuleEntryPath {
                /// Path has to be a valid UTF-8 string or this will panic!
                pub fn new<P: AsRef<Path>>(pa: P) -> ModuleEntryPath {
                    let mut path = PathBuf::new();
                    path.push(format!("{}", $name));
                    path.push(pa.as_ref().clone());
                    let version = Version::parse($version).unwrap();
                    let name = pa.as_ref().file_name().unwrap()
                        .to_str().unwrap();
                    path.set_file_name(format!("{}~{}",
                                               name,
                                               version));
                    ModuleEntryPath(path)
                }
            }

            impl $crate::storeid::IntoStoreId for ModuleEntryPath {
                fn into_storeid(self) -> $crate::storeid::StoreId {
                    StoreId::from(self.0)
                }
            }
        }
    )
}

pub struct StoreIdIterator {
    iter: Box<Iterator<Item = StoreId>>,
}

impl Debug for StoreIdIterator {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "StoreIdIterator")
    }

}

impl StoreIdIterator {

    pub fn new(iter: Box<Iterator<Item = StoreId>>) -> StoreIdIterator {
        StoreIdIterator {
            iter: iter,
        }
    }

}

impl Iterator for StoreIdIterator {
    type Item = StoreId;

    fn next(&mut self) -> Option<StoreId> {
        self.iter.next()
    }

}

#[cfg(test)]
mod test {

    use storeid::IntoStoreId;

    module_entry_path_mod!("test", "0.2.0-alpha+leet1337");

    #[test]
    fn correct_path() {
        let p = module_path::ModuleEntryPath::new("test");

        assert_eq!(p.into_storeid().to_str().unwrap(), "test/test~0.2.0-alpha+leet1337");
    }

}
<|endoftext|>


<commit_before>//! Completion for associated items in a trait implementation.
//!
//! This module adds the completion items related to implementing associated
//! items within a `impl Trait for Struct` block. The current context node
//! must be within either a `FN_DEF`, `TYPE_ALIAS_DEF`, or `CONST_DEF` node
//! and an direct child of an `IMPL_DEF`.
//!
//! # Examples
//!
//! Considering the following trait `impl`:
//!
//! ```ignore
//! trait SomeTrait {
//!     fn foo();
//! }
//!
//! impl SomeTrait for () {
//!     fn f<|>
//! }
//! ```
//!
//! may result in the completion of the following method:
//!
//! ```ignore
//! # trait SomeTrait {
//! #    fn foo();
//! # }
//!
//! impl SomeTrait for () {
//!     fn foo() {}<|>
//! }
//! ```

use hir::{self, Docs, HasSource};
use ra_assists::utils::get_missing_assoc_items;
use ra_syntax::{
    ast::{self, edit, ImplDef},
    AstNode, SyntaxKind, SyntaxNode, TextRange, T,
};
use ra_text_edit::TextEdit;

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

pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
    if let Some((trigger, impl_def)) = completion_match(ctx) {
        match trigger.kind() {
            SyntaxKind::NAME_REF => get_missing_assoc_items(&ctx.sema, &impl_def)
                .into_iter()
                .for_each(|item| match item {
                    hir::AssocItem::Function(fn_item) => {
                        add_function_impl(&trigger, acc, ctx, fn_item)
                    }
                    hir::AssocItem::TypeAlias(type_item) => {
                        add_type_alias_impl(&trigger, acc, ctx, type_item)
                    }
                    hir::AssocItem::Const(const_item) => {
                        add_const_impl(&trigger, acc, ctx, const_item)
                    }
                }),

            SyntaxKind::FN_DEF => {
                for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def)
                    .into_iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::Function(fn_item) => Some(fn_item),
                        _ => None,
                    })
                {
                    add_function_impl(&trigger, acc, ctx, missing_fn);
                }
            }

            SyntaxKind::TYPE_ALIAS_DEF => {
                for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def)
                    .into_iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::TypeAlias(type_item) => Some(type_item),
                        _ => None,
                    })
                {
                    add_type_alias_impl(&trigger, acc, ctx, missing_fn);
                }
            }

            SyntaxKind::CONST_DEF => {
                for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def)
                    .into_iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::Const(const_item) => Some(const_item),
                        _ => None,
                    })
                {
                    add_const_impl(&trigger, acc, ctx, missing_fn);
                }
            }

            _ => {}
        }
    }
}

fn completion_match(ctx: &CompletionContext) -> Option<(SyntaxNode, ImplDef)> {
    let (trigger, impl_def_offset) = ctx.token.ancestors().find_map(|p| match p.kind() {
        SyntaxKind::FN_DEF
        | SyntaxKind::TYPE_ALIAS_DEF
        | SyntaxKind::CONST_DEF
        | SyntaxKind::BLOCK_EXPR => Some((p, 2)),
        SyntaxKind::NAME_REF => Some((p, 5)),
        _ => None,
    })?;
    let impl_def = (0..impl_def_offset - 1)
        .try_fold(trigger.parent()?, |t, _| t.parent())
        .and_then(ast::ImplDef::cast)?;
    Some((trigger, impl_def))
}

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

    let fn_name = func.name(ctx.db).to_string();

    let label = if !func.params(ctx.db).is_empty() {
        format!("fn {}(..)", fn_name)
    } else {
        format!("fn {}()", fn_name)
    };

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

    let completion_kind = if func.has_self_param(ctx.db) {
        CompletionItemKind::Method
    } else {
        CompletionItemKind::Function
    };
    let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end());

    match ctx.config.snippet_cap {
        Some(cap) => {
            let snippet = format!("{} {{\n    $0\n}}", signature);
            builder.snippet_edit(cap, TextEdit::replace(range, snippet))
        }
        None => {
            let header = format!("{} {{", signature);
            builder.text_edit(TextEdit::replace(range, header))
        }
    }
    .kind(completion_kind)
    .add_to(acc);
}

fn add_type_alias_impl(
    type_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    type_alias: hir::TypeAlias,
) {
    let alias_name = type_alias.name(ctx.db).to_string();

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

    let range = TextRange::new(type_def_node.text_range().start(), ctx.source_range().end());

    CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
        .text_edit(TextEdit::replace(range, snippet))
        .lookup_by(alias_name)
        .kind(CompletionItemKind::TypeAlias)
        .set_documentation(type_alias.docs(ctx.db))
        .add_to(acc);
}

fn add_const_impl(
    const_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    const_: hir::Const,
) {
    let const_name = const_.name(ctx.db).map(|n| n.to_string());

    if let Some(const_name) = const_name {
        let snippet = make_const_compl_syntax(&const_.source(ctx.db).value);

        let range = TextRange::new(const_def_node.text_range().start(), ctx.source_range().end());

        CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
            .text_edit(TextEdit::replace(range, snippet))
            .lookup_by(const_name)
            .kind(CompletionItemKind::Const)
            .set_documentation(const_.docs(ctx.db))
            .add_to(acc);
    }
}

fn make_const_compl_syntax(const_: &ast::ConstDef) -> String {
    let const_ = edit::remove_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() == T![;] || s.kind() == T![=])
        .map_or(const_end, |f| f.text_range().start());

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

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

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

#[cfg(test)]
mod tests {
    use insta::assert_debug_snapshot;

    use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind};

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

    #[test]
    fn name_ref_function_type_const() {
        let completions = complete(
            r"
            trait Test {
                type TestType;
                const TEST_CONST: u16;
                fn test();
            }

            struct T1;

            impl Test for T1 {
                t<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "const TEST_CONST: u16 = ",
                source_range: 112..113,
                delete: 112..113,
                insert: "const TEST_CONST: u16 = ",
                kind: Const,
                lookup: "TEST_CONST",
            },
            CompletionItem {
                label: "fn test()",
                source_range: 112..113,
                delete: 112..113,
                insert: "fn test() {\n    $0\n}",
                kind: Function,
                lookup: "test",
            },
            CompletionItem {
                label: "type TestType = ",
                source_range: 112..113,
                delete: 112..113,
                insert: "type TestType = ",
                kind: TypeAlias,
                lookup: "TestType",
            },
        ]
        "###);
    }

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

            struct T1;

            impl Test for T1 {
                fn test() {
                    t<|>
                }
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"[]"###);
    }

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

            struct T1;

            impl Test for T1 {
                t<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn test()",
                source_range: 66..67,
                delete: 66..67,
                insert: "fn test() {\n    $0\n}",
                kind: Function,
                lookup: "test",
            },
        ]
        "###);
    }

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

            struct T1;

            impl Test for T1 {
                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: 68..69,
                delete: 65..69,
                insert: "fn foo() {\n    $0\n}",
                kind: Function,
                lookup: "foo",
            },
        ]
        "###);
    }

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

            struct T1;

            impl Test for T1 {
                fn foo() {}

                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo_bar()",
                source_range: 103..104,
                delete: 100..104,
                insert: "fn foo_bar() {\n    $0\n}",
                kind: Function,
                lookup: "foo_bar",
            },
        ]
        "###);
    }

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

                fn foo_bar();
            }

            struct T1;

            impl Test for T1 {
                fn foo() {
                    <|>
                }
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"[]"###);
    }

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

            struct T1;

            impl Test for T1 {
                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: 71..72,
                delete: 68..72,
                insert: "fn foo<T>() {\n    $0\n}",
                kind: Function,
                lookup: "foo",
            },
        ]
        "###);
    }

    #[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 f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: 93..94,
                delete: 90..94,
                insert: "fn foo<T>()\nwhere T: Into<String> {\n    $0\n}",
                kind: Function,
                lookup: "foo",
            },
        ]
        "###);
    }

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

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

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

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

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

            impl Test for () {
                const S<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "const SOME_CONST: u16 = ",
                source_range: 77..78,
                delete: 71..78,
                insert: "const SOME_CONST: u16 = ",
                kind: Const,
                lookup: "SOME_CONST",
            },
        ]
        "###);
    }
}
<commit_msg>Modernise item completion tests<commit_after>//! Completion for associated items in a trait implementation.
//!
//! This module adds the completion items related to implementing associated
//! items within a `impl Trait for Struct` block. The current context node
//! must be within either a `FN_DEF`, `TYPE_ALIAS_DEF`, or `CONST_DEF` node
//! and an direct child of an `IMPL_DEF`.
//!
//! # Examples
//!
//! Considering the following trait `impl`:
//!
//! ```ignore
//! trait SomeTrait {
//!     fn foo();
//! }
//!
//! impl SomeTrait for () {
//!     fn f<|>
//! }
//! ```
//!
//! may result in the completion of the following method:
//!
//! ```ignore
//! # trait SomeTrait {
//! #    fn foo();
//! # }
//!
//! impl SomeTrait for () {
//!     fn foo() {}<|>
//! }
//! ```

use hir::{self, Docs, HasSource};
use ra_assists::utils::get_missing_assoc_items;
use ra_syntax::{
    ast::{self, edit, ImplDef},
    AstNode, SyntaxKind, SyntaxNode, TextRange, T,
};
use ra_text_edit::TextEdit;

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

pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
    if let Some((trigger, impl_def)) = completion_match(ctx) {
        match trigger.kind() {
            SyntaxKind::NAME_REF => get_missing_assoc_items(&ctx.sema, &impl_def)
                .into_iter()
                .for_each(|item| match item {
                    hir::AssocItem::Function(fn_item) => {
                        add_function_impl(&trigger, acc, ctx, fn_item)
                    }
                    hir::AssocItem::TypeAlias(type_item) => {
                        add_type_alias_impl(&trigger, acc, ctx, type_item)
                    }
                    hir::AssocItem::Const(const_item) => {
                        add_const_impl(&trigger, acc, ctx, const_item)
                    }
                }),

            SyntaxKind::FN_DEF => {
                for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def)
                    .into_iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::Function(fn_item) => Some(fn_item),
                        _ => None,
                    })
                {
                    add_function_impl(&trigger, acc, ctx, missing_fn);
                }
            }

            SyntaxKind::TYPE_ALIAS_DEF => {
                for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def)
                    .into_iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::TypeAlias(type_item) => Some(type_item),
                        _ => None,
                    })
                {
                    add_type_alias_impl(&trigger, acc, ctx, missing_fn);
                }
            }

            SyntaxKind::CONST_DEF => {
                for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def)
                    .into_iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::Const(const_item) => Some(const_item),
                        _ => None,
                    })
                {
                    add_const_impl(&trigger, acc, ctx, missing_fn);
                }
            }

            _ => {}
        }
    }
}

fn completion_match(ctx: &CompletionContext) -> Option<(SyntaxNode, ImplDef)> {
    let (trigger, impl_def_offset) = ctx.token.ancestors().find_map(|p| match p.kind() {
        SyntaxKind::FN_DEF
        | SyntaxKind::TYPE_ALIAS_DEF
        | SyntaxKind::CONST_DEF
        | SyntaxKind::BLOCK_EXPR => Some((p, 2)),
        SyntaxKind::NAME_REF => Some((p, 5)),
        _ => None,
    })?;
    let impl_def = (0..impl_def_offset - 1)
        .try_fold(trigger.parent()?, |t, _| t.parent())
        .and_then(ast::ImplDef::cast)?;
    Some((trigger, impl_def))
}

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

    let fn_name = func.name(ctx.db).to_string();

    let label = if !func.params(ctx.db).is_empty() {
        format!("fn {}(..)", fn_name)
    } else {
        format!("fn {}()", fn_name)
    };

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

    let completion_kind = if func.has_self_param(ctx.db) {
        CompletionItemKind::Method
    } else {
        CompletionItemKind::Function
    };
    let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end());

    match ctx.config.snippet_cap {
        Some(cap) => {
            let snippet = format!("{} {{\n    $0\n}}", signature);
            builder.snippet_edit(cap, TextEdit::replace(range, snippet))
        }
        None => {
            let header = format!("{} {{", signature);
            builder.text_edit(TextEdit::replace(range, header))
        }
    }
    .kind(completion_kind)
    .add_to(acc);
}

fn add_type_alias_impl(
    type_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    type_alias: hir::TypeAlias,
) {
    let alias_name = type_alias.name(ctx.db).to_string();

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

    let range = TextRange::new(type_def_node.text_range().start(), ctx.source_range().end());

    CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
        .text_edit(TextEdit::replace(range, snippet))
        .lookup_by(alias_name)
        .kind(CompletionItemKind::TypeAlias)
        .set_documentation(type_alias.docs(ctx.db))
        .add_to(acc);
}

fn add_const_impl(
    const_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    const_: hir::Const,
) {
    let const_name = const_.name(ctx.db).map(|n| n.to_string());

    if let Some(const_name) = const_name {
        let snippet = make_const_compl_syntax(&const_.source(ctx.db).value);

        let range = TextRange::new(const_def_node.text_range().start(), ctx.source_range().end());

        CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
            .text_edit(TextEdit::replace(range, snippet))
            .lookup_by(const_name)
            .kind(CompletionItemKind::Const)
            .set_documentation(const_.docs(ctx.db))
            .add_to(acc);
    }
}

fn make_const_compl_syntax(const_: &ast::ConstDef) -> String {
    let const_ = edit::remove_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() == T![;] || s.kind() == T![=])
        .map_or(const_end, |f| f.text_range().start());

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

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

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

#[cfg(test)]
mod tests {
    use expect::{expect, Expect};

    use crate::completion::{
        test_utils::{check_edit, completion_list},
        CompletionKind,
    };

    fn check(ra_fixture: &str, expect: Expect) {
        let actual = completion_list(ra_fixture, CompletionKind::Magic);
        expect.assert_eq(&actual)
    }

    #[test]
    fn name_ref_function_type_const() {
        check(
            r#"
trait Test {
    type TestType;
    const TEST_CONST: u16;
    fn test();
}
struct T;

impl Test for T {
    t<|>
}
"#,
            expect![["
ct const TEST_CONST: u16 = \n\
fn fn test()
ta type TestType = \n\
            "]],
        );
    }

    #[test]
    fn no_nested_fn_completions() {
        check(
            r"
trait Test {
    fn test();
    fn test2();
}
struct T;

impl Test for T {
    fn test() {
        t<|>
    }
}
",
            expect![[""]],
        );
    }

    #[test]
    fn name_ref_single_function() {
        check_edit(
            "test",
            r#"
trait Test {
    fn test();
}
struct T;

impl Test for T {
    t<|>
}
"#,
            r#"
trait Test {
    fn test();
}
struct T;

impl Test for T {
    fn test() {
    $0
}
}
"#,
        );
    }

    #[test]
    fn single_function() {
        check_edit(
            "test",
            r#"
trait Test {
    fn test();
}
struct T;

impl Test for T {
    fn t<|>
}
"#,
            r#"
trait Test {
    fn test();
}
struct T;

impl Test for T {
    fn test() {
    $0
}
}
"#,
        );
    }

    #[test]
    fn hide_implemented_fn() {
        check(
            r#"
trait Test {
    fn foo();
    fn foo_bar();
}
struct T;

impl Test for T {
    fn foo() {}
    fn f<|>
}
"#,
            expect![[r#"
                fn fn foo_bar()
            "#]],
        );
    }

    #[test]
    fn generic_fn() {
        check_edit(
            "foo",
            r#"
trait Test {
    fn foo<T>();
}
struct T;

impl Test for T {
    fn f<|>
}
"#,
            r#"
trait Test {
    fn foo<T>();
}
struct T;

impl Test for T {
    fn foo<T>() {
    $0
}
}
"#,
        );
        check_edit(
            "foo",
            r#"
trait Test {
    fn foo<T>() where T: Into<String>;
}
struct T;

impl Test for T {
    fn f<|>
}
"#,
            r#"
trait Test {
    fn foo<T>() where T: Into<String>;
}
struct T;

impl Test for T {
    fn foo<T>()
where T: Into<String> {
    $0
}
}
"#,
        );
    }

    #[test]
    fn associated_type() {
        check_edit(
            "SomeType",
            r#"
trait Test {
    type SomeType;
}

impl Test for () {
    type S<|>
}
"#,
            "
trait Test {
    type SomeType;
}

impl Test for () {
    type SomeType = \n\
}
",
        );
    }

    #[test]
    fn associated_const() {
        check_edit(
            "SOME_CONST",
            r#"
trait Test {
    const SOME_CONST: u16;
}

impl Test for () {
    const S<|>
}
"#,
            "
trait Test {
    const SOME_CONST: u16;
}

impl Test for () {
    const SOME_CONST: u16 = \n\
}
",
        );

        check_edit(
            "SOME_CONST",
            r#"
trait Test {
    const SOME_CONST: u16 = 92;
}

impl Test for () {
    const S<|>
}
"#,
            "
trait Test {
    const SOME_CONST: u16 = 92;
}

impl Test for () {
    const SOME_CONST: u16 = \n\
}
",
        );
    }
}
<|endoftext|>


<commit_before>use key::{Cmd, Key};
use editor::Editor;
use redraw::RedrawTask;
use mode::Mode;

#[cfg(feature = "orbital")]
use orbclient::{EventOption, Event};

#[derive(Copy, Clone)]
/// An instruction, i.e. a command and a numeral parameter
pub struct Inst(pub Parameter, pub Cmd);

/// A numeral parameter, i.e. a number (or nothing) given before a command (toghether making an
/// instruction)
#[derive(Copy, Clone)]
pub enum Parameter {
    /// An integer as parameter
    Int(usize),
    /// Not given (the user have not defined any numeral parameter to this command)
    Null,
}
impl Parameter {
    /// Either unwrap the Int(n) to n or fallback to a given value
    #[inline]
    pub fn or(self, fallback: usize) -> usize {
        if let Parameter::Int(n) = self {
            n
        } else {
            fallback
        }
    }
    /// Fallback to one (default)
    #[inline]
    pub fn d(self) -> usize {
        self.or(1)
    }
}

impl Editor {
    /// Get the next character input. Useful for commands taking a character as post-parameter,
    /// such as r (replace).
    pub fn get_char(&mut self) -> char {
        #[cfg(feature = "orbital")]
        loop {
            match self.window
                      .poll()
                      .unwrap_or(Event::new())
                      .to_option() {
                EventOption::Key(k) => {
                    if let Some(Key::Char(c)) = self.key_state.feed(k) {
                        self.status_bar.cmd.push(c);
                        self.redraw_task = RedrawTask::StatusBar;
                        return c;
                    }
                },
                _ => {},
            }
        }
    }

    /// Get the next instruction, i.e. the next input of a command together with a numeral
    /// parameter.
    pub fn get_inst(&mut self) -> Inst {
        let mut n = 0;
        let mut unset = true;

        let mut key = Key::Null;
        self.status_bar.cmd = String::new();

        // self.status_bar.cmd = String::new();
        #[cfg(feature = "orbital")]
        loop {
             match self.window.poll()
                       .unwrap_or(Event::new())
                       .to_option() {
                EventOption::Key(key_event) => {
                    if let Some(k) = self.key_state.feed(key_event) {
                        let c = k.to_char();
                        self.status_bar.cmd.push(c);
                        self.redraw_status_bar();

                        match self.cursor().mode {
                            Mode::Primitive(_) => {
                                key = k;
                            }
                            Mode::Command(_) => {
                                n = match c {
                                    '0' ... '9' => {
                                        unset = false;
                                        n * 10 + ((c as u8) - b'0') as usize
                                    }
                                    _ => {

                                        key = k;
                                        n
                                    }
                                };
                            }

                        }
                    }
                    match key {
                        Key::Null => {},
                        _ => {
                            return Inst(
                                if unset {
                                    Parameter::Null
                                } else {
                                    Parameter::Int(n)
                                },
                                Cmd { key: key }
                            );
                        },
                    }
                },
                EventOption::Quit(_) => {
                    return Inst(Parameter::Null, Cmd { key: Key::Quit });
                },
                _ => {},
            }
        }

    }
}
<commit_msg>Bring up to date! Yay, it runs on Linux<commit_after>use key::{Cmd, Key};
use editor::Editor;
use redraw::RedrawTask;
use mode::Mode;

#[cfg(feature = "orbital")]
use orbclient::{EventOption, Event};

#[derive(Copy, Clone)]
/// An instruction, i.e. a command and a numeral parameter
pub struct Inst(pub Parameter, pub Cmd);

/// A numeral parameter, i.e. a number (or nothing) given before a command (toghether making an
/// instruction)
#[derive(Copy, Clone)]
pub enum Parameter {
    /// An integer as parameter
    Int(usize),
    /// Not given (the user have not defined any numeral parameter to this command)
    Null,
}
impl Parameter {
    /// Either unwrap the Int(n) to n or fallback to a given value
    #[inline]
    pub fn or(self, fallback: usize) -> usize {
        if let Parameter::Int(n) = self {
            n
        } else {
            fallback
        }
    }
    /// Fallback to one (default)
    #[inline]
    pub fn d(self) -> usize {
        self.or(1)
    }
}

impl Editor {
    /// Get the next character input. Useful for commands taking a character as post-parameter,
    /// such as r (replace).
    pub fn get_char(&mut self) -> char {
        #[cfg(feature = "orbital")]
        loop {
            match self.window
                      .events().next()
                      .unwrap_or(Event::new())
                      .to_option() {
                EventOption::Key(k) => {
                    if let Some(Key::Char(c)) = self.key_state.feed(k) {
                        self.status_bar.cmd.push(c);
                        self.redraw_task = RedrawTask::StatusBar;
                        return c;
                    }
                },
                _ => {},
            }
        }
    }

    /// Get the next instruction, i.e. the next input of a command together with a numeral
    /// parameter.
    pub fn get_inst(&mut self) -> Inst {
        let mut n = 0;
        let mut unset = true;

        let mut key = Key::Null;
        self.status_bar.cmd = String::new();

        // self.status_bar.cmd = String::new();
        #[cfg(feature = "orbital")]
        loop {
             match self.window.events().next()
                       .unwrap_or(Event::new())
                       .to_option() {
                EventOption::Key(key_event) => {
                    if let Some(k) = self.key_state.feed(key_event) {
                        let c = k.to_char();
                        self.status_bar.cmd.push(c);
                        self.redraw_status_bar();

                        match self.cursor().mode {
                            Mode::Primitive(_) => {
                                key = k;
                            }
                            Mode::Command(_) => {
                                n = match c {
                                    '0' ... '9' => {
                                        unset = false;
                                        n * 10 + ((c as u8) - b'0') as usize
                                    }
                                    _ => {

                                        key = k;
                                        n
                                    }
                                };
                            }

                        }
                    }
                    match key {
                        Key::Null => {},
                        _ => {
                            return Inst(
                                if unset {
                                    Parameter::Null
                                } else {
                                    Parameter::Int(n)
                                },
                                Cmd { key: key }
                            );
                        },
                    }
                },
                EventOption::Quit(_) => {
                    return Inst(Parameter::Null, Cmd { key: Key::Quit });
                },
                _ => {},
            }
        }

    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// 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 frame module provides a structred way to send and receive
//! message through streams.
//!
//! ## Data Framing
//!
//! ```ignore
//! 0                   1                   2                   3
//! 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//! | Frame Start   |  Payload Len                  |  Payload  |
//! +-----------------------------------------------------------+
//! |           Payload Data Continued          |   Frame End   |
//! +-----------------------------------------------------------+
//!
//! Start Frame:    8 bits, must be 0x01
//! Payload Len:    16 bits
//! Payload Data:   (Payload Len) bytes
//! End Frame:      8 bits, must be 0x17
//! ```

use std::mem;

pub const START_BYTE:    u8 = 0x01;
pub const END_BYTE:      u8 = 0x17;

pub fn new(buf: &[u8]) -> Vec<u8> {
    let buf_len = buf.len() as u16;
    let mut ret_buf = Vec::<u8>::with_capacity(buf.len() + 4);

    ret_buf.push(START_BYTE);
    ret_buf.push((buf_len >> 8) as u8);
    ret_buf.push(buf_len as u8);
    ret_buf.extend_from_slice(buf);
    ret_buf.push(END_BYTE);

    ret_buf
}

pub fn from_raw_parts(buf: &mut Vec<u8>) -> Option<Vec<u8>> {
    if buf.len() < 5 {
        trace!("buf.len not large enough to process");
        return None;
    }

    if buf[0] != START_BYTE {
        trace!("buf[0] was not START_BYTE");
        let mut new_buf = Vec::<u8>::with_capacity(1024);
        mem::swap(&mut new_buf, buf);
        return None;
    }

    let mask = 0xFFFFu16;
    let mut payload_len = ((buf[1] as u16) << 8) & mask;
    payload_len |= buf[2] as u16;

    trace!("buf.len: {}", buf.len());
    trace!("Payload Len: {}", payload_len);

    let payload_len = payload_len as usize;
    if (buf.len() - 4) < payload_len {
        trace!("Not enough in buf for expected payload\nExpected: {}\nActual: {}",
               payload_len,
               (buf.len() - 4));
        return None;
    }

    if buf[payload_len] != END_BYTE {
        trace!("END_BYTE was not at expected location. Swapping for a fresh buffer");
        let mut new_buf = Vec::<u8>::with_capacity(1024);
        mem::swap(&mut new_buf, buf);
        return None;
    }

    let mut ret_buf = Vec::<u8>::with_capacity(payload_len);
    ret_buf.extend_from_slice(&buf[3..payload_len]);

    let buf_len = buf.len();
    let mut remaining_buf = Vec::<u8>::with_capacity(buf.len() - (payload_len + 4));
    remaining_buf.extend_from_slice(&buf[payload_len..buf_len]);
    mem::swap(buf, &mut remaining_buf);

    trace!("Complete frame read");

    Some(ret_buf)
}
<commit_msg>Off by 3 fix<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// 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 frame module provides a structred way to send and receive
//! message through streams.
//!
//! ## Data Framing
//!
//! ```ignore
//! 0                   1                   2                   3
//! 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//! | Frame Start   |  Payload Len                  |  Payload  |
//! +-----------------------------------------------------------+
//! |           Payload Data Continued          |   Frame End   |
//! +-----------------------------------------------------------+
//!
//! Start Frame:    8 bits, must be 0x01
//! Payload Len:    16 bits
//! Payload Data:   (Payload Len) bytes
//! End Frame:      8 bits, must be 0x17
//! ```

use std::mem;

pub const START_BYTE:    u8 = 0x01;
pub const END_BYTE:      u8 = 0x17;

pub fn new(buf: &[u8]) -> Vec<u8> {
    let buf_len = buf.len() as u16;
    let mut ret_buf = Vec::<u8>::with_capacity(buf.len() + 4);

    ret_buf.push(START_BYTE);
    ret_buf.push((buf_len >> 8) as u8);
    ret_buf.push(buf_len as u8);
    ret_buf.extend_from_slice(buf);
    ret_buf.push(END_BYTE);

    ret_buf
}

pub fn from_raw_parts(buf: &mut Vec<u8>) -> Option<Vec<u8>> {
    if buf.len() < 5 {
        trace!("buf.len not large enough to process");
        return None;
    }

    if buf[0] != START_BYTE {
        trace!("buf[0] was not START_BYTE");
        let mut new_buf = Vec::<u8>::with_capacity(1024);
        mem::swap(&mut new_buf, buf);
        return None;
    }

    let mask = 0xFFFFu16;
    let mut payload_len = ((buf[1] as u16) << 8) & mask;
    payload_len |= buf[2] as u16;

    trace!("buf.len: {}", buf.len());
    trace!("Payload Len: {}", payload_len);

    let payload_len = payload_len as usize;
    if (buf.len() - 4) < payload_len {
        trace!("Not enough in buf for expected payload\nExpected: {}\nActual: {}",
               payload_len,
               (buf.len() - 4));
        return None;
    }

    if buf[payload_len + 3] != END_BYTE {
        trace!("END_BYTE was not at expected location. Swapping for a fresh buffer");
        let mut new_buf = Vec::<u8>::with_capacity(1024);
        mem::swap(&mut new_buf, buf);
        return None;
    }

    let mut ret_buf = Vec::<u8>::with_capacity(payload_len);
    ret_buf.extend_from_slice(&buf[3..payload_len]);

    let buf_len = buf.len();
    let mut remaining_buf = Vec::<u8>::with_capacity(buf.len() - (payload_len + 4));
    remaining_buf.extend_from_slice(&buf[payload_len..buf_len]);
    mem::swap(buf, &mut remaining_buf);

    trace!("Complete frame read");

    Some(ret_buf)
}
<|endoftext|>


<commit_before>use codemap::File;
use codemap::Spanned;
use self::Token::*;
use std::iter::Enumerate;
use std::iter::Peekable;
use std::str::Chars;

type LexIter<'a> = Peekable<Enumerate<Chars<'a>>>;

#[derive(Debug, Clone, PartialEq)]
pub enum Token {
  // Structure
  EOF,
  Enter,
  Exit,
  Space,
  End,
  Comment(String),

  // Literals
  Null,
  Bool(bool),
  Float(f64),
  Int(i64),
  Str(String),
  Name(String),

  // Keywords
  Break,
  Catch,
  Continue,
  Else,
  For,
  Func,
  If,
  Import,
  In,
  Loop,
  Pass,
  Return,
  Save,
  Var,
  While,

  // Symbols
  Arr, // ->
  Ass, // =
  Col, // :
  Com, // ,
  Dot, // .
  Meta,// ::
  Semi,// ;

  // Braces
  Cul, // {
  Cur, // }
  Pal, // (
  Par, // )
  Sql, // [
  Sqr, // ]

  // Operators
  Add, // +
  And, // &
  At,  // @
  Car, // ^
  Div, // /
  Dol, // $
  Mul, // *
  Neg, // ~
  Not, // !
  Or,  // |
  Pct, // %
  Sub, // -

  // Comparisons
  Eql, // ==
  Ge,  // >=
  Gt,  // >
  Le,  // <=
  Lt,  // <
  Ne,  // !=
}

fn lex_number(it: &mut LexIter) -> Token {
  let mut digits = String::new();
  while let Some(&(_i, c)) = it.peek() {
    match c {
      '0'...'9' | '.' => {
        it.next();
        digits.push(c);
      }
      _ => {break}
    }
  }

  match digits.contains(".") {
    true => Float(digits.parse::<f64>().unwrap()),
    false => Int(digits.parse::<i64>().unwrap())
  }
}

fn lex_name(it: &mut LexIter) -> Token {
  let mut name = String::new();
  name.push(it.next().unwrap().1);

  while let Some(&(_i, c)) = it.peek() {
    match c {
      'a'...'z' | 'A'...'Z' | '0'...'9' | '_' => {
        it.next();
        name.push(c);
      }
      _ => {break}
    }
  }

  match name.as_str() {
    "true" => Bool(true),
    "false" => Bool(false),
    "null" => Null,

    "break" => Break,
    "catch" => Catch,
    "continue" => Continue,
    "else" => Else,
    "for" => For,
    "func" => Func,
    "if" => If,
    "import" => Import,
    "in" => In,
    "loop" => Loop,
    "pass" => Pass,
    "return" => Return,
    "save" => Save,
    "var" => Var,
    "while" => While,

    _ => Name(name)
  }
}

fn lex_comment(it: &mut LexIter) -> Token {
  let mut comment = String::new();
  it.next();

  while let Some(&(_i, c)) = it.peek() {
    match c {
      '\n' => {break}
      _ => {
        it.next();
        comment.push(c);
      }
    }
  }

  println!("Comment: {:?}", comment);
  Comment(comment)
}

fn lex_indent(it: &mut LexIter) -> u64 {
  let mut indent: u64 = 0;
  it.next();

  while let Some(&(_i, c)) = it.peek() {
    match c {
      ' ' => {
        it.next();
        indent += 1;
      }
      _ => {break}
    }
  }

  indent
}

fn lex_pair(next: char, solo: Token, pair: Token, it: &mut LexIter) -> Token {
  it.next();

  if let Some(&(_i, c)) = it.peek() {
    if c == next {
      it.next();
      return pair;
    }
  }

  // is this right? if peek() returns a None, we just return `solo`?
  // seems right. None should be the EOF, meaning `solo` is the last token
  solo
}

pub fn lex(input: &File) -> Vec<Spanned<Token>> {
  let mut tokens: Vec<Spanned<Token>> = Vec::new();
  let mut it: LexIter = input.source().chars().enumerate().peekable();
  let mut indent_stack: Vec<u64> = Vec::new();
  let mut current_indent: u64 = 0;

  // start at indentation 0
  indent_stack.push(current_indent);

  while let Some(&(i, c)) = it.peek() {
    let x = if current_indent < indent_stack[indent_stack.len() - 1] {
      indent_stack.pop();
      Exit
    }
    else {
      match c {
        '#' => lex_comment(&mut it),
        'a'...'z' | 'A'...'Z' | '_' => lex_name(&mut it),
        '0'...'9' => lex_number(&mut it),
        '\n' => {
          let indent = lex_indent(&mut it);

          if let Some(&(_, c)) = it.peek() {
            match c {
              '\n' => Space,
              _ => {
                current_indent = indent;
                // if this panics, there's a bug - indent_stack should always have a 0
                if indent > indent_stack[indent_stack.len() - 1] {
                  indent_stack.push(indent);
                  Enter
                }
                else {
                  End
                }
              }
            }
          }
          else {
            End
          }
        }

        // Compound
        '-' => lex_pair('>', Sub, Arr, &mut it),
        '<' => lex_pair('=', Lt, Le, &mut it),
        '>' => lex_pair('=', Gt, Ge, &mut it),
        '=' => lex_pair('=', Ass, Eql, &mut it),
        '!' => lex_pair('=', Not, Ne, &mut it),
        ':' => lex_pair(':', Col, Meta, &mut it),

        // Symbols
        // -> Arr
        // = Ass
        // : Col
        ',' => {it.next(); Com}
        '.' => {it.next(); Dot}
        // :: Meta
        ';' => {it.next(); Semi}

        // Braces
        '(' => {it.next(); Pal}
        ')' => {it.next(); Par}
        '[' => {it.next(); Sql}
        ']' => {it.next(); Sqr}
        '{' => {it.next(); Cul}
        '}' => {it.next(); Cur}

        // Operators
        '+' => {it.next(); Add}
        '&' => {it.next(); And}
        '@' => {it.next(); At}
        '^' => {it.next(); Car}
        '/' => {it.next(); Div}
        '$' => {it.next(); Dol}
        '*' => {it.next(); Mul}
        '~' => {it.next(); Neg}
        // ! Not
        '|' => {it.next(); Or}
        '%' => {it.next(); Pct}
        // - Sub

        _ => {it.next(); Space}
      }
    };

    // figure out what the span was for this token
    // either there's something we can peek, or the span is until EOF
    let mut end_i = if let Some(&(j, _)) = it.peek() {
      j
    }
    else {
      input.source().len()
    };

    let span = input.span.subspan(i as u64, end_i as u64);
    match x {
      // don't emit tokens for spaces or comments
      Space => (),
      Comment(_) => (),

      // don't insert duplicate newlines, or file-leading newlines
      End => {
        match tokens.last().cloned() {
          None => (),
          Some(x) => {
            if x.node != End {
              tokens.push(Spanned {node: End, span: span});
            }
          },
        }
      }

      // exit should always be followed by a End
      Exit => {
        tokens.push(Spanned {node: Exit, span: span});
        tokens.push(Spanned {node: End, span: span});
      }

      // emit everything else
      _ => tokens.push(Spanned {node: x, span: span}),
    }

  }

  let end = input.source().len() as u64;

  while indent_stack.len() > 1 {
    tokens.push(Spanned {node: Exit, span: input.span.subspan(end, end)});
    tokens.push(Spanned {node: End, span: input.span.subspan(end, end)});
    indent_stack.pop();
  }

  tokens.push(Spanned {node: EOF, span: input.span.subspan(end, end)});

  tokens
}
<commit_msg>lexer: Small cleanups<commit_after>use codemap::File;
use codemap::Spanned;
use self::Token::*;
use std::iter::Enumerate;
use std::iter::Peekable;
use std::str::Chars;

type LexIter<'a> = Peekable<Enumerate<Chars<'a>>>;

#[derive(Debug, Clone, PartialEq)]
pub enum Token {
  // Structure
  EOF,
  Enter,
  Exit,
  Space,
  End,
  Comment(String),

  // Literals
  Null,
  Bool(bool),
  Float(f64),
  Int(i64),
  Str(String),
  Name(String),

  // Keywords
  Break,
  Catch,
  Continue,
  Else,
  For,
  Func,
  If,
  Import,
  In,
  Loop,
  Pass,
  Return,
  Save,
  Var,
  While,

  // Symbols
  Arr, // ->
  Ass, // =
  Col, // :
  Com, // ,
  Dot, // .
  Meta,// ::
  Semi,// ;

  // Braces
  Cul, // {
  Cur, // }
  Pal, // (
  Par, // )
  Sql, // [
  Sqr, // ]

  // Operators
  Add, // +
  And, // &
  At,  // @
  Car, // ^
  Div, // /
  Dol, // $
  Mul, // *
  Neg, // ~
  Not, // !
  Or,  // |
  Pct, // %
  Sub, // -

  // Comparisons
  Eql, // ==
  Ge,  // >=
  Gt,  // >
  Le,  // <=
  Lt,  // <
  Ne,  // !=
}

fn lex_number(it: &mut LexIter) -> Token {
  let mut digits = String::new();
  while let Some(&(_i, c)) = it.peek() {
    match c {
      '0'...'9' | '.' => {
        it.next();
        digits.push(c);
      }
      _ => {break}
    }
  }

  match digits.contains(".") {
    true => Float(digits.parse::<f64>().unwrap()),
    false => Int(digits.parse::<i64>().unwrap())
  }
}

fn lex_name(it: &mut LexIter) -> Token {
  let mut name = String::new();
  name.push(it.next().unwrap().1);

  while let Some(&(_i, c)) = it.peek() {
    match c {
      'a'...'z' | 'A'...'Z' | '0'...'9' | '_' => {
        it.next();
        name.push(c);
      }
      _ => {break}
    }
  }

  match name.as_str() {
    "true" => Bool(true),
    "false" => Bool(false),
    "null" => Null,

    "break" => Break,
    "catch" => Catch,
    "continue" => Continue,
    "else" => Else,
    "for" => For,
    "func" => Func,
    "if" => If,
    "import" => Import,
    "in" => In,
    "loop" => Loop,
    "pass" => Pass,
    "return" => Return,
    "save" => Save,
    "var" => Var,
    "while" => While,

    _ => Name(name)
  }
}

fn lex_comment(it: &mut LexIter) -> Token {
  let mut comment = String::new();
  it.next();

  while let Some(&(_i, c)) = it.peek() {
    match c {
      '\n' => {break}
      _ => {
        it.next();
        comment.push(c);
      }
    }
  }

  println!("Comment: {:?}", comment);
  Comment(comment)
}

fn lex_indent(it: &mut LexIter) -> u64 {
  let mut indent: u64 = 0;
  it.next();

  while let Some(&(_i, c)) = it.peek() {
    match c {
      ' ' => {
        it.next();
        indent += 1;
      }
      _ => {break}
    }
  }

  indent
}

fn lex_pair(next: char, solo: Token, pair: Token, it: &mut LexIter) -> Token {
  it.next();

  if let Some(&(_i, c)) = it.peek() {
    if c == next {
      it.next();
      return pair;
    }
  }

  // is this right? if peek() returns a None, we just return `solo`?
  // seems right. None should be the EOF, meaning `solo` is the last token
  solo
}

pub fn lex(input: &File) -> Vec<Spanned<Token>> {
  let mut tokens: Vec<Spanned<Token>> = Vec::new();
  let mut it: LexIter = input.source().chars().enumerate().peekable();
  let mut indent_stack: Vec<u64> = Vec::new();
  let mut current_indent: u64 = 0;

  // start at indentation 0
  indent_stack.push(current_indent);

  while let Some(&(i, c)) = it.peek() {
    let x = if current_indent < indent_stack[indent_stack.len() - 1] {
      indent_stack.pop();
      Exit
    }
    else {
      match c {
        '#' => lex_comment(&mut it),
        'a'...'z' | 'A'...'Z' | '_' => lex_name(&mut it),
        '0'...'9' => lex_number(&mut it),
        '\n' => {
          let indent = lex_indent(&mut it);

          if let Some(&(_, c)) = it.peek() {
            match c {
              '\n' => Space,
              _ => {
                current_indent = indent;
                // if this panics, there's a bug - indent_stack should always have a 0
                if indent > indent_stack[indent_stack.len() - 1] {
                  indent_stack.push(indent);
                  Enter
                }
                else {
                  End
                }
              }
            }
          }
          else {
            End
          }
        }

        // Compound
        '-' => lex_pair('>', Sub, Arr, &mut it),
        '<' => lex_pair('=', Lt, Le, &mut it),
        '>' => lex_pair('=', Gt, Ge, &mut it),
        '=' => lex_pair('=', Ass, Eql, &mut it),
        '!' => lex_pair('=', Not, Ne, &mut it),
        ':' => lex_pair(':', Col, Meta, &mut it),

        // Symbols
        // -> Arr
        // = Ass
        // : Col
        ',' => {it.next(); Com}
        '.' => {it.next(); Dot}
        // :: Meta
        ';' => {it.next(); Semi}

        // Braces
        '(' => {it.next(); Pal}
        ')' => {it.next(); Par}
        '[' => {it.next(); Sql}
        ']' => {it.next(); Sqr}
        '{' => {it.next(); Cul}
        '}' => {it.next(); Cur}

        // Operators
        '+' => {it.next(); Add}
        '&' => {it.next(); And}
        '@' => {it.next(); At}
        '^' => {it.next(); Car}
        '/' => {it.next(); Div}
        '$' => {it.next(); Dol}
        '*' => {it.next(); Mul}
        '~' => {it.next(); Neg}
        // ! Not
        '|' => {it.next(); Or}
        '%' => {it.next(); Pct}
        // - Sub

        _ => {it.next(); Space}
      }
    };

    // figure out what the span was for this token
    // either there's something we can peek, or the span is until EOF
    let mut end_i = if let Some(&(j, _)) = it.peek() {
      j
    }
    else {
      input.source().len()
    };
    let span = input.span.subspan(i as u64, end_i as u64);

    match x {
      // don't emit tokens for spaces or comments
      Space => (),
      Comment(_) => (),

      // don't insert duplicate newlines, or file-leading newlines
      End => {
        match tokens.last().cloned() {
          None => (),
          Some(x) => {
            if x.node != End {
              tokens.push(Spanned {node: End, span: span});
            }
          },
        }
      }

      // exit should always be followed by a End
      Exit => {
        tokens.push(Spanned {node: Exit, span: span});
        tokens.push(Spanned {node: End, span: span});
      }

      // emit everything else
      _ => tokens.push(Spanned {node: x, span: span}),
    }

  }

  // make a span for all closing tokens
  let end = input.source().len() as u64;
  let span = input.span.subspan(end, end);

  // exit blocks that are open at EOF
  while indent_stack.len() > 1 {
    tokens.push(Spanned {node: Exit, span: span});
    tokens.push(Spanned {node: End, span: span});
    indent_stack.pop();
  }

  // push the EOF token
  tokens.push(Spanned {node: EOF, span: span});

  tokens
}
<|endoftext|>


<commit_before>use libc::c_int;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};

use ReadsMemory;

pub struct MemReader {
  pid: u32
}

impl MemReader {
  pub fn new(pid: u32) -> Self {
    MemReader {
      pid: pid
    }
  }

  fn get_memory_file(&self) -> Result<File, c_int> {
    File::open(&format!("/proc/{}/maps", self.pid)).map_err(|_| -1)
  }
}

impl ReadsMemory for MemReader {
  fn read_bytes(&self, address: usize, n: usize) -> Result<Vec<u8>, c_int> {
    let mut file = self.get_memory_file()?;
    file.seek(SeekFrom::Start(address as u64)).map_err(|_| -2)?;
    let mut bytes = Vec::with_capacity(n);
    file.read(&mut bytes).map_err(|_| -3)?;
    Ok(bytes)
  }
}
<commit_msg>fix: set length of vector<commit_after>use libc::c_int;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};

use ReadsMemory;

pub struct MemReader {
  pid: u32
}

impl MemReader {
  pub fn new(pid: u32) -> Self {
    MemReader {
      pid: pid
    }
  }

  fn get_memory_file(&self) -> Result<File, c_int> {
    File::open(&format!("/proc/{}/maps", self.pid)).map_err(|_| -1)
  }
}

impl ReadsMemory for MemReader {
  fn read_bytes(&self, address: usize, n: usize) -> Result<Vec<u8>, c_int> {
    let mut file = self.get_memory_file()?;
    file.seek(SeekFrom::Start(address as u64)).map_err(|_| -2)?;
    let mut bytes: Vec<u8> = Vec::with_capacity(n);
    unsafe { bytes.set_len(n) };
    file.read_exact(&mut bytes).map_err(|_| -3)?;
    Ok(bytes)
  }
}
<|endoftext|>