<commit_before>//! Completes keywords.

use syntax::{ast, SyntaxKind};
use test_utils::mark;

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

pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) {
    // complete keyword "crate" in use stmt
    let source_range = ctx.source_range();

    if ctx.use_item_syntax.is_some() {
        if ctx.path_qual.is_none() {
            CompletionItem::new(CompletionKind::Keyword, source_range, "crate::")
                .kind(CompletionItemKind::Keyword)
                .insert_text("crate::")
                .add_to(acc);
        }
        CompletionItem::new(CompletionKind::Keyword, source_range, "self")
            .kind(CompletionItemKind::Keyword)
            .add_to(acc);
        CompletionItem::new(CompletionKind::Keyword, source_range, "super::")
            .kind(CompletionItemKind::Keyword)
            .insert_text("super::")
            .add_to(acc);
    }

    // Suggest .await syntax for types that implement Future trait
    if let Some(receiver) = &ctx.dot_receiver {
        if let Some(ty) = ctx.sema.type_of_expr(receiver) {
            if ty.impls_future(ctx.db) {
                CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await")
                    .kind(CompletionItemKind::Keyword)
                    .detail("expr.await")
                    .insert_text("await")
                    .add_to(acc);
            }
        };
    }
}

pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
    if ctx.token.kind() == SyntaxKind::COMMENT {
        mark::hit!(no_keyword_completion_in_comments);
        return;
    }
    if ctx.record_lit_syntax.is_some() {
        mark::hit!(no_keyword_completion_in_record_lit);
        return;
    }

    let has_trait_or_impl_parent = ctx.has_impl_parent || ctx.has_trait_parent;
    if ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling {
        add_keyword(ctx, acc, "where", "where ");
        return;
    }
    if ctx.unsafe_is_prev {
        if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent {
            add_keyword(ctx, acc, "fn", "fn $0() {}")
        }

        if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
            add_keyword(ctx, acc, "trait", "trait $0 {}");
            add_keyword(ctx, acc, "impl", "impl $0 {}");
        }

        return;
    }
    if ctx.has_item_list_or_source_file_parent || has_trait_or_impl_parent || ctx.block_expr_parent
    {
        add_keyword(ctx, acc, "fn", "fn $0() {}");
    }
    if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
        add_keyword(ctx, acc, "use", "use ");
        add_keyword(ctx, acc, "impl", "impl $0 {}");
        add_keyword(ctx, acc, "trait", "trait $0 {}");
    }

    if ctx.has_item_list_or_source_file_parent {
        add_keyword(ctx, acc, "enum", "enum $0 {}");
        add_keyword(ctx, acc, "struct", "struct $0");
        add_keyword(ctx, acc, "union", "union $0 {}");
    }

    if ctx.is_expr {
        add_keyword(ctx, acc, "match", "match $0 {}");
        add_keyword(ctx, acc, "while", "while $0 {}");
        add_keyword(ctx, acc, "loop", "loop {$0}");
        add_keyword(ctx, acc, "if", "if $0 {}");
        add_keyword(ctx, acc, "if let", "if let $1 = $0 {}");
    }

    if ctx.if_is_prev || ctx.block_expr_parent {
        add_keyword(ctx, acc, "let", "let ");
    }

    if ctx.after_if {
        add_keyword(ctx, acc, "else", "else {$0}");
        add_keyword(ctx, acc, "else if", "else if $0 {}");
    }
    if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
        add_keyword(ctx, acc, "mod", "mod $0 {}");
    }
    if ctx.bind_pat_parent || ctx.ref_pat_parent {
        add_keyword(ctx, acc, "mut", "mut ");
    }
    if ctx.has_item_list_or_source_file_parent || has_trait_or_impl_parent || ctx.block_expr_parent
    {
        add_keyword(ctx, acc, "const", "const ");
        add_keyword(ctx, acc, "type", "type ");
    }
    if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
        add_keyword(ctx, acc, "static", "static ");
    };
    if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
        add_keyword(ctx, acc, "extern", "extern ");
    }
    if ctx.has_item_list_or_source_file_parent
        || has_trait_or_impl_parent
        || ctx.block_expr_parent
        || ctx.is_match_arm
    {
        add_keyword(ctx, acc, "unsafe", "unsafe ");
    }
    if ctx.in_loop_body {
        if ctx.can_be_stmt {
            add_keyword(ctx, acc, "continue", "continue;");
            add_keyword(ctx, acc, "break", "break;");
        } else {
            add_keyword(ctx, acc, "continue", "continue");
            add_keyword(ctx, acc, "break", "break");
        }
    }
    if ctx.has_item_list_or_source_file_parent || ctx.has_impl_parent | ctx.has_field_list_parent {
        add_keyword(ctx, acc, "pub(crate)", "pub(crate) ");
        add_keyword(ctx, acc, "pub", "pub ");
    }

    if !ctx.is_trivial_path {
        return;
    }
    let fn_def = match &ctx.function_syntax {
        Some(it) => it,
        None => return,
    };
    acc.add_all(complete_return(ctx, &fn_def, ctx.can_be_stmt));
}

fn keyword(ctx: &CompletionContext, kw: &str, snippet: &str) -> CompletionItem {
    let res = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw)
        .kind(CompletionItemKind::Keyword);

    match ctx.config.snippet_cap {
        Some(cap) => res.insert_snippet(cap, snippet),
        _ => res.insert_text(if snippet.contains('$') { kw } else { snippet }),
    }
    .build()
}

fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) {
    acc.add(keyword(ctx, kw, snippet));
}

fn complete_return(
    ctx: &CompletionContext,
    fn_def: &ast::Fn,
    can_be_stmt: bool,
) -> Option<CompletionItem> {
    let snip = match (can_be_stmt, fn_def.ret_type().is_some()) {
        (true, true) => "return $0;",
        (true, false) => "return;",
        (false, true) => "return $0",
        (false, false) => "return",
    };
    Some(keyword(ctx, "return", snip))
}

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

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

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

    #[test]
    fn test_keywords_in_use_stmt() {
        check(
            r"use $0",
            expect![[r#"
                kw crate::
                kw self
                kw super::
            "#]],
        );

        check(
            r"use a::$0",
            expect![[r#"
                kw self
                kw super::
            "#]],
        );

        check(
            r"use a::{b, $0}",
            expect![[r#"
                kw self
                kw super::
            "#]],
        );
    }

    #[test]
    fn test_keywords_at_source_file_level() {
        check(
            r"m$0",
            expect![[r#"
                kw fn
                kw use
                kw impl
                kw trait
                kw enum
                kw struct
                kw union
                kw mod
                kw const
                kw type
                kw static
                kw extern
                kw unsafe
                kw pub(crate)
                kw pub
            "#]],
        );
    }

    #[test]
    fn test_keywords_in_function() {
        check(
            r"fn quux() { $0 }",
            expect![[r#"
                kw fn
                kw use
                kw impl
                kw trait
                kw match
                kw while
                kw loop
                kw if
                kw if let
                kw let
                kw mod
                kw const
                kw type
                kw static
                kw extern
                kw unsafe
                kw return
            "#]],
        );
    }

    #[test]
    fn test_keywords_inside_block() {
        check(
            r"fn quux() { if true { $0 } }",
            expect![[r#"
                kw fn
                kw use
                kw impl
                kw trait
                kw match
                kw while
                kw loop
                kw if
                kw if let
                kw let
                kw mod
                kw const
                kw type
                kw static
                kw extern
                kw unsafe
                kw return
            "#]],
        );
    }

    #[test]
    fn test_keywords_after_if() {
        check(
            r#"fn quux() { if true { () } $0 }"#,
            expect![[r#"
                kw fn
                kw use
                kw impl
                kw trait
                kw match
                kw while
                kw loop
                kw if
                kw if let
                kw let
                kw else
                kw else if
                kw mod
                kw const
                kw type
                kw static
                kw extern
                kw unsafe
                kw return
            "#]],
        );
        check_edit(
            "else",
            r#"fn quux() { if true { () } $0 }"#,
            r#"fn quux() { if true { () } else {$0} }"#,
        );
    }

    #[test]
    fn test_keywords_in_match_arm() {
        check(
            r#"
fn quux() -> i32 {
    match () { () => $0 }
}
"#,
            expect![[r#"
                kw match
                kw while
                kw loop
                kw if
                kw if let
                kw unsafe
                kw return
            "#]],
        );
    }

    #[test]
    fn test_keywords_in_trait_def() {
        check(
            r"trait My { $0 }",
            expect![[r#"
                kw fn
                kw const
                kw type
                kw unsafe
            "#]],
        );
    }

    #[test]
    fn test_keywords_in_impl_def() {
        check(
            r"impl My { $0 }",
            expect![[r#"
                kw fn
                kw const
                kw type
                kw unsafe
                kw pub(crate)
                kw pub
            "#]],
        );
    }

    #[test]
    fn test_keywords_in_loop() {
        check(
            r"fn my() { loop { $0 } }",
            expect![[r#"
                kw fn
                kw use
                kw impl
                kw trait
                kw match
                kw while
                kw loop
                kw if
                kw if let
                kw let
                kw mod
                kw const
                kw type
                kw static
                kw extern
                kw unsafe
                kw continue
                kw break
                kw return
            "#]],
        );
    }

    #[test]
    fn test_keywords_after_unsafe_in_item_list() {
        check(
            r"unsafe $0",
            expect![[r#"
                kw fn
                kw trait
                kw impl
            "#]],
        );
    }

    #[test]
    fn test_keywords_after_unsafe_in_block_expr() {
        check(
            r"fn my_fn() { unsafe $0 }",
            expect![[r#"
                kw fn
                kw trait
                kw impl
            "#]],
        );
    }

    #[test]
    fn test_mut_in_ref_and_in_fn_parameters_list() {
        check(
            r"fn my_fn(&$0) {}",
            expect![[r#"
                kw mut
            "#]],
        );
        check(
            r"fn my_fn($0) {}",
            expect![[r#"
                kw mut
            "#]],
        );
        check(
            r"fn my_fn() { let &$0 }",
            expect![[r#"
                kw mut
            "#]],
        );
    }

    #[test]
    fn test_where_keyword() {
        check(
            r"trait A $0",
            expect![[r#"
                kw where
            "#]],
        );
        check(
            r"impl A $0",
            expect![[r#"
                kw where
            "#]],
        );
    }

    #[test]
    fn no_keyword_completion_in_comments() {
        mark::check!(no_keyword_completion_in_comments);
        check(
            r#"
fn test() {
    let x = 2; // A comment$0
}
"#,
            expect![[""]],
        );
        check(
            r#"
/*
Some multi-line comment$0
*/
"#,
            expect![[""]],
        );
        check(
            r#"
/// Some doc comment
/// let test$0 = 1
"#,
            expect![[""]],
        );
    }

    #[test]
    fn test_completion_await_impls_future() {
        check(
            r#"
//- /main.rs crate:main deps:std
use std::future::*;
struct A {}
impl Future for A {}
fn foo(a: A) { a.$0 }

//- /std/lib.rs crate:std
pub mod future {
    #[lang = "future_trait"]
    pub trait Future {}
}
"#,
            expect![[r#"
                kw await expr.await
            "#]],
        );

        check(
            r#"
//- /main.rs crate:main deps:std
use std::future::*;
fn foo() {
    let a = async {};
    a.$0
}

//- /std/lib.rs crate:std
pub mod future {
    #[lang = "future_trait"]
    pub trait Future {
        type Output;
    }
}
"#,
            expect![[r#"
                kw await expr.await
            "#]],
        )
    }

    #[test]
    fn after_let() {
        check(
            r#"fn main() { let _ = $0 }"#,
            expect![[r#"
                kw match
                kw while
                kw loop
                kw if
                kw if let
                kw return
            "#]],
        )
    }

    #[test]
    fn before_field() {
        check(
            r#"
struct Foo {
    $0
    pub f: i32,
}
"#,
            expect![[r#"
                kw pub(crate)
                kw pub
            "#]],
        )
    }

    #[test]
    fn skip_struct_initializer() {
        mark::check!(no_keyword_completion_in_record_lit);
        check(
            r#"
struct Foo {
    pub f: i32,
}
fn foo() {
    Foo {
        $0
    }
}
"#,
            expect![[r#""#]],
        );
    }

    #[test]
    fn struct_initializer_field_expr() {
        check(
            r#"
struct Foo {
    pub f: i32,
}
fn foo() {
    Foo {
        f: $0
    }
}
"#,
            expect![[r#"
                kw match
                kw while
                kw loop
                kw if
                kw if let
                kw return
            "#]],
        );
    }
}
<commit_msg>Simplify<commit_after>//! Completes keywords.

use syntax::SyntaxKind;
use test_utils::mark;

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

pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) {
    // complete keyword "crate" in use stmt
    let source_range = ctx.source_range();

    if ctx.use_item_syntax.is_some() {
        if ctx.path_qual.is_none() {
            CompletionItem::new(CompletionKind::Keyword, source_range, "crate::")
                .kind(CompletionItemKind::Keyword)
                .insert_text("crate::")
                .add_to(acc);
        }
        CompletionItem::new(CompletionKind::Keyword, source_range, "self")
            .kind(CompletionItemKind::Keyword)
            .add_to(acc);
        CompletionItem::new(CompletionKind::Keyword, source_range, "super::")
            .kind(CompletionItemKind::Keyword)
            .insert_text("super::")
            .add_to(acc);
    }

    // Suggest .await syntax for types that implement Future trait
    if let Some(receiver) = &ctx.dot_receiver {
        if let Some(ty) = ctx.sema.type_of_expr(receiver) {
            if ty.impls_future(ctx.db) {
                CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await")
                    .kind(CompletionItemKind::Keyword)
                    .detail("expr.await")
                    .insert_text("await")
                    .add_to(acc);
            }
        };
    }
}

pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
    if ctx.token.kind() == SyntaxKind::COMMENT {
        mark::hit!(no_keyword_completion_in_comments);
        return;
    }
    if ctx.record_lit_syntax.is_some() {
        mark::hit!(no_keyword_completion_in_record_lit);
        return;
    }

    let has_trait_or_impl_parent = ctx.has_impl_parent || ctx.has_trait_parent;
    if ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling {
        add_keyword(ctx, acc, "where", "where ");
        return;
    }
    if ctx.unsafe_is_prev {
        if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent {
            add_keyword(ctx, acc, "fn", "fn $0() {}")
        }

        if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
            add_keyword(ctx, acc, "trait", "trait $0 {}");
            add_keyword(ctx, acc, "impl", "impl $0 {}");
        }

        return;
    }
    if ctx.has_item_list_or_source_file_parent || has_trait_or_impl_parent || ctx.block_expr_parent
    {
        add_keyword(ctx, acc, "fn", "fn $0() {}");
    }
    if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
        add_keyword(ctx, acc, "use", "use ");
        add_keyword(ctx, acc, "impl", "impl $0 {}");
        add_keyword(ctx, acc, "trait", "trait $0 {}");
    }

    if ctx.has_item_list_or_source_file_parent {
        add_keyword(ctx, acc, "enum", "enum $0 {}");
        add_keyword(ctx, acc, "struct", "struct $0");
        add_keyword(ctx, acc, "union", "union $0 {}");
    }

    if ctx.is_expr {
        add_keyword(ctx, acc, "match", "match $0 {}");
        add_keyword(ctx, acc, "while", "while $0 {}");
        add_keyword(ctx, acc, "loop", "loop {$0}");
        add_keyword(ctx, acc, "if", "if $0 {}");
        add_keyword(ctx, acc, "if let", "if let $1 = $0 {}");
    }

    if ctx.if_is_prev || ctx.block_expr_parent {
        add_keyword(ctx, acc, "let", "let ");
    }

    if ctx.after_if {
        add_keyword(ctx, acc, "else", "else {$0}");
        add_keyword(ctx, acc, "else if", "else if $0 {}");
    }
    if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
        add_keyword(ctx, acc, "mod", "mod $0 {}");
    }
    if ctx.bind_pat_parent || ctx.ref_pat_parent {
        add_keyword(ctx, acc, "mut", "mut ");
    }
    if ctx.has_item_list_or_source_file_parent || has_trait_or_impl_parent || ctx.block_expr_parent
    {
        add_keyword(ctx, acc, "const", "const ");
        add_keyword(ctx, acc, "type", "type ");
    }
    if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
        add_keyword(ctx, acc, "static", "static ");
    };
    if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
        add_keyword(ctx, acc, "extern", "extern ");
    }
    if ctx.has_item_list_or_source_file_parent
        || has_trait_or_impl_parent
        || ctx.block_expr_parent
        || ctx.is_match_arm
    {
        add_keyword(ctx, acc, "unsafe", "unsafe ");
    }
    if ctx.in_loop_body {
        if ctx.can_be_stmt {
            add_keyword(ctx, acc, "continue", "continue;");
            add_keyword(ctx, acc, "break", "break;");
        } else {
            add_keyword(ctx, acc, "continue", "continue");
            add_keyword(ctx, acc, "break", "break");
        }
    }
    if ctx.has_item_list_or_source_file_parent || ctx.has_impl_parent | ctx.has_field_list_parent {
        add_keyword(ctx, acc, "pub(crate)", "pub(crate) ");
        add_keyword(ctx, acc, "pub", "pub ");
    }

    if !ctx.is_trivial_path {
        return;
    }
    let fn_def = match &ctx.function_syntax {
        Some(it) => it,
        None => return,
    };

    add_keyword(
        ctx,
        acc,
        "return",
        match (ctx.can_be_stmt, fn_def.ret_type().is_some()) {
            (true, true) => "return $0;",
            (true, false) => "return;",
            (false, true) => "return $0",
            (false, false) => "return",
        },
    )
}

fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) {
    let builder = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw)
        .kind(CompletionItemKind::Keyword);
    let builder = match ctx.config.snippet_cap {
        Some(cap) => builder.insert_snippet(cap, snippet),
        None => builder.insert_text(if snippet.contains('$') { kw } else { snippet }),
    };
    acc.add(builder.build());
}

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

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

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

    #[test]
    fn test_keywords_in_use_stmt() {
        check(
            r"use $0",
            expect![[r#"
                kw crate::
                kw self
                kw super::
            "#]],
        );

        check(
            r"use a::$0",
            expect![[r#"
                kw self
                kw super::
            "#]],
        );

        check(
            r"use a::{b, $0}",
            expect![[r#"
                kw self
                kw super::
            "#]],
        );
    }

    #[test]
    fn test_keywords_at_source_file_level() {
        check(
            r"m$0",
            expect![[r#"
                kw fn
                kw use
                kw impl
                kw trait
                kw enum
                kw struct
                kw union
                kw mod
                kw const
                kw type
                kw static
                kw extern
                kw unsafe
                kw pub(crate)
                kw pub
            "#]],
        );
    }

    #[test]
    fn test_keywords_in_function() {
        check(
            r"fn quux() { $0 }",
            expect![[r#"
                kw fn
                kw use
                kw impl
                kw trait
                kw match
                kw while
                kw loop
                kw if
                kw if let
                kw let
                kw mod
                kw const
                kw type
                kw static
                kw extern
                kw unsafe
                kw return
            "#]],
        );
    }

    #[test]
    fn test_keywords_inside_block() {
        check(
            r"fn quux() { if true { $0 } }",
            expect![[r#"
                kw fn
                kw use
                kw impl
                kw trait
                kw match
                kw while
                kw loop
                kw if
                kw if let
                kw let
                kw mod
                kw const
                kw type
                kw static
                kw extern
                kw unsafe
                kw return
            "#]],
        );
    }

    #[test]
    fn test_keywords_after_if() {
        check(
            r#"fn quux() { if true { () } $0 }"#,
            expect![[r#"
                kw fn
                kw use
                kw impl
                kw trait
                kw match
                kw while
                kw loop
                kw if
                kw if let
                kw let
                kw else
                kw else if
                kw mod
                kw const
                kw type
                kw static
                kw extern
                kw unsafe
                kw return
            "#]],
        );
        check_edit(
            "else",
            r#"fn quux() { if true { () } $0 }"#,
            r#"fn quux() { if true { () } else {$0} }"#,
        );
    }

    #[test]
    fn test_keywords_in_match_arm() {
        check(
            r#"
fn quux() -> i32 {
    match () { () => $0 }
}
"#,
            expect![[r#"
                kw match
                kw while
                kw loop
                kw if
                kw if let
                kw unsafe
                kw return
            "#]],
        );
    }

    #[test]
    fn test_keywords_in_trait_def() {
        check(
            r"trait My { $0 }",
            expect![[r#"
                kw fn
                kw const
                kw type
                kw unsafe
            "#]],
        );
    }

    #[test]
    fn test_keywords_in_impl_def() {
        check(
            r"impl My { $0 }",
            expect![[r#"
                kw fn
                kw const
                kw type
                kw unsafe
                kw pub(crate)
                kw pub
            "#]],
        );
    }

    #[test]
    fn test_keywords_in_loop() {
        check(
            r"fn my() { loop { $0 } }",
            expect![[r#"
                kw fn
                kw use
                kw impl
                kw trait
                kw match
                kw while
                kw loop
                kw if
                kw if let
                kw let
                kw mod
                kw const
                kw type
                kw static
                kw extern
                kw unsafe
                kw continue
                kw break
                kw return
            "#]],
        );
    }

    #[test]
    fn test_keywords_after_unsafe_in_item_list() {
        check(
            r"unsafe $0",
            expect![[r#"
                kw fn
                kw trait
                kw impl
            "#]],
        );
    }

    #[test]
    fn test_keywords_after_unsafe_in_block_expr() {
        check(
            r"fn my_fn() { unsafe $0 }",
            expect![[r#"
                kw fn
                kw trait
                kw impl
            "#]],
        );
    }

    #[test]
    fn test_mut_in_ref_and_in_fn_parameters_list() {
        check(
            r"fn my_fn(&$0) {}",
            expect![[r#"
                kw mut
            "#]],
        );
        check(
            r"fn my_fn($0) {}",
            expect![[r#"
                kw mut
            "#]],
        );
        check(
            r"fn my_fn() { let &$0 }",
            expect![[r#"
                kw mut
            "#]],
        );
    }

    #[test]
    fn test_where_keyword() {
        check(
            r"trait A $0",
            expect![[r#"
                kw where
            "#]],
        );
        check(
            r"impl A $0",
            expect![[r#"
                kw where
            "#]],
        );
    }

    #[test]
    fn no_keyword_completion_in_comments() {
        mark::check!(no_keyword_completion_in_comments);
        check(
            r#"
fn test() {
    let x = 2; // A comment$0
}
"#,
            expect![[""]],
        );
        check(
            r#"
/*
Some multi-line comment$0
*/
"#,
            expect![[""]],
        );
        check(
            r#"
/// Some doc comment
/// let test$0 = 1
"#,
            expect![[""]],
        );
    }

    #[test]
    fn test_completion_await_impls_future() {
        check(
            r#"
//- /main.rs crate:main deps:std
use std::future::*;
struct A {}
impl Future for A {}
fn foo(a: A) { a.$0 }

//- /std/lib.rs crate:std
pub mod future {
    #[lang = "future_trait"]
    pub trait Future {}
}
"#,
            expect![[r#"
                kw await expr.await
            "#]],
        );

        check(
            r#"
//- /main.rs crate:main deps:std
use std::future::*;
fn foo() {
    let a = async {};
    a.$0
}

//- /std/lib.rs crate:std
pub mod future {
    #[lang = "future_trait"]
    pub trait Future {
        type Output;
    }
}
"#,
            expect![[r#"
                kw await expr.await
            "#]],
        )
    }

    #[test]
    fn after_let() {
        check(
            r#"fn main() { let _ = $0 }"#,
            expect![[r#"
                kw match
                kw while
                kw loop
                kw if
                kw if let
                kw return
            "#]],
        )
    }

    #[test]
    fn before_field() {
        check(
            r#"
struct Foo {
    $0
    pub f: i32,
}
"#,
            expect![[r#"
                kw pub(crate)
                kw pub
            "#]],
        )
    }

    #[test]
    fn skip_struct_initializer() {
        mark::check!(no_keyword_completion_in_record_lit);
        check(
            r#"
struct Foo {
    pub f: i32,
}
fn foo() {
    Foo {
        $0
    }
}
"#,
            expect![[r#""#]],
        );
    }

    #[test]
    fn struct_initializer_field_expr() {
        check(
            r#"
struct Foo {
    pub f: i32,
}
fn foo() {
    Foo {
        f: $0
    }
}
"#,
            expect![[r#"
                kw match
                kw while
                kw loop
                kw if
                kw if let
                kw return
            "#]],
        );
    }
}
<|endoftext|>


<commit_before>use ra_syntax::{
    ast::{self, NameOwner, VisibilityOwner, TypeAscriptionOwner, AstNode},
};

pub(crate) trait ShortLabel {
    fn short_label(&self) -> Option<String>;
}

impl ShortLabel for ast::FnDef {
    fn short_label(&self) -> Option<String> {
        Some(crate::display::function_label(self))
    }
}

impl ShortLabel for ast::StructDef {
    fn short_label(&self) -> Option<String> {
        short_label_from_node(self, "struct ")
    }
}

impl ShortLabel for ast::EnumDef {
    fn short_label(&self) -> Option<String> {
        short_label_from_node(self, "enum ")
    }
}

impl ShortLabel for ast::TraitDef {
    fn short_label(&self) -> Option<String> {
        short_label_from_node(self, "trait ")
    }
}

impl ShortLabel for ast::Module {
    fn short_label(&self) -> Option<String> {
        short_label_from_node(self, "mod ")
    }
}

impl ShortLabel for ast::TypeAliasDef {
    fn short_label(&self) -> Option<String> {
        short_label_from_node(self, "type ")
    }
}

impl ShortLabel for ast::ConstDef {
    fn short_label(&self) -> Option<String> {
        short_label_from_ascribed_node(self, "const ")
    }
}

impl ShortLabel for ast::StaticDef {
    fn short_label(&self) -> Option<String> {
        short_label_from_ascribed_node(self, "static ")
    }
}

impl ShortLabel for ast::NamedFieldDef {
    fn short_label(&self) -> Option<String> {
        short_label_from_ascribed_node(self, "")
    }
}

impl ShortLabel for ast::EnumVariant {
    fn short_label(&self) -> Option<String> {
        Some(self.name()?.text().to_string())
    }
}

fn short_label_from_ascribed_node<T>(node: &T, prefix: &str) -> Option<String>
where
    T: NameOwner + VisibilityOwner + TypeAscriptionOwner,
{
    let mut string = short_label_from_node(node, prefix)?;

    if let Some(type_ref) = node.ascribed_type() {
        string.push_str(": ");
        type_ref.syntax().text().push_to(&mut string);
    }

    Some(string)
}

fn short_label_from_node<T>(node: &T, label: &str) -> Option<String>
where
    T: NameOwner + VisibilityOwner,
{
    let mut string =
        node.visibility().map(|v| format!("{} ", v.syntax().text())).unwrap_or_default();
    string.push_str(label);
    string.push_str(node.name()?.text().as_str());
    Some(string)
}
<commit_msg>Rename "string" to "buf"<commit_after>use ra_syntax::{
    ast::{self, NameOwner, VisibilityOwner, TypeAscriptionOwner, AstNode},
};

pub(crate) trait ShortLabel {
    fn short_label(&self) -> Option<String>;
}

impl ShortLabel for ast::FnDef {
    fn short_label(&self) -> Option<String> {
        Some(crate::display::function_label(self))
    }
}

impl ShortLabel for ast::StructDef {
    fn short_label(&self) -> Option<String> {
        short_label_from_node(self, "struct ")
    }
}

impl ShortLabel for ast::EnumDef {
    fn short_label(&self) -> Option<String> {
        short_label_from_node(self, "enum ")
    }
}

impl ShortLabel for ast::TraitDef {
    fn short_label(&self) -> Option<String> {
        short_label_from_node(self, "trait ")
    }
}

impl ShortLabel for ast::Module {
    fn short_label(&self) -> Option<String> {
        short_label_from_node(self, "mod ")
    }
}

impl ShortLabel for ast::TypeAliasDef {
    fn short_label(&self) -> Option<String> {
        short_label_from_node(self, "type ")
    }
}

impl ShortLabel for ast::ConstDef {
    fn short_label(&self) -> Option<String> {
        short_label_from_ascribed_node(self, "const ")
    }
}

impl ShortLabel for ast::StaticDef {
    fn short_label(&self) -> Option<String> {
        short_label_from_ascribed_node(self, "static ")
    }
}

impl ShortLabel for ast::NamedFieldDef {
    fn short_label(&self) -> Option<String> {
        short_label_from_ascribed_node(self, "")
    }
}

impl ShortLabel for ast::EnumVariant {
    fn short_label(&self) -> Option<String> {
        Some(self.name()?.text().to_string())
    }
}

fn short_label_from_ascribed_node<T>(node: &T, prefix: &str) -> Option<String>
where
    T: NameOwner + VisibilityOwner + TypeAscriptionOwner,
{
    let mut buf = short_label_from_node(node, prefix)?;

    if let Some(type_ref) = node.ascribed_type() {
        buf.push_str(": ");
        type_ref.syntax().text().push_to(&mut buf);
    }

    Some(buf)
}

fn short_label_from_node<T>(node: &T, label: &str) -> Option<String>
where
    T: NameOwner + VisibilityOwner,
{
    let mut buf =
        node.visibility().map(|v| format!("{} ", v.syntax().text())).unwrap_or_default();
    buf.push_str(label);
    buf.push_str(node.name()?.text().as_str());
    Some(buf)
}
<|endoftext|>


<commit_before>//! This LintPass catches both string addition and string addition + assignment
//!
//! Note that since we have two lints where one subsumes the other, we try to
//! disable the subsumed lint unless it has a higher level

use rustc::lint::*;
use rustc::middle::ty::TypeVariants::TyStruct;
use syntax::ast::*;
use syntax::codemap::{Span, Spanned};
use eq_op::is_exp_equal;
use types::match_ty_unwrap;
use utils::{match_def_path, span_lint, walk_ptrs_ty, get_parent_expr};

declare_lint! {
    pub STRING_ADD_ASSIGN,
    Warn,
    "Warn on `x = x + ..` where x is a `String`"
}

declare_lint! {
    pub STRING_ADD,
    Allow,
    "Warn on `x + ..` where x is a `String`"
}

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

impl LintPass for StringAdd {
    fn get_lints(&self) -> LintArray {
        lint_array!(STRING_ADD, STRING_ADD_ASSIGN)
    }

    fn check_expr(&mut self, cx: &Context, e: &Expr) {
        if let &ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) = &e.node {
            if is_string(cx, left) {
                if let Allow = cx.current_level(STRING_ADD_ASSIGN) {
                    // the string_add_assign is allow, so no duplicates
                } else {
                    let parent = get_parent_expr(cx, e);
                    if let Some(ref p) = parent {
                        if let &ExprAssign(ref target, _) = &p.node {
                            // avoid duplicate matches
                            if is_exp_equal(target, left) { return; }
                        }
                    }
                }
                //TODO check for duplicates
                 span_lint(cx, STRING_ADD, e.span,
                        "you add something to a string. \
                        Consider using `String::push_str()` instead.")
            }
        } else if let &ExprAssign(ref target, ref  src) = &e.node {
            if is_string(cx, target) && is_add(src, target) {
                span_lint(cx, STRING_ADD_ASSIGN, e.span,
                    "you assign the result of adding something to this string. \
                    Consider using `String::push_str()` instead")
            }
        }
    }
}

fn is_string(cx: &Context, e: &Expr) -> bool {
    let ty = walk_ptrs_ty(cx.tcx.expr_ty(e));
    if let TyStruct(did, _) = ty.sty {
        match_def_path(cx, did.did, &["collections", "string", "String"])
    } else { false }
}

fn is_add(src: &Expr, target: &Expr) -> bool {
    match &src.node {
        &ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) =>
            is_exp_equal(target, left),
        &ExprBlock(ref block) => block.stmts.is_empty() &&
            block.expr.as_ref().map_or(false, |expr| is_add(&*expr, target)),
        &ExprParen(ref expr) => is_add(&*expr, target),
        _ => false
    }
}
<commit_msg>grammar<commit_after>//! This LintPass catches both string addition and string addition + assignment
//!
//! Note that since we have two lints where one subsumes the other, we try to
//! disable the subsumed lint unless it has a higher level

use rustc::lint::*;
use rustc::middle::ty::TypeVariants::TyStruct;
use syntax::ast::*;
use syntax::codemap::{Span, Spanned};
use eq_op::is_exp_equal;
use types::match_ty_unwrap;
use utils::{match_def_path, span_lint, walk_ptrs_ty, get_parent_expr};

declare_lint! {
    pub STRING_ADD_ASSIGN,
    Allow,
    "expressions of the form `x = x + ..` where x is a `String`"
}

declare_lint! {
    pub STRING_ADD,
    Allow,
    "expressions of the form on `x + ..` where x is a `String`"
}

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

impl LintPass for StringAdd {
    fn get_lints(&self) -> LintArray {
        lint_array!(STRING_ADD, STRING_ADD_ASSIGN)
    }

    fn check_expr(&mut self, cx: &Context, e: &Expr) {
        if let &ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) = &e.node {
            if is_string(cx, left) {
                if let Allow = cx.current_level(STRING_ADD_ASSIGN) {
                    // the string_add_assign is allow, so no duplicates
                } else {
                    let parent = get_parent_expr(cx, e);
                    if let Some(ref p) = parent {
                        if let &ExprAssign(ref target, _) = &p.node {
                            // avoid duplicate matches
                            if is_exp_equal(target, left) { return; }
                        }
                    }
                }
                //TODO check for duplicates
                 span_lint(cx, STRING_ADD, e.span,
                        "you added something to a string. \
                        Consider using `String::push_str()` instead.")
            }
        } else if let &ExprAssign(ref target, ref  src) = &e.node {
            if is_string(cx, target) && is_add(src, target) {
                span_lint(cx, STRING_ADD_ASSIGN, e.span,
                    "you assigned the result of adding something to this string. \
                    Consider using `String::push_str()` instead.")
            }
        }
    }
}

fn is_string(cx: &Context, e: &Expr) -> bool {
    let ty = walk_ptrs_ty(cx.tcx.expr_ty(e));
    if let TyStruct(did, _) = ty.sty {
        match_def_path(cx, did.did, &["collections", "string", "String"])
    } else { false }
}

fn is_add(src: &Expr, target: &Expr) -> bool {
    match &src.node {
        &ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) =>
            is_exp_equal(target, left),
        &ExprBlock(ref block) => block.stmts.is_empty() &&
            block.expr.as_ref().map_or(false, |expr| is_add(&*expr, target)),
        &ExprParen(ref expr) => is_add(&*expr, target),
        _ => false
    }
}
<|endoftext|>


<commit_before>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::mem;
use libc::{c_void, c_uint};

#[cfg(any(target_os = "macos", target_os = "ios"))]
use ffi::enums::Format;
#[cfg(any(target_os = "macos", target_os = "ios"))]
use ffi::CGContextRef;

#[cfg(feature = "glib")]
use glib::translate::*;
use ffi;
use ffi::enums::{
    Content,
    Status,
    SurfaceType,
};

#[derive(Debug)]
pub struct Surface(*mut ffi::cairo_surface_t);

impl Surface {
    #[doc(hidden)]
    pub unsafe fn from_raw_none(ptr: *mut ffi::cairo_surface_t) -> Surface {
        assert!(!ptr.is_null());
        ffi::cairo_surface_reference(ptr);
        Surface(ptr)
    }

    #[doc(hidden)]
    pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_surface_t) -> Surface {
        assert!(!ptr.is_null());
        Surface(ptr)
    }

    #[doc(hidden)]
    pub fn to_raw_none(&self) -> *mut ffi::cairo_surface_t {
        self.0
    }

    pub fn status(&self) -> Status {
        unsafe { ffi::cairo_surface_status(self.0) }
    }

    pub fn create_similar(&self, content: Content, width: i32, height: i32) -> Surface {
        unsafe { Self::from_raw_full(ffi::cairo_surface_create_similar(self.0, content, width, height)) }
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    pub fn quartz_create(format: Format, width: u32, height: u32) -> Surface {
        unsafe { Self::from_raw_full(ffi::cairo_quartz_surface_create(format, width, height)) }
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    pub fn quartz_create_for_cg_context(cg_context: CGContextRef, width: c_uint, height: c_uint) -> Surface {
        unsafe { Self::from_raw_full(ffi::cairo_quartz_surface_create_for_cg_context(cg_context, width, height)) }
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    pub fn quartz_get_cg_context(&self) -> CGContextRef {
        unsafe { ffi::cairo_quartz_surface_get_cg_context(self.to_raw_none()) }
    }
}

#[cfg(feature = "glib")]
impl<'a> ToGlibPtr<'a, *mut ffi::cairo_surface_t> for Surface {
    type Storage = &'a Surface;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::cairo_surface_t, Self> {
        Stash(self.to_raw_none(), self)
    }
}

#[cfg(feature = "glib")]
impl FromGlibPtrNone<*mut ffi::cairo_surface_t> for Surface {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut ffi::cairo_surface_t) -> Surface {
        Self::from_raw_none(ptr)
    }
}

#[cfg(feature = "glib")]
impl FromGlibPtrFull<*mut ffi::cairo_surface_t> for Surface {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut ffi::cairo_surface_t) -> Surface {
        Self::from_raw_full(ptr)
    }
}

impl AsRef<Surface> for Surface {
    fn as_ref(&self) -> &Surface {
        self
    }
}

impl Clone for Surface {
    fn clone(&self) -> Surface {
        unsafe { Self::from_raw_none(self.0) }
    }
}

impl Drop for Surface {
    fn drop(&mut self) {
        unsafe { ffi::cairo_surface_destroy(self.0); }
    }
}

pub trait SurfaceExt {
    fn flush(&self);
    fn finish(&self);
    fn get_type(&self) -> SurfaceType;
}

impl<O: AsRef<Surface>> SurfaceExt for O {
    fn flush(&self) {
        unsafe { ffi::cairo_surface_flush(self.as_ref().0); }
    }

    fn finish(&self) {
        unsafe { ffi::cairo_surface_finish(self.as_ref().0); }
    }

    fn get_type(&self) -> SurfaceType {
        unsafe { ffi::cairo_surface_get_type(self.as_ref().0) }
    }
}

pub trait SurfacePriv {
    unsafe fn set_user_data<K, T>(&self, key: &K, data: Box<T>) -> Result<(), Status>;
}

impl<O: AsRef<Surface>> SurfacePriv for O {
    unsafe fn set_user_data<K, T>(&self, key: &K, data: Box<T>) -> Result<(), Status> {
        let status = ffi::cairo_surface_set_user_data(self.as_ref().0, mem::transmute(key),
            mem::transmute(data), Some(unbox::<T>));
        match status {
            Status::Success => Ok(()),
            x => Err(x),
        }
    }
}

unsafe extern fn unbox<T>(data: *mut c_void) {
    let data: Box<T> = mem::transmute(data);
    drop(data);
}
<commit_msg>Replace `c_uint` with `u32` in surface<commit_after>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::mem;
use libc::c_void;

#[cfg(any(target_os = "macos", target_os = "ios"))]
use ffi::enums::Format;
#[cfg(any(target_os = "macos", target_os = "ios"))]
use ffi::CGContextRef;

#[cfg(feature = "glib")]
use glib::translate::*;
use ffi;
use ffi::enums::{
    Content,
    Status,
    SurfaceType,
};

#[derive(Debug)]
pub struct Surface(*mut ffi::cairo_surface_t);

impl Surface {
    #[doc(hidden)]
    pub unsafe fn from_raw_none(ptr: *mut ffi::cairo_surface_t) -> Surface {
        assert!(!ptr.is_null());
        ffi::cairo_surface_reference(ptr);
        Surface(ptr)
    }

    #[doc(hidden)]
    pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_surface_t) -> Surface {
        assert!(!ptr.is_null());
        Surface(ptr)
    }

    #[doc(hidden)]
    pub fn to_raw_none(&self) -> *mut ffi::cairo_surface_t {
        self.0
    }

    pub fn status(&self) -> Status {
        unsafe { ffi::cairo_surface_status(self.0) }
    }

    pub fn create_similar(&self, content: Content, width: i32, height: i32) -> Surface {
        unsafe { Self::from_raw_full(ffi::cairo_surface_create_similar(self.0, content, width, height)) }
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    pub fn quartz_create(format: Format, width: u32, height: u32) -> Surface {
        unsafe { Self::from_raw_full(ffi::cairo_quartz_surface_create(format, width, height)) }
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    pub fn quartz_create_for_cg_context(cg_context: CGContextRef, width: u32, height: u32) -> Surface {
        unsafe { Self::from_raw_full(ffi::cairo_quartz_surface_create_for_cg_context(cg_context, width, height)) }
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    pub fn quartz_get_cg_context(&self) -> CGContextRef {
        unsafe { ffi::cairo_quartz_surface_get_cg_context(self.to_raw_none()) }
    }
}

#[cfg(feature = "glib")]
impl<'a> ToGlibPtr<'a, *mut ffi::cairo_surface_t> for Surface {
    type Storage = &'a Surface;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::cairo_surface_t, Self> {
        Stash(self.to_raw_none(), self)
    }
}

#[cfg(feature = "glib")]
impl FromGlibPtrNone<*mut ffi::cairo_surface_t> for Surface {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut ffi::cairo_surface_t) -> Surface {
        Self::from_raw_none(ptr)
    }
}

#[cfg(feature = "glib")]
impl FromGlibPtrFull<*mut ffi::cairo_surface_t> for Surface {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut ffi::cairo_surface_t) -> Surface {
        Self::from_raw_full(ptr)
    }
}

impl AsRef<Surface> for Surface {
    fn as_ref(&self) -> &Surface {
        self
    }
}

impl Clone for Surface {
    fn clone(&self) -> Surface {
        unsafe { Self::from_raw_none(self.0) }
    }
}

impl Drop for Surface {
    fn drop(&mut self) {
        unsafe { ffi::cairo_surface_destroy(self.0); }
    }
}

pub trait SurfaceExt {
    fn flush(&self);
    fn finish(&self);
    fn get_type(&self) -> SurfaceType;
}

impl<O: AsRef<Surface>> SurfaceExt for O {
    fn flush(&self) {
        unsafe { ffi::cairo_surface_flush(self.as_ref().0); }
    }

    fn finish(&self) {
        unsafe { ffi::cairo_surface_finish(self.as_ref().0); }
    }

    fn get_type(&self) -> SurfaceType {
        unsafe { ffi::cairo_surface_get_type(self.as_ref().0) }
    }
}

pub trait SurfacePriv {
    unsafe fn set_user_data<K, T>(&self, key: &K, data: Box<T>) -> Result<(), Status>;
}

impl<O: AsRef<Surface>> SurfacePriv for O {
    unsafe fn set_user_data<K, T>(&self, key: &K, data: Box<T>) -> Result<(), Status> {
        let status = ffi::cairo_surface_set_user_data(self.as_ref().0, mem::transmute(key),
            mem::transmute(data), Some(unbox::<T>));
        match status {
            Status::Success => Ok(()),
            x => Err(x),
        }
    }
}

unsafe extern "C" fn unbox<T>(data: *mut c_void) {
    let data: Box<T> = mem::transmute(data);
    drop(data);
}
<|endoftext|>


<commit_before>pub mod block {
    pub const FULL: &str = "█";
    pub const SEVEN_EIGHTHS: &str = "▉";
    pub const THREE_QUARTERS: &str = "▊";
    pub const FIVE_EIGHTHS: &str = "▋";
    pub const HALF: &str = "▌";
    pub const THREE_EIGHTHS: &str = "▍";
    pub const ONE_QUARTER: &str = "▎";
    pub const ONE_EIGHTH: &str = "▏";
}

pub mod bar {
    pub const FULL: &str = "█";
    pub const SEVEN_EIGHTHS: &str = "▇";
    pub const THREE_QUARTERS: &str = "▆";
    pub const FIVE_EIGHTHS: &str = "▅";
    pub const HALF: &str = "▄";
    pub const THREE_EIGHTHS: &str = "▃";
    pub const ONE_QUARTER: &str = "▂";
    pub const ONE_EIGHTH: &str = "▁";
}

pub mod line {
    pub const TOP_RIGHT: &str = "┐";
    pub const VERTICAL: &str = "│";
    pub const HORIZONTAL: &str = "─";
    pub const TOP_LEFT: &str = "┌";
    pub const BOTTOM_RIGHT: &str = "┘";
    pub const BOTTOM_LEFT: &str = "└";
    pub const VERTICAL_LEFT: &str = "┤";
    pub const VERTICAL_RIGHT: &str = "├";
    pub const HORIZONTAL_DOWN: &str = "┬";
    pub const HORIZONTAL_UP: &str = "┴";
    pub const CROSS: &str = "┼";
}

pub const DOT: &str = "•";
<commit_msg>add round corners and double lines to symbols<commit_after>pub mod block {
    pub const FULL: &str = "█";
    pub const SEVEN_EIGHTHS: &str = "▉";
    pub const THREE_QUARTERS: &str = "▊";
    pub const FIVE_EIGHTHS: &str = "▋";
    pub const HALF: &str = "▌";
    pub const THREE_EIGHTHS: &str = "▍";
    pub const ONE_QUARTER: &str = "▎";
    pub const ONE_EIGHTH: &str = "▏";
}

pub mod bar {
    pub const FULL: &str = "█";
    pub const SEVEN_EIGHTHS: &str = "▇";
    pub const THREE_QUARTERS: &str = "▆";
    pub const FIVE_EIGHTHS: &str = "▅";
    pub const HALF: &str = "▄";
    pub const THREE_EIGHTHS: &str = "▃";
    pub const ONE_QUARTER: &str = "▂";
    pub const ONE_EIGHTH: &str = "▁";
}

pub mod line {
    pub const TOP_RIGHT: &str = "┐";
    pub const VERTICAL: &str = "│";
    pub const HORIZONTAL: &str = "─";
    pub const TOP_LEFT: &str = "┌";
    pub const BOTTOM_RIGHT: &str = "┘";
    pub const BOTTOM_LEFT: &str = "└";
    pub const VERTICAL_LEFT: &str = "┤";
    pub const VERTICAL_RIGHT: &str = "├";
    pub const HORIZONTAL_DOWN: &str = "┬";
    pub const HORIZONTAL_UP: &str = "┴";
    pub const CROSS: &str = "┼";
}

pub const DOT: &str = "•";

pub mod rounded {
    pub const TOP_RIGHT: &str = "╮";
    pub const TOP_LEFT: &str = "╭";
    pub const BOTTOM_RIGHT: &str = "╯";
    pub const BOTTOM_LEFT: &str = "╰";
}

pub mod double {
    pub const VERTICAL: &str = "║";
    pub const HORIZONTAL: &str = "═";
    pub const TOP_RIGHT: &str = "╗";
    pub const TOP_LEFT: &str = "╔";
    pub const BOTTOM_RIGHT: &str = "╝";
    pub const BOTTOM_LEFT: &str = "╚";
    pub const VERTICAL_LEFT: &str = "╣";
    pub const VERTICAL_RIGHT: &str = "╠";
    pub const HORIZONTAL_DOWN: &str = "╦";
    pub const HORIZONTAL_UP: &str = "╩";
}
<|endoftext|>


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

use std::sync::mpsc;
use std::sync::{Arc, Mutex, Condvar};
use std::collections::hash_map::HashMap;
use std::cell::{RefCell};
use std::io::{Error, ErrorKind};
use std::slice;
use std::fmt::{self, Debug, Formatter};
use std::cmp::{PartialEq};
use std::ops::Deref;
use std::mem;

use uuid::Uuid;

struct ServerRecord {
    sender: MpscSender,
    conn_sender: mpsc::Sender<bool>,
    conn_receiver: Mutex<mpsc::Receiver<bool>>,
}

impl ServerRecord {
    fn new(sender: MpscSender) -> ServerRecord {
        let (tx, rx) = mpsc::channel::<bool>();
        ServerRecord {
            sender: sender,
            conn_sender: tx,
            conn_receiver: Mutex::new(rx),
        }
    }

    fn accept(&self) {
        self.conn_receiver.lock().unwrap().recv().unwrap();
    }

    fn connect(&self) {
        self.conn_sender.send(true).unwrap();
    }
}

lazy_static! {
    static ref ONE_SHOT_SERVERS: Mutex<HashMap<String,ServerRecord>> = Mutex::new(HashMap::new());
}

struct MpscChannelMessage(Vec<u8>, Vec<MpscChannel>, Vec<MpscSharedMemory>);

pub fn channel() -> Result<(MpscSender, MpscReceiver),MpscError> {
    let (base_sender, base_receiver) = mpsc::channel::<MpscChannelMessage>();
    Ok((MpscSender::new(base_sender), MpscReceiver::new(base_receiver)))
}

pub struct MpscReceiver {
    receiver: RefCell<Option<mpsc::Receiver<MpscChannelMessage>>>,
}

impl MpscReceiver {
    fn new(receiver: mpsc::Receiver<MpscChannelMessage>) -> MpscReceiver {
        MpscReceiver {
            receiver: RefCell::new(Some(receiver)),
        }
    }

    pub fn consume(&self) -> MpscReceiver {
        let receiver = self.receiver.borrow_mut().take();
        MpscReceiver::new(receiver.unwrap())
    }

    pub fn recv(&self) -> Result<(Vec<u8>, Vec<OpaqueMpscChannel>, Vec<MpscSharedMemory>),MpscError> {
        let r = self.receiver.borrow();
        match r.as_ref().unwrap().recv() {
            Ok(MpscChannelMessage(d,c,s)) => Ok((d,
                                                 c.into_iter().map(OpaqueMpscChannel::new).collect(),
                                                 s)),
            Err(_) => Err(MpscError::ChannelClosedError),
        }
    }

    pub fn try_recv(&self) -> Result<(Vec<u8>, Vec<OpaqueMpscChannel>, Vec<MpscSharedMemory>),MpscError> {
        let r = self.receiver.borrow();
        match r.as_ref().unwrap().try_recv() {
            Ok(MpscChannelMessage(d,c,s)) => Ok((d,
                                                 c.into_iter().map(OpaqueMpscChannel::new).collect(),
                                                 s)),
            Err(_) => Err(MpscError::ChannelClosedError),
        }
    }
}

unsafe impl Send for MpscReceiver { }
unsafe impl Sync for MpscReceiver { }

#[derive(Clone)]
pub struct MpscSender {
    sender: RefCell<mpsc::Sender<MpscChannelMessage>>,
}

unsafe impl Send for MpscSender { }
unsafe impl Sync for MpscSender { }

impl MpscSender {
    fn new(sender: mpsc::Sender<MpscChannelMessage>) -> MpscSender {
        MpscSender {
            sender: RefCell::new(sender),
        }
    }

    pub fn connect(name: String) -> Result<MpscSender,MpscError> {
        let record = ONE_SHOT_SERVERS.lock().unwrap().remove(&name).unwrap();
        record.connect();
        Ok(record.sender)
    }

    pub fn send(&self,
                data: &[u8],
                ports: Vec<MpscChannel>,
                shared_memory_regions: Vec<MpscSharedMemory>)
                -> Result<(),MpscError>
    {
        match self.sender.borrow().send(MpscChannelMessage(data.to_vec(), ports, shared_memory_regions)) {
            Err(_) => Err(MpscError::ChannelClosedError),
            Ok(_) => Ok(()),
        }
    }
}

pub struct MpscReceiverSet {
    last_index: usize,
    receiver_ids: Vec<usize>,
    receivers: Vec<MpscReceiver>,
}

impl MpscReceiverSet {
    pub fn new() -> Result<MpscReceiverSet,MpscError> {
        Ok(MpscReceiverSet {
            last_index: 0,
            receiver_ids: vec![],
            receivers: vec![],
        })
    }

    pub fn add(&mut self, receiver: MpscReceiver) -> Result<i64,MpscError> {
        self.last_index += 1;
        self.receiver_ids.push(self.last_index);
        self.receivers.push(receiver.consume());
        Ok(self.last_index as i64)
    }

    pub fn select(&mut self) -> Result<Vec<MpscSelectionResult>,MpscError> {
        let mut receivers: Vec<Option<mpsc::Receiver<MpscChannelMessage>>> = Vec::with_capacity(self.receivers.len());
        let mut r_id: i64 = -1;
        let mut r_index: usize = 0;

        {
            let select = mpsc::Select::new();
            // we *must* allocate exact capacity for this, because the Handles *can't move*
            let mut handles: Vec<mpsc::Handle<MpscChannelMessage>> = Vec::with_capacity(self.receivers.len());

            for r in &self.receivers {
                let inner_r = mem::replace(&mut *r.receiver.borrow_mut(), None);
                receivers.push(inner_r);
            }

            for r in &receivers {
                unsafe {
                    handles.push(select.handle(r.as_ref().unwrap()));
                    handles.last_mut().unwrap().add();
                }
            }

            let id = select.wait();

            for (index,h) in handles.iter().enumerate() {
                if h.id() == id {
                    r_index = index;
                    r_id = self.receiver_ids[index] as i64;
                    break;
                }
            }
        }

        // put the receivers back
        for (index,r) in self.receivers.iter().enumerate() {
            mem::replace(&mut *r.receiver.borrow_mut(), mem::replace(&mut receivers[index], None));
        }

        if r_id == -1 {
            return Err(MpscError::UnknownError);
        }

        let receivers = &mut self.receivers;
        match receivers[r_index].recv() {
            Ok((data, channels, shmems)) =>
                Ok(vec![MpscSelectionResult::DataReceived(r_id, data, channels, shmems)]),
            Err(MpscError::ChannelClosedError) => {
                receivers.remove(r_index);
                self.receiver_ids.remove(r_index);
                Ok(vec![MpscSelectionResult::ChannelClosed(r_id)])
            },
            Err(err) => Err(err),
        }
    }
}

pub enum MpscSelectionResult {
    DataReceived(i64, Vec<u8>, Vec<OpaqueMpscChannel>, Vec<MpscSharedMemory>),
    ChannelClosed(i64),
}

pub struct MpscOneShotServer {
    receiver: RefCell<Option<MpscReceiver>>,
    name: String,
}

impl MpscOneShotServer {
    pub fn new() -> Result<(MpscOneShotServer, String),MpscError> {
        let (sender, receiver) = match channel() {
            Ok((s,r)) => (s,r),
            Err(err) => return Err(err),
        };

        let name = Uuid::new_v4().to_string();
        let record = ServerRecord::new(sender);
        ONE_SHOT_SERVERS.lock().unwrap().insert(name.clone(), record);
        Ok((MpscOneShotServer {
            receiver: RefCell::new(Some(receiver)),
            name: name.clone(),
        },name.clone()))
    }

    pub fn accept(&self) -> Result<(MpscReceiver,
                                    Vec<u8>,
                                    Vec<OpaqueMpscChannel>,
                                    Vec<MpscSharedMemory>),MpscError>
    {
        ONE_SHOT_SERVERS.lock().unwrap().get(&self.name).unwrap().accept();
        let receiver = self.receiver.borrow_mut().take().unwrap();
        let (data, channels, shmems) = receiver.recv().unwrap();
        Ok((receiver, data, channels, shmems))
    }
}

pub enum MpscChannel {
    Sender(MpscSender),
    Receiver(MpscReceiver),
}

pub struct OpaqueMpscChannel {
    channel: RefCell<Option<MpscChannel>>,
}

impl OpaqueMpscChannel {
    fn new(channel: MpscChannel) -> OpaqueMpscChannel {
        OpaqueMpscChannel {
            channel: RefCell::new(Some(channel))
        }
    }

    pub fn to_receiver(&self) -> MpscReceiver {
        match self.channel.borrow_mut().take().unwrap() {
            MpscChannel::Sender(_) => panic!("Opaque channel is not a receiver!"),
            MpscChannel::Receiver(r) => r
        }
    }

    pub fn to_sender(&self) -> MpscSender {
        match self.channel.borrow_mut().take().unwrap() {
            MpscChannel::Sender(s) => s,
            MpscChannel::Receiver(_) => panic!("Opaque channel is not a sender!"),
        }
    }
}

pub struct MpscSharedMemory {
    ptr: *mut u8,
    length: usize,
    data: Arc<Vec<u8>>,
}

unsafe impl Send for MpscSharedMemory {}
unsafe impl Sync for MpscSharedMemory {}

impl Clone for MpscSharedMemory {
    fn clone(&self) -> MpscSharedMemory {
        MpscSharedMemory {
            ptr: self.ptr,
            length: self.length,
            data: self.data.clone(),
        }
    }
}

impl PartialEq for MpscSharedMemory {
    fn eq(&self, other: &MpscSharedMemory) -> bool {
        **self == **other
    }
}

impl Debug for MpscSharedMemory {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> {
        (**self).fmt(formatter)
    }
}

impl Deref for MpscSharedMemory {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &[u8] {
        if self.ptr.is_null() {
            panic!("attempted to access a consumed `MpscSharedMemory`")
        }
        unsafe {
            slice::from_raw_parts(self.ptr, self.length)
        }
    }
}

impl MpscSharedMemory {
    pub fn from_byte(byte: u8, length: usize) -> MpscSharedMemory {
        let mut v = Arc::new(vec![byte; length]);
        MpscSharedMemory {
            ptr: Arc::get_mut(&mut v).unwrap().as_mut_ptr(),
            length: length,
            data: v
        }
    }

    pub fn from_bytes(bytes: &[u8]) -> MpscSharedMemory {
        let mut v = Arc::new(bytes.to_vec());
        MpscSharedMemory {
            ptr: Arc::get_mut(&mut v).unwrap().as_mut_ptr(),
            length: v.len(),
            data: v
        }
    }
}

#[derive(Debug)]
pub enum MpscError {
    ChannelClosedError,
    UnknownError,
}

impl From<MpscError> for Error {
    fn from(mpsc_error: MpscError) -> Error {
        match mpsc_error {
            MpscError::ChannelClosedError => {
                Error::new(ErrorKind::BrokenPipe, "MPSC channel closed")
            }
            MpscError::UnknownError => Error::new(ErrorKind::Other, "Other MPSC channel error"),
        }
    }
}

<commit_msg>Fix: Provide dummy Debug impls for platform::inprocess::{MpscSender, MpscReceiver}<commit_after>// Copyright 2015 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::sync::mpsc;
use std::sync::{Arc, Mutex, Condvar};
use std::collections::hash_map::HashMap;
use std::cell::{RefCell};
use std::io::{Error, ErrorKind};
use std::slice;
use std::fmt::{self, Debug, Formatter};
use std::cmp::{PartialEq};
use std::ops::Deref;
use std::mem;

use uuid::Uuid;

struct ServerRecord {
    sender: MpscSender,
    conn_sender: mpsc::Sender<bool>,
    conn_receiver: Mutex<mpsc::Receiver<bool>>,
}

impl ServerRecord {
    fn new(sender: MpscSender) -> ServerRecord {
        let (tx, rx) = mpsc::channel::<bool>();
        ServerRecord {
            sender: sender,
            conn_sender: tx,
            conn_receiver: Mutex::new(rx),
        }
    }

    fn accept(&self) {
        self.conn_receiver.lock().unwrap().recv().unwrap();
    }

    fn connect(&self) {
        self.conn_sender.send(true).unwrap();
    }
}

lazy_static! {
    static ref ONE_SHOT_SERVERS: Mutex<HashMap<String,ServerRecord>> = Mutex::new(HashMap::new());
}

struct MpscChannelMessage(Vec<u8>, Vec<MpscChannel>, Vec<MpscSharedMemory>);

pub fn channel() -> Result<(MpscSender, MpscReceiver),MpscError> {
    let (base_sender, base_receiver) = mpsc::channel::<MpscChannelMessage>();
    Ok((MpscSender::new(base_sender), MpscReceiver::new(base_receiver)))
}

pub struct MpscReceiver {
    receiver: RefCell<Option<mpsc::Receiver<MpscChannelMessage>>>,
}

// Can't derive, as mpsc::Receiver doesn't implement Debug.
impl fmt::Debug for MpscReceiver {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Not sure there is anything useful we could print here.
        write!(f, "MpscReceiver {{ .. }}")
    }
}

impl MpscReceiver {
    fn new(receiver: mpsc::Receiver<MpscChannelMessage>) -> MpscReceiver {
        MpscReceiver {
            receiver: RefCell::new(Some(receiver)),
        }
    }

    pub fn consume(&self) -> MpscReceiver {
        let receiver = self.receiver.borrow_mut().take();
        MpscReceiver::new(receiver.unwrap())
    }

    pub fn recv(&self) -> Result<(Vec<u8>, Vec<OpaqueMpscChannel>, Vec<MpscSharedMemory>),MpscError> {
        let r = self.receiver.borrow();
        match r.as_ref().unwrap().recv() {
            Ok(MpscChannelMessage(d,c,s)) => Ok((d,
                                                 c.into_iter().map(OpaqueMpscChannel::new).collect(),
                                                 s)),
            Err(_) => Err(MpscError::ChannelClosedError),
        }
    }

    pub fn try_recv(&self) -> Result<(Vec<u8>, Vec<OpaqueMpscChannel>, Vec<MpscSharedMemory>),MpscError> {
        let r = self.receiver.borrow();
        match r.as_ref().unwrap().try_recv() {
            Ok(MpscChannelMessage(d,c,s)) => Ok((d,
                                                 c.into_iter().map(OpaqueMpscChannel::new).collect(),
                                                 s)),
            Err(_) => Err(MpscError::ChannelClosedError),
        }
    }
}

unsafe impl Send for MpscReceiver { }
unsafe impl Sync for MpscReceiver { }

#[derive(Clone)]
pub struct MpscSender {
    sender: RefCell<mpsc::Sender<MpscChannelMessage>>,
}

// Can't derive, as mpsc::Sender doesn't implement Debug.
impl fmt::Debug for MpscSender {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Not sure there is anything useful we could print here.
        write!(f, "MpscSender {{ .. }}")
    }
}

unsafe impl Send for MpscSender { }
unsafe impl Sync for MpscSender { }

impl MpscSender {
    fn new(sender: mpsc::Sender<MpscChannelMessage>) -> MpscSender {
        MpscSender {
            sender: RefCell::new(sender),
        }
    }

    pub fn connect(name: String) -> Result<MpscSender,MpscError> {
        let record = ONE_SHOT_SERVERS.lock().unwrap().remove(&name).unwrap();
        record.connect();
        Ok(record.sender)
    }

    pub fn send(&self,
                data: &[u8],
                ports: Vec<MpscChannel>,
                shared_memory_regions: Vec<MpscSharedMemory>)
                -> Result<(),MpscError>
    {
        match self.sender.borrow().send(MpscChannelMessage(data.to_vec(), ports, shared_memory_regions)) {
            Err(_) => Err(MpscError::ChannelClosedError),
            Ok(_) => Ok(()),
        }
    }
}

pub struct MpscReceiverSet {
    last_index: usize,
    receiver_ids: Vec<usize>,
    receivers: Vec<MpscReceiver>,
}

impl MpscReceiverSet {
    pub fn new() -> Result<MpscReceiverSet,MpscError> {
        Ok(MpscReceiverSet {
            last_index: 0,
            receiver_ids: vec![],
            receivers: vec![],
        })
    }

    pub fn add(&mut self, receiver: MpscReceiver) -> Result<i64,MpscError> {
        self.last_index += 1;
        self.receiver_ids.push(self.last_index);
        self.receivers.push(receiver.consume());
        Ok(self.last_index as i64)
    }

    pub fn select(&mut self) -> Result<Vec<MpscSelectionResult>,MpscError> {
        let mut receivers: Vec<Option<mpsc::Receiver<MpscChannelMessage>>> = Vec::with_capacity(self.receivers.len());
        let mut r_id: i64 = -1;
        let mut r_index: usize = 0;

        {
            let select = mpsc::Select::new();
            // we *must* allocate exact capacity for this, because the Handles *can't move*
            let mut handles: Vec<mpsc::Handle<MpscChannelMessage>> = Vec::with_capacity(self.receivers.len());

            for r in &self.receivers {
                let inner_r = mem::replace(&mut *r.receiver.borrow_mut(), None);
                receivers.push(inner_r);
            }

            for r in &receivers {
                unsafe {
                    handles.push(select.handle(r.as_ref().unwrap()));
                    handles.last_mut().unwrap().add();
                }
            }

            let id = select.wait();

            for (index,h) in handles.iter().enumerate() {
                if h.id() == id {
                    r_index = index;
                    r_id = self.receiver_ids[index] as i64;
                    break;
                }
            }
        }

        // put the receivers back
        for (index,r) in self.receivers.iter().enumerate() {
            mem::replace(&mut *r.receiver.borrow_mut(), mem::replace(&mut receivers[index], None));
        }

        if r_id == -1 {
            return Err(MpscError::UnknownError);
        }

        let receivers = &mut self.receivers;
        match receivers[r_index].recv() {
            Ok((data, channels, shmems)) =>
                Ok(vec![MpscSelectionResult::DataReceived(r_id, data, channels, shmems)]),
            Err(MpscError::ChannelClosedError) => {
                receivers.remove(r_index);
                self.receiver_ids.remove(r_index);
                Ok(vec![MpscSelectionResult::ChannelClosed(r_id)])
            },
            Err(err) => Err(err),
        }
    }
}

pub enum MpscSelectionResult {
    DataReceived(i64, Vec<u8>, Vec<OpaqueMpscChannel>, Vec<MpscSharedMemory>),
    ChannelClosed(i64),
}

pub struct MpscOneShotServer {
    receiver: RefCell<Option<MpscReceiver>>,
    name: String,
}

impl MpscOneShotServer {
    pub fn new() -> Result<(MpscOneShotServer, String),MpscError> {
        let (sender, receiver) = match channel() {
            Ok((s,r)) => (s,r),
            Err(err) => return Err(err),
        };

        let name = Uuid::new_v4().to_string();
        let record = ServerRecord::new(sender);
        ONE_SHOT_SERVERS.lock().unwrap().insert(name.clone(), record);
        Ok((MpscOneShotServer {
            receiver: RefCell::new(Some(receiver)),
            name: name.clone(),
        },name.clone()))
    }

    pub fn accept(&self) -> Result<(MpscReceiver,
                                    Vec<u8>,
                                    Vec<OpaqueMpscChannel>,
                                    Vec<MpscSharedMemory>),MpscError>
    {
        ONE_SHOT_SERVERS.lock().unwrap().get(&self.name).unwrap().accept();
        let receiver = self.receiver.borrow_mut().take().unwrap();
        let (data, channels, shmems) = receiver.recv().unwrap();
        Ok((receiver, data, channels, shmems))
    }
}

pub enum MpscChannel {
    Sender(MpscSender),
    Receiver(MpscReceiver),
}

pub struct OpaqueMpscChannel {
    channel: RefCell<Option<MpscChannel>>,
}

impl OpaqueMpscChannel {
    fn new(channel: MpscChannel) -> OpaqueMpscChannel {
        OpaqueMpscChannel {
            channel: RefCell::new(Some(channel))
        }
    }

    pub fn to_receiver(&self) -> MpscReceiver {
        match self.channel.borrow_mut().take().unwrap() {
            MpscChannel::Sender(_) => panic!("Opaque channel is not a receiver!"),
            MpscChannel::Receiver(r) => r
        }
    }

    pub fn to_sender(&self) -> MpscSender {
        match self.channel.borrow_mut().take().unwrap() {
            MpscChannel::Sender(s) => s,
            MpscChannel::Receiver(_) => panic!("Opaque channel is not a sender!"),
        }
    }
}

pub struct MpscSharedMemory {
    ptr: *mut u8,
    length: usize,
    data: Arc<Vec<u8>>,
}

unsafe impl Send for MpscSharedMemory {}
unsafe impl Sync for MpscSharedMemory {}

impl Clone for MpscSharedMemory {
    fn clone(&self) -> MpscSharedMemory {
        MpscSharedMemory {
            ptr: self.ptr,
            length: self.length,
            data: self.data.clone(),
        }
    }
}

impl PartialEq for MpscSharedMemory {
    fn eq(&self, other: &MpscSharedMemory) -> bool {
        **self == **other
    }
}

impl Debug for MpscSharedMemory {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> {
        (**self).fmt(formatter)
    }
}

impl Deref for MpscSharedMemory {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &[u8] {
        if self.ptr.is_null() {
            panic!("attempted to access a consumed `MpscSharedMemory`")
        }
        unsafe {
            slice::from_raw_parts(self.ptr, self.length)
        }
    }
}

impl MpscSharedMemory {
    pub fn from_byte(byte: u8, length: usize) -> MpscSharedMemory {
        let mut v = Arc::new(vec![byte; length]);
        MpscSharedMemory {
            ptr: Arc::get_mut(&mut v).unwrap().as_mut_ptr(),
            length: length,
            data: v
        }
    }

    pub fn from_bytes(bytes: &[u8]) -> MpscSharedMemory {
        let mut v = Arc::new(bytes.to_vec());
        MpscSharedMemory {
            ptr: Arc::get_mut(&mut v).unwrap().as_mut_ptr(),
            length: v.len(),
            data: v
        }
    }
}

#[derive(Debug)]
pub enum MpscError {
    ChannelClosedError,
    UnknownError,
}

impl From<MpscError> for Error {
    fn from(mpsc_error: MpscError) -> Error {
        match mpsc_error {
            MpscError::ChannelClosedError => {
                Error::new(ErrorKind::BrokenPipe, "MPSC channel closed")
            }
            MpscError::UnknownError => Error::new(ErrorKind::Other, "Other MPSC channel error"),
        }
    }
}

<|endoftext|>


<commit_before>//! An adapter providing time-related services, such as the current
//! timestamp or the current time of day.

use foxbox_adapters::adapter::*;
use foxbox_taxonomy::api::{ Error, InternalError };
use foxbox_taxonomy::values::{ Range, TimeStamp, Type, ValDuration, Value };
use foxbox_taxonomy::services::*;
use foxbox_taxonomy::util::Id;

use transformable_channels::mpsc::*;

use std::collections::{ HashMap, HashSet };
use std::sync::Arc;

use chrono;
use chrono::*;
use timer;

static ADAPTER_NAME: &'static str = "Clock adapter (built-in)";
static ADAPTER_VENDOR: &'static str = "team@link.mozilla.org";
static ADAPTER_VERSION: [u32;4] = [0, 0, 0, 0];

#[derive(Clone)]
enum Op {
    Enter(Id<Getter>, Value),
    Exit(Id<Getter>, Value),
}

enum Movement { Enter, Exit }

pub struct Clock {
    /// Timer used to dispatch `register_watch` requests.
    timer: timer::Timer,
    getter_timestamp_id: Id<Getter>,
    getter_time_of_day_id: Id<Getter>,
}

/// A guard used to cancel watching for values.
struct Guard(Vec<timer::Guard>);
impl AdapterWatchGuard for Guard {
}

impl Clock {
    pub fn id() -> Id<AdapterId> {
        Id::new("clock@link.mozilla.org")
    }
    pub fn service_clock_id() -> Id<ServiceId> {
        Id::new("service:clock@link.mozilla.org")
    }
    pub fn getter_timestamp_id() -> Id<Getter> {
        Id::new("getter:timestamp.clock@link.mozilla.org")
    }
    pub fn getter_time_of_day_id() -> Id<Getter> {
        Id::new("getter:timeofday.clock@link.mozilla.org")
    }
}
impl Adapter for Clock {
    fn id(&self) -> Id<AdapterId> {
        Self::id()
    }

    fn name(&self) -> &str {
        ADAPTER_NAME
    }

    fn vendor(&self) -> &str {
        ADAPTER_VENDOR
    }

    fn version(&self) -> &[u32;4] {
        &ADAPTER_VERSION
    }

    fn fetch_values(&self, mut set: Vec<Id<Getter>>) -> ResultMap<Id<Getter>, Option<Value>, Error> {
        set.drain(..).map(|id| {
            if id == self.getter_timestamp_id {
                let date = TimeStamp::from_datetime(chrono::UTC::now());
                (id, Ok(Some(Value::TimeStamp(date))))
            } else if id == self.getter_time_of_day_id {
                use chrono::Timelike;
                let date = chrono::Local::now();
                let duration = chrono::Duration::seconds(date.num_seconds_from_midnight() as i64);
                (id, Ok(Some(Value::Duration(ValDuration::new(duration)))))
            } else {
                (id.clone(), Err(Error::InternalError(InternalError::NoSuchGetter(id))))
            }
        }).collect()
    }

    fn send_values(&self, mut values: HashMap<Id<Setter>, Value>) -> ResultMap<Id<Setter>, (), Error> {
        values.drain()
            .map(|(id, _)| {
                (id.clone(), Err(Error::InternalError(InternalError::NoSuchSetter(id))))
            })
            .collect()
    }

    fn register_watch(&self, mut watch: Vec<(Id<Getter>, Option<Range>)>,
        tx: Box<ExtSender<WatchEvent>>) ->
            ResultMap<Id<Getter>, Box<AdapterWatchGuard>, Error>
    {
        let tx = tx.map(|msg| {
            match msg {
                Op::Enter(id, value) => {
                    WatchEvent::Enter {
                        id: id,
                        value: value
                    }
                },
                Op::Exit(id, value) => {
                    WatchEvent::Exit {
                        id: id,
                        value: value
                    }
                },
            }
        });
        watch.drain(..).map(|(id, filter)| {
            (id.clone(), match filter {
                None => Err(Error::GetterRequiresThresholdForWatching(id)),
                Some(range) => self.aux_register_watch(&id, range, Box::new(tx.clone()))
            })
        }).collect()
    }
}

impl Clock {
    fn aux_register_watch(&self, id: &Id<Getter>, range: Range, tx: Box<ExtSender<Op>>)
        -> Result<Box<AdapterWatchGuard>, Error>
    {
        match () {
            _ if *id == self.getter_time_of_day_id => self.aux_register_watch_timeofday(id, range, tx),
            _ if *id == self.getter_timestamp_id => self.aux_register_watch_timestamp(id, range, tx),
            _ => Err(Error::GetterDoesNotSupportWatching(id.clone()))
        }
    }

    fn aux_register_watch_timeofday(&self, id: &Id<Getter>, range: Range, tx: Box<ExtSender<Op>>)
        -> Result<Box<AdapterWatchGuard>, Error>
    {
        use foxbox_taxonomy::values::Range::*;

        // Sanity checks
        let typ = try!(range.get_type().map_err(Error::TypeError));
        try!(Type::Duration.ensure_eq(&typ).map_err(Error::TypeError));

        // Now determine when to call the trigger. Repeat duration is always one day.
        let mut thresholds = match range {
            Leq (ref val) => {
                // Equivalent to BetweenEq { min: 0am, max: val }
                let ts = *try!(val.as_duration().map_err(Error::TypeError))
                    .as_duration();
                vec![(Movement::Enter, Duration::seconds(0)), (Movement::Exit, ts)]
            }
            Geq (ref val) => {
                // Equivalent to BetweenEq { min: val, max: 0am }
                let ts = *try!(val.as_duration().map_err(Error::TypeError))
                    .as_duration();
                vec![(Movement::Enter, ts), (Movement::Exit, Duration::days(1))]
            }
            BetweenEq { ref min, ref max } => {
                let ts_min = *try!(min.as_duration().map_err(Error::TypeError))
                    .as_duration();
                let ts_max = *try!(max.as_duration().map_err(Error::TypeError))
                    .as_duration();
                vec![(Movement::Enter, ts_min), (Movement::Exit, ts_max)]
            }
            OutOfStrict { ref min, ref max } => {
                // Equivalent to BetweenEq {min: 0am, max: min} and BetweenEq {min: max, max: 0am}
                let ts_min = *try!(min.as_duration().map_err(Error::TypeError))
                    .as_duration();
                let ts_max = *try!(max.as_duration().map_err(Error::TypeError))
                    .as_duration();
                vec![(Movement::Exit, ts_min), (Movement::Enter, ts_max)]
            }
            Eq (ref val) => {
                let ts = *try!(val.as_duration().map_err(Error::TypeError))
                    .as_duration();
                vec![(Movement::Enter, ts.clone()), (Movement::Exit, ts)]
            }
        };

        // Determine when the next timers needs to launch.
        let now = chrono::Local::now();
        let guards : Vec<timer::Guard> = thresholds.drain(..).filter_map(|(movement, threshold)| {
            let date = match Self::get_next_date(&now, threshold) {
                Err(_) => return None,
                Ok(date) => date,
            };
            let id = id.clone();
            let tx = tx.clone();
            let guard = self.timer.schedule(date, Some(Duration::days(1)), move || {
                let naive_time = chrono::Local::now().time();
                let duration = Duration::hours(naive_time.hour() as i64)
                    + Duration::minutes(naive_time.minute() as i64)
                    + Duration::seconds(naive_time.second() as i64);

                let event = match movement {
                    Movement::Enter => Op::Enter(id.clone(),
                        Value::Duration(ValDuration::new(duration))),
                    Movement::Exit => Op::Exit(id.clone(),
                        Value::Duration(ValDuration::new(duration))),
                };
                let _ = tx.send(event);
            });
            Some(guard)
        }).collect();
        Ok(Box::new(Guard(guards)))
    }

    fn get_next_date(now: &DateTime<Local>, time_of_day: Duration)
        -> Result<DateTime<Local>, Error>
    {
        match chrono::Local::today().and_time(NaiveTime::from_hms(0, 0, 0) + time_of_day) {
            None => Err(Error::InvalidValue(Value::Duration(ValDuration::new(time_of_day)))),
            Some(date) => {
                if date >= *now  {
                    Ok(date)
                } else {
                    // Otherwise, shift to tomorrow.
                    match date.checked_add(Duration::days(1)) {
                        None => Err(Error::InvalidValue(Value::Duration(ValDuration::new(time_of_day)))),
                        Some(date) => Ok(date)
                    }
                }
            }
        }
    }

    fn aux_register_watch_timestamp(&self, id: &Id<Getter>, range: Range, tx: Box<ExtSender<Op>>)
        -> Result<Box<AdapterWatchGuard>, Error>
    {
        use foxbox_taxonomy::values::Range::*;

        // Sanity checks
        let typ = try!(range.get_type().map_err(Error::TypeError));
        try!(Type::TimeStamp.ensure_eq(&typ).map_err(Error::TypeError));

        // Now determine when/if to call the trigger.
        let mut thresholds = match range {
            Leq (_) => {
                // This variant doesn't make sense.
                return Ok(Box::new(Guard(vec![])))
            }
            Geq (ref val) | Eq (ref val) => {
                let ts = *try!(val.as_timestamp().map_err(Error::TypeError))
                    .as_datetime();
                vec![(Movement::Enter, ts)]
            }
            OutOfStrict { ref min, ref max } => {
                let ts_min = *try!(min.as_timestamp().map_err(Error::TypeError))
                    .as_datetime();
                let ts_max = *try!(max.as_timestamp().map_err(Error::TypeError))
                    .as_datetime();
                vec![(Movement::Exit, ts_min), (Movement::Enter, ts_max)]
            }
            BetweenEq { ref min, ref max } => {
                let ts_min = *try!(min.as_timestamp().map_err(Error::TypeError))
                    .as_datetime();
                let ts_max = *try!(max.as_timestamp().map_err(Error::TypeError))
                    .as_datetime();
                vec![(Movement::Enter, ts_min), (Movement::Exit, ts_max)]
            }
        };

        // Determine when/if the next timers needs to launch.
        let now = chrono::UTC::now();
        let guards : Vec<timer::Guard> = thresholds.drain(..).filter_map(|(movement, date)| {
            if date < now {
                return None
            }
            let id = id.clone();
            let tx = tx.clone();
            let guard = self.timer.schedule_with_date(date, move || {
                let naive_time = chrono::Local::now().time();
                let duration = Duration::hours(naive_time.hour() as i64)
                    + Duration::minutes(naive_time.minute() as i64)
                    + Duration::seconds(naive_time.second() as i64);

                let event = match movement {
                    Movement::Enter => Op::Enter(id.clone(),
                        Value::Duration(ValDuration::new(duration))),
                    Movement::Exit => Op::Exit(id.clone(),
                        Value::Duration(ValDuration::new(duration))),
                };
                let _ = tx.send(event);
            });
            Some(guard)
        }).collect();
        Ok(Box::new(Guard(guards)))
    }
}

impl Clock {
    pub fn init<T>(adapt: &T) -> Result<(), Error>
        where T: AdapterManagerHandle
    {
        let getter_timestamp_id = Clock::getter_timestamp_id();
        let getter_time_of_day_id = Clock::getter_time_of_day_id();
        let service_clock_id = Clock::service_clock_id();
        let clock = Box::new(Clock {
            timer: timer::Timer::new(),
            getter_timestamp_id: getter_timestamp_id.clone(),
            getter_time_of_day_id: getter_time_of_day_id.clone(),
        });
        try!(adapt.add_adapter(clock));
        try!(adapt.add_service(Service::empty(Clock::service_clock_id(), Clock::id())));
        try!(adapt.add_getter(Channel {
                tags: HashSet::new(),
                adapter: Clock::id(),
                id: getter_time_of_day_id.clone(),
                last_seen: None,
                service: service_clock_id.clone(),
                mechanism: Getter {
                    kind: ChannelKind::CurrentTimeOfDay,
                    poll: Some(ValDuration::new(chrono::Duration::seconds(1))),
                    trigger: None,
                    watch: true,
                    updated: None
                }
        }));
        try!(adapt.add_getter(Channel {
                tags: HashSet::new(),
                adapter: Clock::id(),
                id: getter_timestamp_id.clone(),
                last_seen: None,
                service: service_clock_id.clone(),
                mechanism: Getter {
                    kind: ChannelKind::CurrentTime,
                    poll: Some(ValDuration::new(chrono::Duration::seconds(1))),
                    trigger: None,
                    watch: true,
                    updated: None
                }
        }));
        Ok(())
    }
}
<commit_msg>Remove unused import.<commit_after>//! An adapter providing time-related services, such as the current
//! timestamp or the current time of day.

use foxbox_adapters::adapter::*;
use foxbox_taxonomy::api::{ Error, InternalError };
use foxbox_taxonomy::values::{ Range, TimeStamp, Type, ValDuration, Value };
use foxbox_taxonomy::services::*;
use foxbox_taxonomy::util::Id;

use transformable_channels::mpsc::*;

use std::collections::{ HashMap, HashSet };

use chrono;
use chrono::*;
use timer;

static ADAPTER_NAME: &'static str = "Clock adapter (built-in)";
static ADAPTER_VENDOR: &'static str = "team@link.mozilla.org";
static ADAPTER_VERSION: [u32;4] = [0, 0, 0, 0];

#[derive(Clone)]
enum Op {
    Enter(Id<Getter>, Value),
    Exit(Id<Getter>, Value),
}

enum Movement { Enter, Exit }

pub struct Clock {
    /// Timer used to dispatch `register_watch` requests.
    timer: timer::Timer,
    getter_timestamp_id: Id<Getter>,
    getter_time_of_day_id: Id<Getter>,
}

/// A guard used to cancel watching for values.
struct Guard(Vec<timer::Guard>);
impl AdapterWatchGuard for Guard {
}

impl Clock {
    pub fn id() -> Id<AdapterId> {
        Id::new("clock@link.mozilla.org")
    }
    pub fn service_clock_id() -> Id<ServiceId> {
        Id::new("service:clock@link.mozilla.org")
    }
    pub fn getter_timestamp_id() -> Id<Getter> {
        Id::new("getter:timestamp.clock@link.mozilla.org")
    }
    pub fn getter_time_of_day_id() -> Id<Getter> {
        Id::new("getter:timeofday.clock@link.mozilla.org")
    }
}
impl Adapter for Clock {
    fn id(&self) -> Id<AdapterId> {
        Self::id()
    }

    fn name(&self) -> &str {
        ADAPTER_NAME
    }

    fn vendor(&self) -> &str {
        ADAPTER_VENDOR
    }

    fn version(&self) -> &[u32;4] {
        &ADAPTER_VERSION
    }

    fn fetch_values(&self, mut set: Vec<Id<Getter>>) -> ResultMap<Id<Getter>, Option<Value>, Error> {
        set.drain(..).map(|id| {
            if id == self.getter_timestamp_id {
                let date = TimeStamp::from_datetime(chrono::UTC::now());
                (id, Ok(Some(Value::TimeStamp(date))))
            } else if id == self.getter_time_of_day_id {
                use chrono::Timelike;
                let date = chrono::Local::now();
                let duration = chrono::Duration::seconds(date.num_seconds_from_midnight() as i64);
                (id, Ok(Some(Value::Duration(ValDuration::new(duration)))))
            } else {
                (id.clone(), Err(Error::InternalError(InternalError::NoSuchGetter(id))))
            }
        }).collect()
    }

    fn send_values(&self, mut values: HashMap<Id<Setter>, Value>) -> ResultMap<Id<Setter>, (), Error> {
        values.drain()
            .map(|(id, _)| {
                (id.clone(), Err(Error::InternalError(InternalError::NoSuchSetter(id))))
            })
            .collect()
    }

    fn register_watch(&self, mut watch: Vec<(Id<Getter>, Option<Range>)>,
        tx: Box<ExtSender<WatchEvent>>) ->
            ResultMap<Id<Getter>, Box<AdapterWatchGuard>, Error>
    {
        let tx = tx.map(|msg| {
            match msg {
                Op::Enter(id, value) => {
                    WatchEvent::Enter {
                        id: id,
                        value: value
                    }
                },
                Op::Exit(id, value) => {
                    WatchEvent::Exit {
                        id: id,
                        value: value
                    }
                },
            }
        });
        watch.drain(..).map(|(id, filter)| {
            (id.clone(), match filter {
                None => Err(Error::GetterRequiresThresholdForWatching(id)),
                Some(range) => self.aux_register_watch(&id, range, Box::new(tx.clone()))
            })
        }).collect()
    }
}

impl Clock {
    fn aux_register_watch(&self, id: &Id<Getter>, range: Range, tx: Box<ExtSender<Op>>)
        -> Result<Box<AdapterWatchGuard>, Error>
    {
        match () {
            _ if *id == self.getter_time_of_day_id => self.aux_register_watch_timeofday(id, range, tx),
            _ if *id == self.getter_timestamp_id => self.aux_register_watch_timestamp(id, range, tx),
            _ => Err(Error::GetterDoesNotSupportWatching(id.clone()))
        }
    }

    fn aux_register_watch_timeofday(&self, id: &Id<Getter>, range: Range, tx: Box<ExtSender<Op>>)
        -> Result<Box<AdapterWatchGuard>, Error>
    {
        use foxbox_taxonomy::values::Range::*;

        // Sanity checks
        let typ = try!(range.get_type().map_err(Error::TypeError));
        try!(Type::Duration.ensure_eq(&typ).map_err(Error::TypeError));

        // Now determine when to call the trigger. Repeat duration is always one day.
        let mut thresholds = match range {
            Leq (ref val) => {
                // Equivalent to BetweenEq { min: 0am, max: val }
                let ts = *try!(val.as_duration().map_err(Error::TypeError))
                    .as_duration();
                vec![(Movement::Enter, Duration::seconds(0)), (Movement::Exit, ts)]
            }
            Geq (ref val) => {
                // Equivalent to BetweenEq { min: val, max: 0am }
                let ts = *try!(val.as_duration().map_err(Error::TypeError))
                    .as_duration();
                vec![(Movement::Enter, ts), (Movement::Exit, Duration::days(1))]
            }
            BetweenEq { ref min, ref max } => {
                let ts_min = *try!(min.as_duration().map_err(Error::TypeError))
                    .as_duration();
                let ts_max = *try!(max.as_duration().map_err(Error::TypeError))
                    .as_duration();
                vec![(Movement::Enter, ts_min), (Movement::Exit, ts_max)]
            }
            OutOfStrict { ref min, ref max } => {
                // Equivalent to BetweenEq {min: 0am, max: min} and BetweenEq {min: max, max: 0am}
                let ts_min = *try!(min.as_duration().map_err(Error::TypeError))
                    .as_duration();
                let ts_max = *try!(max.as_duration().map_err(Error::TypeError))
                    .as_duration();
                vec![(Movement::Exit, ts_min), (Movement::Enter, ts_max)]
            }
            Eq (ref val) => {
                let ts = *try!(val.as_duration().map_err(Error::TypeError))
                    .as_duration();
                vec![(Movement::Enter, ts.clone()), (Movement::Exit, ts)]
            }
        };

        // Determine when the next timers needs to launch.
        let now = chrono::Local::now();
        let guards : Vec<timer::Guard> = thresholds.drain(..).filter_map(|(movement, threshold)| {
            let date = match Self::get_next_date(&now, threshold) {
                Err(_) => return None,
                Ok(date) => date,
            };
            let id = id.clone();
            let tx = tx.clone();
            let guard = self.timer.schedule(date, Some(Duration::days(1)), move || {
                let naive_time = chrono::Local::now().time();
                let duration = Duration::hours(naive_time.hour() as i64)
                    + Duration::minutes(naive_time.minute() as i64)
                    + Duration::seconds(naive_time.second() as i64);

                let event = match movement {
                    Movement::Enter => Op::Enter(id.clone(),
                        Value::Duration(ValDuration::new(duration))),
                    Movement::Exit => Op::Exit(id.clone(),
                        Value::Duration(ValDuration::new(duration))),
                };
                let _ = tx.send(event);
            });
            Some(guard)
        }).collect();
        Ok(Box::new(Guard(guards)))
    }

    fn get_next_date(now: &DateTime<Local>, time_of_day: Duration)
        -> Result<DateTime<Local>, Error>
    {
        match chrono::Local::today().and_time(NaiveTime::from_hms(0, 0, 0) + time_of_day) {
            None => Err(Error::InvalidValue(Value::Duration(ValDuration::new(time_of_day)))),
            Some(date) => {
                if date >= *now  {
                    Ok(date)
                } else {
                    // Otherwise, shift to tomorrow.
                    match date.checked_add(Duration::days(1)) {
                        None => Err(Error::InvalidValue(Value::Duration(ValDuration::new(time_of_day)))),
                        Some(date) => Ok(date)
                    }
                }
            }
        }
    }

    fn aux_register_watch_timestamp(&self, id: &Id<Getter>, range: Range, tx: Box<ExtSender<Op>>)
        -> Result<Box<AdapterWatchGuard>, Error>
    {
        use foxbox_taxonomy::values::Range::*;

        // Sanity checks
        let typ = try!(range.get_type().map_err(Error::TypeError));
        try!(Type::TimeStamp.ensure_eq(&typ).map_err(Error::TypeError));

        // Now determine when/if to call the trigger.
        let mut thresholds = match range {
            Leq (_) => {
                // This variant doesn't make sense.
                return Ok(Box::new(Guard(vec![])))
            }
            Geq (ref val) | Eq (ref val) => {
                let ts = *try!(val.as_timestamp().map_err(Error::TypeError))
                    .as_datetime();
                vec![(Movement::Enter, ts)]
            }
            OutOfStrict { ref min, ref max } => {
                let ts_min = *try!(min.as_timestamp().map_err(Error::TypeError))
                    .as_datetime();
                let ts_max = *try!(max.as_timestamp().map_err(Error::TypeError))
                    .as_datetime();
                vec![(Movement::Exit, ts_min), (Movement::Enter, ts_max)]
            }
            BetweenEq { ref min, ref max } => {
                let ts_min = *try!(min.as_timestamp().map_err(Error::TypeError))
                    .as_datetime();
                let ts_max = *try!(max.as_timestamp().map_err(Error::TypeError))
                    .as_datetime();
                vec![(Movement::Enter, ts_min), (Movement::Exit, ts_max)]
            }
        };

        // Determine when/if the next timers needs to launch.
        let now = chrono::UTC::now();
        let guards : Vec<timer::Guard> = thresholds.drain(..).filter_map(|(movement, date)| {
            if date < now {
                return None
            }
            let id = id.clone();
            let tx = tx.clone();
            let guard = self.timer.schedule_with_date(date, move || {
                let naive_time = chrono::Local::now().time();
                let duration = Duration::hours(naive_time.hour() as i64)
                    + Duration::minutes(naive_time.minute() as i64)
                    + Duration::seconds(naive_time.second() as i64);

                let event = match movement {
                    Movement::Enter => Op::Enter(id.clone(),
                        Value::Duration(ValDuration::new(duration))),
                    Movement::Exit => Op::Exit(id.clone(),
                        Value::Duration(ValDuration::new(duration))),
                };
                let _ = tx.send(event);
            });
            Some(guard)
        }).collect();
        Ok(Box::new(Guard(guards)))
    }
}

impl Clock {
    pub fn init<T>(adapt: &T) -> Result<(), Error>
        where T: AdapterManagerHandle
    {
        let getter_timestamp_id = Clock::getter_timestamp_id();
        let getter_time_of_day_id = Clock::getter_time_of_day_id();
        let service_clock_id = Clock::service_clock_id();
        let clock = Box::new(Clock {
            timer: timer::Timer::new(),
            getter_timestamp_id: getter_timestamp_id.clone(),
            getter_time_of_day_id: getter_time_of_day_id.clone(),
        });
        try!(adapt.add_adapter(clock));
        try!(adapt.add_service(Service::empty(Clock::service_clock_id(), Clock::id())));
        try!(adapt.add_getter(Channel {
                tags: HashSet::new(),
                adapter: Clock::id(),
                id: getter_time_of_day_id.clone(),
                last_seen: None,
                service: service_clock_id.clone(),
                mechanism: Getter {
                    kind: ChannelKind::CurrentTimeOfDay,
                    poll: Some(ValDuration::new(chrono::Duration::seconds(1))),
                    trigger: None,
                    watch: true,
                    updated: None
                }
        }));
        try!(adapt.add_getter(Channel {
                tags: HashSet::new(),
                adapter: Clock::id(),
                id: getter_timestamp_id.clone(),
                last_seen: None,
                service: service_clock_id.clone(),
                mechanism: Getter {
                    kind: ChannelKind::CurrentTime,
                    poll: Some(ValDuration::new(chrono::Duration::seconds(1))),
                    trigger: None,
                    watch: true,
                    updated: None
                }
        }));
        Ok(())
    }
}
<|endoftext|>