<commit_before>//! Completes references after dot (fields and method calls).

use hir::{HasVisibility, Type};
use rustc_hash::FxHashSet;
use test_utils::mark;

use crate::{context::CompletionContext, Completions};

/// Complete dot accesses, i.e. fields or methods.
pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
    let dot_receiver = match &ctx.dot_receiver {
        Some(expr) => expr,
        _ => return,
    };

    let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) {
        Some(ty) => ty,
        _ => return,
    };

    if ctx.is_call {
        mark::hit!(test_no_struct_field_completion_for_method_call);
    } else {
        complete_fields(acc, ctx, &receiver_ty);
    }
    complete_methods(acc, ctx, &receiver_ty);
}

fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
    for receiver in receiver.autoderef(ctx.db) {
        for (field, ty) in receiver.fields(ctx.db) {
            if ctx.scope.module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) {
                // Skip private field. FIXME: If the definition location of the
                // field is editable, we should show the completion
                continue;
            }
            acc.add_field(ctx, field, &ty);
        }
        for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() {
            // FIXME: Handle visibility
            acc.add_tuple_field(ctx, i, &ty);
        }
    }
}

fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
    if let Some(krate) = ctx.krate {
        let mut seen_methods = FxHashSet::default();
        let traits_in_scope = ctx.scope.traits_in_scope();
        receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| {
            if func.self_param(ctx.db).is_some()
                && ctx.scope.module().map_or(true, |m| func.is_visible_from(ctx.db, m))
                && seen_methods.insert(func.name(ctx.db))
            {
                acc.add_function(ctx, func, None);
            }
            None::<()>
        });
    }
}

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

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

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

    #[test]
    fn test_struct_field_and_method_completion() {
        check(
            r#"
struct S { foo: u32 }
impl S {
    fn bar(&self) {}
}
fn foo(s: S) { s.$0 }
"#,
            expect![[r#"
                fd foo   u32
                me bar() fn bar(&self)
            "#]],
        );
    }

    #[test]
    fn test_struct_field_completion_self() {
        check(
            r#"
struct S { the_field: (u32,) }
impl S {
    fn foo(self) { self.$0 }
}
"#,
            expect![[r#"
                fd the_field (u32,)
                me foo()     fn foo(self)
            "#]],
        )
    }

    #[test]
    fn test_struct_field_completion_autoderef() {
        check(
            r#"
struct A { the_field: (u32, i32) }
impl A {
    fn foo(&self) { self.$0 }
}
"#,
            expect![[r#"
                fd the_field (u32, i32)
                me foo()     fn foo(&self)
            "#]],
        )
    }

    #[test]
    fn test_no_struct_field_completion_for_method_call() {
        mark::check!(test_no_struct_field_completion_for_method_call);
        check(
            r#"
struct A { the_field: u32 }
fn foo(a: A) { a.$0() }
"#,
            expect![[""]],
        );
    }

    #[test]
    fn test_visibility_filtering() {
        check(
            r#"
mod inner {
    pub struct A {
        private_field: u32,
        pub pub_field: u32,
        pub(crate) crate_field: u32,
        pub(crate) super_field: u32,
    }
}
fn foo(a: inner::A) { a.$0 }
"#,
            expect![[r#"
                fd pub_field   u32
                fd crate_field u32
                fd super_field u32
            "#]],
        );

        check(
            r#"
struct A {}
mod m {
    impl super::A {
        fn private_method(&self) {}
        pub(crate) fn the_method(&self) {}
    }
}
fn foo(a: A) { a.$0 }
"#,
            expect![[r#"
                me the_method() pub(crate) fn the_method(&self)
            "#]],
        );
    }

    #[test]
    fn test_union_field_completion() {
        check(
            r#"
union U { field: u8, other: u16 }
fn foo(u: U) { u.$0 }
"#,
            expect![[r#"
                fd field u8
                fd other u16
            "#]],
        );
    }

    #[test]
    fn test_method_completion_only_fitting_impls() {
        check(
            r#"
struct A<T> {}
impl A<u32> {
    fn the_method(&self) {}
}
impl A<i32> {
    fn the_other_method(&self) {}
}
fn foo(a: A<u32>) { a.$0 }
"#,
            expect![[r#"
                me the_method() fn the_method(&self)
            "#]],
        )
    }

    #[test]
    fn test_trait_method_completion() {
        check(
            r#"
struct A {}
trait Trait { fn the_method(&self); }
impl Trait for A {}
fn foo(a: A) { a.$0 }
"#,
            expect![[r#"
                me the_method() fn the_method(&self)
            "#]],
        );
    }

    #[test]
    fn test_trait_method_completion_deduplicated() {
        check(
            r"
struct A {}
trait Trait { fn the_method(&self); }
impl<T> Trait for T {}
fn foo(a: &A) { a.$0 }
",
            expect![[r#"
                me the_method() fn the_method(&self)
            "#]],
        );
    }

    #[test]
    fn completes_trait_method_from_other_module() {
        check(
            r"
struct A {}
mod m {
    pub trait Trait { fn the_method(&self); }
}
use m::Trait;
impl Trait for A {}
fn foo(a: A) { a.$0 }
",
            expect![[r#"
                me the_method() fn the_method(&self)
            "#]],
        );
    }

    #[test]
    fn test_no_non_self_method() {
        check(
            r#"
struct A {}
impl A {
    fn the_method() {}
}
fn foo(a: A) {
   a.$0
}
"#,
            expect![[""]],
        );
    }

    #[test]
    fn test_tuple_field_completion() {
        check(
            r#"
fn foo() {
   let b = (0, 3.14);
   b.$0
}
"#,
            expect![[r#"
                fd 0 i32
                fd 1 f64
            "#]],
        )
    }

    #[test]
    fn test_tuple_field_inference() {
        check(
            r#"
pub struct S;
impl S { pub fn blah(&self) {} }

struct T(S);

impl T {
    fn foo(&self) {
        // FIXME: This doesn't work without the trailing `a` as `0.` is a float
        self.0.a$0
    }
}
"#,
            expect![[r#"
                me blah() pub fn blah(&self)
            "#]],
        );
    }

    #[test]
    fn test_completion_works_in_consts() {
        check(
            r#"
struct A { the_field: u32 }
const X: u32 = {
    A { the_field: 92 }.$0
};
"#,
            expect![[r#"
                fd the_field u32
            "#]],
        );
    }

    #[test]
    fn works_in_simple_macro_1() {
        check(
            r#"
macro_rules! m { ($e:expr) => { $e } }
struct A { the_field: u32 }
fn foo(a: A) {
    m!(a.x$0)
}
"#,
            expect![[r#"
                fd the_field u32
            "#]],
        );
    }

    #[test]
    fn works_in_simple_macro_2() {
        // this doesn't work yet because the macro doesn't expand without the token -- maybe it can be fixed with better recovery
        check(
            r#"
macro_rules! m { ($e:expr) => { $e } }
struct A { the_field: u32 }
fn foo(a: A) {
    m!(a.$0)
}
"#,
            expect![[r#"
                fd the_field u32
            "#]],
        );
    }

    #[test]
    fn works_in_simple_macro_recursive_1() {
        check(
            r#"
macro_rules! m { ($e:expr) => { $e } }
struct A { the_field: u32 }
fn foo(a: A) {
    m!(m!(m!(a.x$0)))
}
"#,
            expect![[r#"
                fd the_field u32
            "#]],
        );
    }

    #[test]
    fn macro_expansion_resilient() {
        check(
            r#"
macro_rules! dbg {
    () => {};
    ($val:expr) => {
        match $val { tmp => { tmp } }
    };
    // Trailing comma with single argument is ignored
    ($val:expr,) => { $crate::dbg!($val) };
    ($($val:expr),+ $(,)?) => {
        ($($crate::dbg!($val)),+,)
    };
}
struct A { the_field: u32 }
fn foo(a: A) {
    dbg!(a.$0)
}
"#,
            expect![[r#"
                fd the_field u32
            "#]],
        );
    }

    #[test]
    fn test_method_completion_issue_3547() {
        check(
            r#"
struct HashSet<T> {}
impl<T> HashSet<T> {
    pub fn the_method(&self) {}
}
fn foo() {
    let s: HashSet<_>;
    s.$0
}
"#,
            expect![[r#"
                me the_method() pub fn the_method(&self)
            "#]],
        );
    }

    #[test]
    fn completes_method_call_when_receiver_is_a_macro_call() {
        check(
            r#"
struct S;
impl S { fn foo(&self) {} }
macro_rules! make_s { () => { S }; }
fn main() { make_s!().f$0; }
"#,
            expect![[r#"
                me foo() fn foo(&self)
            "#]],
        )
    }
}
<commit_msg>Use another name instead of dbg for test<commit_after>//! Completes references after dot (fields and method calls).

use hir::{HasVisibility, Type};
use rustc_hash::FxHashSet;
use test_utils::mark;

use crate::{context::CompletionContext, Completions};

/// Complete dot accesses, i.e. fields or methods.
pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
    let dot_receiver = match &ctx.dot_receiver {
        Some(expr) => expr,
        _ => return,
    };

    let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) {
        Some(ty) => ty,
        _ => return,
    };

    if ctx.is_call {
        mark::hit!(test_no_struct_field_completion_for_method_call);
    } else {
        complete_fields(acc, ctx, &receiver_ty);
    }
    complete_methods(acc, ctx, &receiver_ty);
}

fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
    for receiver in receiver.autoderef(ctx.db) {
        for (field, ty) in receiver.fields(ctx.db) {
            if ctx.scope.module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) {
                // Skip private field. FIXME: If the definition location of the
                // field is editable, we should show the completion
                continue;
            }
            acc.add_field(ctx, field, &ty);
        }
        for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() {
            // FIXME: Handle visibility
            acc.add_tuple_field(ctx, i, &ty);
        }
    }
}

fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
    if let Some(krate) = ctx.krate {
        let mut seen_methods = FxHashSet::default();
        let traits_in_scope = ctx.scope.traits_in_scope();
        receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| {
            if func.self_param(ctx.db).is_some()
                && ctx.scope.module().map_or(true, |m| func.is_visible_from(ctx.db, m))
                && seen_methods.insert(func.name(ctx.db))
            {
                acc.add_function(ctx, func, None);
            }
            None::<()>
        });
    }
}

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

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

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

    #[test]
    fn test_struct_field_and_method_completion() {
        check(
            r#"
struct S { foo: u32 }
impl S {
    fn bar(&self) {}
}
fn foo(s: S) { s.$0 }
"#,
            expect![[r#"
                fd foo   u32
                me bar() fn bar(&self)
            "#]],
        );
    }

    #[test]
    fn test_struct_field_completion_self() {
        check(
            r#"
struct S { the_field: (u32,) }
impl S {
    fn foo(self) { self.$0 }
}
"#,
            expect![[r#"
                fd the_field (u32,)
                me foo()     fn foo(self)
            "#]],
        )
    }

    #[test]
    fn test_struct_field_completion_autoderef() {
        check(
            r#"
struct A { the_field: (u32, i32) }
impl A {
    fn foo(&self) { self.$0 }
}
"#,
            expect![[r#"
                fd the_field (u32, i32)
                me foo()     fn foo(&self)
            "#]],
        )
    }

    #[test]
    fn test_no_struct_field_completion_for_method_call() {
        mark::check!(test_no_struct_field_completion_for_method_call);
        check(
            r#"
struct A { the_field: u32 }
fn foo(a: A) { a.$0() }
"#,
            expect![[""]],
        );
    }

    #[test]
    fn test_visibility_filtering() {
        check(
            r#"
mod inner {
    pub struct A {
        private_field: u32,
        pub pub_field: u32,
        pub(crate) crate_field: u32,
        pub(crate) super_field: u32,
    }
}
fn foo(a: inner::A) { a.$0 }
"#,
            expect![[r#"
                fd pub_field   u32
                fd crate_field u32
                fd super_field u32
            "#]],
        );

        check(
            r#"
struct A {}
mod m {
    impl super::A {
        fn private_method(&self) {}
        pub(crate) fn the_method(&self) {}
    }
}
fn foo(a: A) { a.$0 }
"#,
            expect![[r#"
                me the_method() pub(crate) fn the_method(&self)
            "#]],
        );
    }

    #[test]
    fn test_union_field_completion() {
        check(
            r#"
union U { field: u8, other: u16 }
fn foo(u: U) { u.$0 }
"#,
            expect![[r#"
                fd field u8
                fd other u16
            "#]],
        );
    }

    #[test]
    fn test_method_completion_only_fitting_impls() {
        check(
            r#"
struct A<T> {}
impl A<u32> {
    fn the_method(&self) {}
}
impl A<i32> {
    fn the_other_method(&self) {}
}
fn foo(a: A<u32>) { a.$0 }
"#,
            expect![[r#"
                me the_method() fn the_method(&self)
            "#]],
        )
    }

    #[test]
    fn test_trait_method_completion() {
        check(
            r#"
struct A {}
trait Trait { fn the_method(&self); }
impl Trait for A {}
fn foo(a: A) { a.$0 }
"#,
            expect![[r#"
                me the_method() fn the_method(&self)
            "#]],
        );
    }

    #[test]
    fn test_trait_method_completion_deduplicated() {
        check(
            r"
struct A {}
trait Trait { fn the_method(&self); }
impl<T> Trait for T {}
fn foo(a: &A) { a.$0 }
",
            expect![[r#"
                me the_method() fn the_method(&self)
            "#]],
        );
    }

    #[test]
    fn completes_trait_method_from_other_module() {
        check(
            r"
struct A {}
mod m {
    pub trait Trait { fn the_method(&self); }
}
use m::Trait;
impl Trait for A {}
fn foo(a: A) { a.$0 }
",
            expect![[r#"
                me the_method() fn the_method(&self)
            "#]],
        );
    }

    #[test]
    fn test_no_non_self_method() {
        check(
            r#"
struct A {}
impl A {
    fn the_method() {}
}
fn foo(a: A) {
   a.$0
}
"#,
            expect![[""]],
        );
    }

    #[test]
    fn test_tuple_field_completion() {
        check(
            r#"
fn foo() {
   let b = (0, 3.14);
   b.$0
}
"#,
            expect![[r#"
                fd 0 i32
                fd 1 f64
            "#]],
        )
    }

    #[test]
    fn test_tuple_field_inference() {
        check(
            r#"
pub struct S;
impl S { pub fn blah(&self) {} }

struct T(S);

impl T {
    fn foo(&self) {
        // FIXME: This doesn't work without the trailing `a` as `0.` is a float
        self.0.a$0
    }
}
"#,
            expect![[r#"
                me blah() pub fn blah(&self)
            "#]],
        );
    }

    #[test]
    fn test_completion_works_in_consts() {
        check(
            r#"
struct A { the_field: u32 }
const X: u32 = {
    A { the_field: 92 }.$0
};
"#,
            expect![[r#"
                fd the_field u32
            "#]],
        );
    }

    #[test]
    fn works_in_simple_macro_1() {
        check(
            r#"
macro_rules! m { ($e:expr) => { $e } }
struct A { the_field: u32 }
fn foo(a: A) {
    m!(a.x$0)
}
"#,
            expect![[r#"
                fd the_field u32
            "#]],
        );
    }

    #[test]
    fn works_in_simple_macro_2() {
        // this doesn't work yet because the macro doesn't expand without the token -- maybe it can be fixed with better recovery
        check(
            r#"
macro_rules! m { ($e:expr) => { $e } }
struct A { the_field: u32 }
fn foo(a: A) {
    m!(a.$0)
}
"#,
            expect![[r#"
                fd the_field u32
            "#]],
        );
    }

    #[test]
    fn works_in_simple_macro_recursive_1() {
        check(
            r#"
macro_rules! m { ($e:expr) => { $e } }
struct A { the_field: u32 }
fn foo(a: A) {
    m!(m!(m!(a.x$0)))
}
"#,
            expect![[r#"
                fd the_field u32
            "#]],
        );
    }

    #[test]
    fn macro_expansion_resilient() {
        check(
            r#"
macro_rules! d {
    () => {};
    ($val:expr) => {
        match $val { tmp => { tmp } }
    };
    // Trailing comma with single argument is ignored
    ($val:expr,) => { $crate::d!($val) };
    ($($val:expr),+ $(,)?) => {
        ($($crate::d!($val)),+,)
    };
}
struct A { the_field: u32 }
fn foo(a: A) {
    d!(a.$0)
}
"#,
            expect![[r#"
                fd the_field u32
            "#]],
        );
    }

    #[test]
    fn test_method_completion_issue_3547() {
        check(
            r#"
struct HashSet<T> {}
impl<T> HashSet<T> {
    pub fn the_method(&self) {}
}
fn foo() {
    let s: HashSet<_>;
    s.$0
}
"#,
            expect![[r#"
                me the_method() pub fn the_method(&self)
            "#]],
        );
    }

    #[test]
    fn completes_method_call_when_receiver_is_a_macro_call() {
        check(
            r#"
struct S;
impl S { fn foo(&self) {} }
macro_rules! make_s { () => { S }; }
fn main() { make_s!().f$0; }
"#,
            expect![[r#"
                me foo() fn foo(&self)
            "#]],
        )
    }
}
<|endoftext|>


<commit_before>extern crate regex;
extern crate serde_json;

#[macro_use]
extern crate throw;

use throw::Result;

macro_rules! assert_matches {
    ($expected:expr, $actual:expr) => {{
        let expected = ($expected).replace("    ", "\t");
        let re = regex::Regex::new(&expected).expect("expected hardcoded regex to compile");

        let actual = format!("{}", $actual);

        assert!(
            re.is_match(&actual),
            format!(
                "expected error to match regex `\n{}\n`, but found `\n{}\n`",
                expected, actual
            )
        );
    }};
}

fn throw_static_message() -> Result<(), &'static str> {
    throw_new!("hi");
}

fn throw1() -> Result<(), ()> {
    throw_new!(());
}

fn throw2() -> Result<(), ()> {
    up!(throw1());
    Ok(())
}

fn throw3() -> Result<(), ()> {
    up!(throw2());
    Ok(())
}

fn throw_with_context1() -> Result<(), &'static str> {
    throw_new!("Error with context", "code"=>78,"application"=>"rust_core")
}

fn throw_with_context2() -> Result<(), &'static str> {
    up!(throw_with_context1(), "project_secret"=>"omega");
    Ok(())
}

fn throw_with_context3() -> Result<(), &'static str> {
    up!(throw_with_context2(),  "score"=>0.75, "height"=>948);
    Ok(())
}

fn gives_ok() -> Result<&'static str, &'static str> {
    Ok("ok")
}

fn throws_ok() -> Result<&'static str, &'static str> {
    let ok_msg = up!(gives_ok());
    Ok(ok_msg)
}

mod mod_test {
    use throw::Result;

    pub fn throws() -> Result<(), &'static str> {
        throw_new!("ahhhh");
    }
}

fn throws_into() -> Result<(), String> {
    throw!(Err("some static string"));
    Ok(())
}

fn throws_into_key_value() -> Result<(), String> {
    throw!(Err("some static string"), "key" => "value");
    Ok(())
}

fn throws_into_multiple_key_value_pairs() -> Result<(), String> {
    throw!(
        Err("some static string"),
        "key" => "value",
        "key2" => "value2",
        "key3" => "value3",
        "key4" => "value4",
    );
    Ok(())
}

#[test]
fn test_static_message() {
    let error = throw_static_message().unwrap_err();
    assert_eq!(*error.error(), "hi");
    assert_matches!(
        r#"Error: hi
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        error
    );
    assert_eq!("hi".to_owned(), error.into_origin());
}

#[test]
#[cfg(any(feature = "serde-1", feature = "serde-1-std"))]
fn serialize_json() {
    let error = throw_with_context3().unwrap_err();
    let json = serde_json::to_string(&error).unwrap();
    assert_eq!(r#"{"points":[{"line":40,"column":5,"module_path":"exceptions_work","file":"tests/exceptions_work.rs"},{"line":44,"column":5,"module_path":"exceptions_work","file":"tests/exceptions_work.rs"},{"line":49,"column":5,"module_path":"exceptions_work","file":"tests/exceptions_work.rs"}],"context":[{"key":"code","value":78},{"key":"application","value":"rust_core"},{"key":"project_secret","value":"omega"},{"key":"score","value":0.75},{"key":"height","value":948}],"error":"Error with context"}"#, json);
}

#[test]
fn test_throw_with_context() {
    let error = throw_with_context1().unwrap_err();
    assert_eq!(error.get_context().len(), 2);

    let error2 = throw_with_context3().unwrap_err();
    assert_eq!(error2.get_context().len(), 5);

    assert_matches!(
        r#"Error: "Error with context"
    height: 948
	score: 0.75
	project_secret: omega
	application: rust_core
	code: 78
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        format!("{:?}", error2)
    );
}

#[test]
#[allow(deprecated)]
fn test_multiple_throws() {
    let error = throw3().unwrap_err();
    assert_eq!(error.error(), &());
    assert_eq!(error.error(), error.original_error());
    assert_matches!(
        r#"Error: \(\)
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        format!("{:?}", error)
    );
}

#[test]
fn test_returns_ok() {
    let ok = throws_ok().unwrap();
    assert_eq!(ok, "ok");
}

#[test]
fn test_mod_throw() {
    let error = mod_test::throws().unwrap_err();
    assert_matches!(
        r#"Error: ahhhh
    at [0-9]+:[0-9] in exceptions_work::mod_test \([a-z/._-]+\)"#,
        error
    );
}

#[test]
fn test_throws_into() {
    let error = throws_into().unwrap_err();
    assert_matches!(
        r#"Error: some static string
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        error
    )
}

#[test]
fn test_throws_into_key_value() {
    let error = throws_into_key_value().unwrap_err();
    assert_matches!(
        r#"Error: some static string
    key: value
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        error
    )
}

#[test]
fn test_throws_into_multiple_key_value_pairs() {
    let error = throws_into_multiple_key_value_pairs().unwrap_err();
    assert_matches!(
        r#"Error: some static string
    key4: value4
    key3: value3
    key2: value2
    key: value
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        error
    )
}
<commit_msg>Update test to use correct line numbers in reformatted code.<commit_after>extern crate regex;
extern crate serde_json;

#[macro_use]
extern crate throw;

use throw::Result;

macro_rules! assert_matches {
    ($expected:expr, $actual:expr) => {{
        let expected = ($expected).replace("    ", "\t");
        let re = regex::Regex::new(&expected).expect("expected hardcoded regex to compile");

        let actual = format!("{}", $actual);

        assert!(
            re.is_match(&actual),
            format!(
                "expected error to match regex `\n{}\n`, but found `\n{}\n`",
                expected, actual
            )
        );
    }};
}

fn throw_static_message() -> Result<(), &'static str> {
    throw_new!("hi");
}

fn throw1() -> Result<(), ()> {
    throw_new!(());
}

fn throw2() -> Result<(), ()> {
    up!(throw1());
    Ok(())
}

fn throw3() -> Result<(), ()> {
    up!(throw2());
    Ok(())
}

fn throw_with_context1() -> Result<(), &'static str> {
    throw_new!("Error with context", "code"=>78,"application"=>"rust_core")
}

fn throw_with_context2() -> Result<(), &'static str> {
    up!(throw_with_context1(), "project_secret"=>"omega");
    Ok(())
}

fn throw_with_context3() -> Result<(), &'static str> {
    up!(throw_with_context2(),  "score"=>0.75, "height"=>948);
    Ok(())
}

fn gives_ok() -> Result<&'static str, &'static str> {
    Ok("ok")
}

fn throws_ok() -> Result<&'static str, &'static str> {
    let ok_msg = up!(gives_ok());
    Ok(ok_msg)
}

mod mod_test {
    use throw::Result;

    pub fn throws() -> Result<(), &'static str> {
        throw_new!("ahhhh");
    }
}

fn throws_into() -> Result<(), String> {
    throw!(Err("some static string"));
    Ok(())
}

fn throws_into_key_value() -> Result<(), String> {
    throw!(Err("some static string"), "key" => "value");
    Ok(())
}

fn throws_into_multiple_key_value_pairs() -> Result<(), String> {
    throw!(
        Err("some static string"),
        "key" => "value",
        "key2" => "value2",
        "key3" => "value3",
        "key4" => "value4",
    );
    Ok(())
}

#[test]
fn test_static_message() {
    let error = throw_static_message().unwrap_err();
    assert_eq!(*error.error(), "hi");
    assert_matches!(
        r#"Error: hi
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        error
    );
    assert_eq!("hi".to_owned(), error.into_origin());
}

#[test]
#[cfg(any(feature = "serde-1", feature = "serde-1-std"))]
fn serialize_json() {
    let error = throw_with_context3().unwrap_err();
    let json = serde_json::to_string(&error).unwrap();
    assert_eq!(r#"{"points":[{"line":45,"column":4,"module_path":"exceptions_work","file":"tests/exceptions_work.rs"},{"line":49,"column":4,"module_path":"exceptions_work","file":"tests/exceptions_work.rs"},{"line":54,"column":4,"module_path":"exceptions_work","file":"tests/exceptions_work.rs"}],"context":[{"key":"code","value":78},{"key":"application","value":"rust_core"},{"key":"project_secret","value":"omega"},{"key":"score","value":0.75},{"key":"height","value":948}],"error":"Error with context"}"#, json);
}

#[test]
fn test_throw_with_context() {
    let error = throw_with_context1().unwrap_err();
    assert_eq!(error.get_context().len(), 2);

    let error2 = throw_with_context3().unwrap_err();
    assert_eq!(error2.get_context().len(), 5);

    assert_matches!(
        r#"Error: "Error with context"
    height: 948
	score: 0.75
	project_secret: omega
	application: rust_core
	code: 78
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        format!("{:?}", error2)
    );
}

#[test]
#[allow(deprecated)]
fn test_multiple_throws() {
    let error = throw3().unwrap_err();
    assert_eq!(error.error(), &());
    assert_eq!(error.error(), error.original_error());
    assert_matches!(
        r#"Error: \(\)
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        format!("{:?}", error)
    );
}

#[test]
fn test_returns_ok() {
    let ok = throws_ok().unwrap();
    assert_eq!(ok, "ok");
}

#[test]
fn test_mod_throw() {
    let error = mod_test::throws().unwrap_err();
    assert_matches!(
        r#"Error: ahhhh
    at [0-9]+:[0-9] in exceptions_work::mod_test \([a-z/._-]+\)"#,
        error
    );
}

#[test]
fn test_throws_into() {
    let error = throws_into().unwrap_err();
    assert_matches!(
        r#"Error: some static string
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        error
    )
}

#[test]
fn test_throws_into_key_value() {
    let error = throws_into_key_value().unwrap_err();
    assert_matches!(
        r#"Error: some static string
    key: value
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        error
    )
}

#[test]
fn test_throws_into_multiple_key_value_pairs() {
    let error = throws_into_multiple_key_value_pairs().unwrap_err();
    assert_matches!(
        r#"Error: some static string
    key4: value4
    key3: value3
    key2: value2
    key: value
    at [0-9]+:[0-9] in exceptions_work \([a-z/._-]+\)"#,
        error
    )
}
<|endoftext|>


<commit_before>extern crate libudis86_sys;
extern crate regex;

extern crate unwind_mc;

mod analysis_helper;

use libudis86_sys::ud_type::*;

use unwind_mc::flow_analyzer::*;
use unwind_mc::il::*;
use unwind_mc::il_decompiler;
use unwind_mc::type_resolver::*;

#[test]
fn stage_test_find_max() {
    let analyzer = analysis_helper::analyze(
        "
        08048400: 56                 push esi
        08048401: 8b 4c 24 0c        mov ecx, [esp+0xc]
        08048405: b8 00 00 00 80     mov eax, 0x80000000
        0804840a: 85 c9              test ecx, ecx
        0804840c: 74 16              jz 0x8048424
        0804840e: 8b 54 24 08        mov edx, [esp+0x8]
        08048412: b8 00 00 00 80     mov eax, 0x80000000
        08048417: 8b 32              mov esi, [edx]
        08048419: 39 f0              cmp eax, esi
        0804841b: 0f 4c c6           cmovl eax, esi
        0804841e: 83 c2 04           add edx, 0x4
        08048421: 49                 dec ecx
        08048422: 75 f3              jnz 0x8048417
        08048424: 5e                 pop esi
        08048425: c3                 ret",
    );
    let il = il_decompiler::decompile(analyzer.graph(), 0x8048400);

    use unwind_mc::il::BranchType::*;
    use unwind_mc::il::ILBinaryOperator::*;
    use unwind_mc::il::ILInstruction::*;
    use unwind_mc::il::ILOperand::*;

    let nop0 = Nop;
    let asn0 = Assign(binary(Register(UD_R_ECX), Argument(4)));
    let asn1 = Assign(binary(Register(UD_R_EAX), Value(0x80000000)));
    let cmp0 = Compare(binary(Register(UD_R_ECX), Value(0)));
    let br0 = Branch(branch(Equal, 15));
    let asn2 = Assign(binary(Register(UD_R_EDX), Argument(0)));
    let asn3 = Assign(binary(Register(UD_R_EAX), Value(0x80000000)));
    let asn4 = Assign(binary(Register(UD_R_ESI), Pointer(UD_R_EDX, 0)));
    let cmp1 = Compare(binary(Register(UD_R_EAX), Register(UD_R_ESI)));
    let br1 = Branch(branch(GreaterOrEqual, 11));
    let asn5 = Assign(binary(Register(UD_R_EAX), Register(UD_R_ESI)));
    let add0 = Binary(Add, binary(Register(UD_R_EDX), Value(4)));
    let sub0 = Binary(Subtract, binary(Register(UD_R_ECX), Value(1)));
    let cmp2 = Compare(binary(Register(UD_R_ECX), Value(0)));
    let br2 = Branch(branch(NotEqual, 7));
    let nop1 = Nop;
    let ret = Return(unary(Register(UD_R_EAX)));

    let expected = vec![
        nop0.clone(),
        asn0.clone(),
        asn1.clone(),
        cmp0.clone(),
        br0.clone(),
        asn2.clone(),
        asn3.clone(),
        asn4.clone(),
        cmp1.clone(),
        br1.clone(),
        asn5.clone(),
        add0.clone(),
        sub0.clone(),
        cmp2.clone(),
        br2.clone(),
        nop1.clone(),
        ret.clone(),
    ];

    assert_eq!(il, expected);

    let blocks = build_flow_graph(il);

    let expected = vec![
        Block::SequentialBlock(SequentialBlock {
            instructions: vec![nop0, asn0, asn1],
        }),
        Block::ConditionalBlock(ConditionalBlock {
            condition: invert_condition(vec![cmp0, br0]),
            true_branch: vec![
                Block::SequentialBlock(SequentialBlock {
                    instructions: vec![asn2, asn3],
                }),
                Block::DoWhileBlock(DoWhileBlock {
                    condition: vec![cmp2, br2],
                    body: vec![
                        Block::SequentialBlock(SequentialBlock {
                            instructions: vec![asn4],
                        }),
                        Block::ConditionalBlock(ConditionalBlock {
                            condition: invert_condition(vec![cmp1, br1]),
                            true_branch: vec![Block::SequentialBlock(SequentialBlock {
                                instructions: vec![asn5],
                            })],
                            false_branch: vec![],
                        }),
                        Block::SequentialBlock(SequentialBlock {
                            instructions: vec![add0, sub0],
                        }),
                    ],
                }),
            ],
            false_branch: vec![],
        }),
        Block::SequentialBlock(SequentialBlock {
            instructions: vec![nop1, ret],
        }),
    ];

    assert_eq!(blocks, expected);

    let (blocks, types) = TypeResolver::resolve_types(blocks);
    let parameter_types = types.parameter_types;
    let variable_types = types.variable_types;
    let local_types = types.local_types;

    assert_eq!(parameter_types.len(), 2);
    assert_eq!(
        parameter_types[0],
        DataType::Pointer(Box::new(DataType::Int32))
    );
    assert_eq!(parameter_types[1], DataType::Int32);

    assert_eq!(variable_types.len(), 5);
    assert_eq!(variable_types[0], DataType::Int32);
    assert_eq!(variable_types[1], DataType::Int32);
    assert_eq!(
        variable_types[2],
        DataType::Pointer(Box::new(DataType::Int32))
    );
    assert_eq!(variable_types[3], DataType::Int32);
    assert_eq!(variable_types[4], DataType::Int32);

    assert_eq!(local_types.len(), 0);
}
<commit_msg>Check blocks in type resolver test<commit_after>extern crate libudis86_sys;
extern crate regex;

extern crate unwind_mc;

mod analysis_helper;

use libudis86_sys::ud_type::*;

use unwind_mc::flow_analyzer::*;
use unwind_mc::il::*;
use unwind_mc::il_decompiler;
use unwind_mc::type_resolver::*;

#[test]
fn stage_test_find_max() {
    let analyzer = analysis_helper::analyze(
        "
        08048400: 56                 push esi
        08048401: 8b 4c 24 0c        mov ecx, [esp+0xc]
        08048405: b8 00 00 00 80     mov eax, 0x80000000
        0804840a: 85 c9              test ecx, ecx
        0804840c: 74 16              jz 0x8048424
        0804840e: 8b 54 24 08        mov edx, [esp+0x8]
        08048412: b8 00 00 00 80     mov eax, 0x80000000
        08048417: 8b 32              mov esi, [edx]
        08048419: 39 f0              cmp eax, esi
        0804841b: 0f 4c c6           cmovl eax, esi
        0804841e: 83 c2 04           add edx, 0x4
        08048421: 49                 dec ecx
        08048422: 75 f3              jnz 0x8048417
        08048424: 5e                 pop esi
        08048425: c3                 ret",
    );
    let il = il_decompiler::decompile(analyzer.graph(), 0x8048400);

    use unwind_mc::il::BranchType::*;
    use unwind_mc::il::ILBinaryOperator::*;
    use unwind_mc::il::ILInstruction::*;
    use unwind_mc::il::ILOperand::*;

    let expected = vec![
        Nop,
        Assign(binary(Register(UD_R_ECX), Argument(4))),
        Assign(binary(Register(UD_R_EAX), Value(0x80000000))),
        Compare(binary(Register(UD_R_ECX), Value(0))),
        Branch(branch(Equal, 15)),
        Assign(binary(Register(UD_R_EDX), Argument(0))),
        Assign(binary(Register(UD_R_EAX), Value(0x80000000))),
        Assign(binary(Register(UD_R_ESI), Pointer(UD_R_EDX, 0))),
        Compare(binary(Register(UD_R_EAX), Register(UD_R_ESI))),
        Branch(branch(GreaterOrEqual, 11)),
        Assign(binary(Register(UD_R_EAX), Register(UD_R_ESI))),
        Binary(Add, binary(Register(UD_R_EDX), Value(4))),
        Binary(Subtract, binary(Register(UD_R_ECX), Value(1))),
        Compare(binary(Register(UD_R_ECX), Value(0))),
        Branch(branch(NotEqual, 7)),
        Nop,
        Return(unary(Register(UD_R_EAX))),
    ];

    assert_eq!(il, expected);

    let blocks = build_flow_graph(il);

    let expected = vec![
        Block::SequentialBlock(SequentialBlock {
            instructions: vec![
                Nop,
                Assign(binary(Register(UD_R_ECX), Argument(4))),
                Assign(binary(Register(UD_R_EAX), Value(0x80000000))),
            ],
        }),
        Block::ConditionalBlock(ConditionalBlock {
            condition: invert_condition(vec![
                Compare(binary(Register(UD_R_ECX), Value(0))),
                Branch(branch(Equal, 15)),
            ]),
            true_branch: vec![
                Block::SequentialBlock(SequentialBlock {
                    instructions: vec![
                        Assign(binary(Register(UD_R_EDX), Argument(0))),
                        Assign(binary(Register(UD_R_EAX), Value(0x80000000))),
                    ],
                }),
                Block::DoWhileBlock(DoWhileBlock {
                    condition: vec![
                        Compare(binary(Register(UD_R_ECX), Value(0))),
                        Branch(branch(NotEqual, 7)),
                    ],
                    body: vec![
                        Block::SequentialBlock(SequentialBlock {
                            instructions: vec![Assign(binary(
                                Register(UD_R_ESI),
                                Pointer(UD_R_EDX, 0),
                            ))],
                        }),
                        Block::ConditionalBlock(ConditionalBlock {
                            condition: invert_condition(vec![
                                Compare(binary(Register(UD_R_EAX), Register(UD_R_ESI))),
                                Branch(branch(GreaterOrEqual, 11)),
                            ]),
                            true_branch: vec![Block::SequentialBlock(SequentialBlock {
                                instructions: vec![Assign(binary(
                                    Register(UD_R_EAX),
                                    Register(UD_R_ESI),
                                ))],
                            })],
                            false_branch: vec![],
                        }),
                        Block::SequentialBlock(SequentialBlock {
                            instructions: vec![
                                Binary(Add, binary(Register(UD_R_EDX), Value(4))),
                                Binary(Subtract, binary(Register(UD_R_ECX), Value(1))),
                            ],
                        }),
                    ],
                }),
            ],
            false_branch: vec![],
        }),
        Block::SequentialBlock(SequentialBlock {
            instructions: vec![Nop, Return(unary(Register(UD_R_EAX)))],
        }),
    ];

    assert_eq!(blocks, expected);

    let (blocks, types) = TypeResolver::resolve_types(blocks);
    let parameter_types = types.parameter_types;
    let variable_types = types.variable_types;
    let local_types = types.local_types;

    assert_eq!(parameter_types.len(), 2);
    assert_eq!(
        parameter_types[0],
        DataType::Pointer(Box::new(DataType::Int32))
    );
    assert_eq!(parameter_types[1], DataType::Int32);

    assert_eq!(variable_types.len(), 5);
    assert_eq!(variable_types[0], DataType::Int32);
    assert_eq!(variable_types[1], DataType::Int32);
    assert_eq!(
        variable_types[2],
        DataType::Pointer(Box::new(DataType::Int32))
    );
    assert_eq!(variable_types[3], DataType::Int32);
    assert_eq!(variable_types[4], DataType::Int32);

    assert_eq!(local_types.len(), 0);

    let expected = vec![
        Block::SequentialBlock(SequentialBlock {
            instructions: vec![
                Nop,
                Assign(binary((Register(UD_R_ECX), Some(0)), (Argument(4), None))),
                Assign(binary(
                    (Register(UD_R_EAX), Some(1)),
                    (Value(0x80000000), None),
                )),
            ],
        }),
        Block::ConditionalBlock(ConditionalBlock {
            condition: invert_condition(vec![
                Compare(binary((Register(UD_R_ECX), Some(0)), (Value(0), None))),
                Branch(branch(Equal, 15)),
            ]),
            true_branch: vec![
                Block::SequentialBlock(SequentialBlock {
                    instructions: vec![
                        Assign(binary((Register(UD_R_EDX), Some(2)), (Argument(0), None))),
                        Assign(binary(
                            (Register(UD_R_EAX), Some(1)),
                            (Value(0x80000000), None),
                        )),
                    ],
                }),
                Block::DoWhileBlock(DoWhileBlock {
                    condition: vec![
                        Compare(binary((Register(UD_R_ECX), Some(0)), (Value(0), None))),
                        Branch(branch(NotEqual, 7)),
                    ],
                    body: vec![
                        Block::SequentialBlock(SequentialBlock {
                            instructions: vec![Assign(binary(
                                (Register(UD_R_ESI), Some(4)),
                                (Pointer(UD_R_EDX, 0), Some(2)),
                            ))],
                        }),
                        Block::ConditionalBlock(ConditionalBlock {
                            condition: invert_condition(vec![
                                Compare(binary(
                                    (Register(UD_R_EAX), Some(1)),
                                    (Register(UD_R_ESI), Some(4)),
                                )),
                                Branch(branch(GreaterOrEqual, 11)),
                            ]),
                            true_branch: vec![Block::SequentialBlock(SequentialBlock {
                                instructions: vec![Assign(binary(
                                    (Register(UD_R_EAX), Some(1)),
                                    (Register(UD_R_ESI), Some(4)),
                                ))],
                            })],
                            false_branch: vec![],
                        }),
                        Block::SequentialBlock(SequentialBlock {
                            instructions: vec![
                                Binary(
                                    Add,
                                    binary((Register(UD_R_EDX), Some(2)), (Value(4), None)),
                                ),
                                Binary(
                                    Subtract,
                                    binary((Register(UD_R_ECX), Some(0)), (Value(1), None)),
                                ),
                            ],
                        }),
                    ],
                }),
            ],
            false_branch: vec![],
        }),
        Block::SequentialBlock(SequentialBlock {
            instructions: vec![Nop, Return(unary((Register(UD_R_EAX), Some(1))))],
        }),
    ];

    assert_eq!(blocks, expected);
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! Interface between Consensus and Network layers.

use crate::{
    error::NetworkError,
    interface::{NetworkNotification, NetworkRequest},
    proto::{ConsensusMsg, RequestBlock, RequestChunk, RespondBlock, RespondChunk},
    protocols::{
        direct_send::Message,
        rpc::{error::RpcError, OutboundRpcRequest},
    },
    validator_network::Event,
    NetworkPublicKeys, ProtocolId,
};
use bytes::Bytes;
use channel;
use futures::{
    channel::oneshot,
    stream::Map,
    task::{Context, Poll},
    SinkExt, Stream, StreamExt,
};
use pin_utils::unsafe_pinned;
use protobuf::Message as proto_msg;
use std::{pin::Pin, time::Duration};
use types::{validator_public_keys::ValidatorPublicKeys, PeerId};

/// Protocol id for consensus RPC calls
pub const CONSENSUS_RPC_PROTOCOL: &[u8] = b"/libra/consensus/rpc/0.1.0";
/// Protocol id for consensus direct-send calls
pub const CONSENSUS_DIRECT_SEND_PROTOCOL: &[u8] = b"/libra/consensus/direct-send/0.1.0";

/// The interface from Network to Consensus layer.
///
/// `ConsensusNetworkEvents` is a `Stream` of `NetworkNotification` where the
/// raw `Bytes` direct-send and rpc messages are deserialized into
/// `ConsensusMessage` types. `ConsensusNetworkEvents` is a thin wrapper around
/// an `channel::Receiver<NetworkNotification>`.
pub struct ConsensusNetworkEvents {
    inner: Map<
        channel::Receiver<NetworkNotification>,
        fn(NetworkNotification) -> Result<Event<ConsensusMsg>, NetworkError>,
    >,
}

impl ConsensusNetworkEvents {
    // This use of `unsafe_pinned` is safe because:
    //   1. This struct does not implement [`Drop`]
    //   2. This struct does not implement [`Unpin`]
    //   3. This struct is not `#[repr(packed)]`
    unsafe_pinned!(
        inner:
            Map<
                channel::Receiver<NetworkNotification>,
                fn(NetworkNotification) -> Result<Event<ConsensusMsg>, NetworkError>,
            >
    );

    pub fn new(receiver: channel::Receiver<NetworkNotification>) -> Self {
        let inner = receiver.map::<_, fn(_) -> _>(|notification| match notification {
            NetworkNotification::NewPeer(peer_id) => Ok(Event::NewPeer(peer_id)),
            NetworkNotification::LostPeer(peer_id) => Ok(Event::LostPeer(peer_id)),
            NetworkNotification::RecvRpc(peer_id, rpc_req) => {
                let req_msg = ::protobuf::parse_from_bytes(rpc_req.data.as_ref())?;
                Ok(Event::RpcRequest((peer_id, req_msg, rpc_req.res_tx)))
            }
            NetworkNotification::RecvMessage(peer_id, msg) => {
                let msg = ::protobuf::parse_from_bytes(msg.mdata.as_ref())?;
                Ok(Event::Message((peer_id, msg)))
            }
        });

        Self { inner }
    }
}

impl Stream for ConsensusNetworkEvents {
    type Item = Result<Event<ConsensusMsg>, NetworkError>;

    fn poll_next(self: Pin<&mut Self>, context: &mut Context) -> Poll<Option<Self::Item>> {
        self.inner().poll_next(context)
    }
}

/// The interface from Consensus to Networking layer.
///
/// This is a thin wrapper around an `channel::Sender<NetworkRequest>`, so it is
/// easy to clone and send off to a separate task. For example, the rpc requests
/// return Futures that encapsulate the whole flow, from sending the request to
/// remote, to finally receiving the response and deserializing. It therefore
/// makes the most sense to make the rpc call on a separate async task, which
/// requires the `ConsensusNetworkSender` to be `Clone` and `Send`.
#[derive(Clone)]
pub struct ConsensusNetworkSender {
    inner: channel::Sender<NetworkRequest>,
}

impl ConsensusNetworkSender {
    pub fn new(inner: channel::Sender<NetworkRequest>) -> Self {
        Self { inner }
    }

    /// Send a fire-and-forget "direct-send" message to remote peer `recipient`.
    ///
    /// Currently, the returned Future simply resolves when the message has been
    /// enqueued on the network actor's event queue. It therefore makes no
    /// reliable delivery guarantees.
    pub async fn send_to(
        &mut self,
        recipient: PeerId,
        message: ConsensusMsg,
    ) -> Result<(), NetworkError> {
        self.inner
            .send(NetworkRequest::SendMessage(
                recipient,
                Message {
                    protocol: ProtocolId::from_static(CONSENSUS_DIRECT_SEND_PROTOCOL),
                    mdata: Bytes::from(message.write_to_bytes().unwrap()),
                },
            ))
            .await?;
        Ok(())
    }

    /// Send a RequestBlock RPC request to remote peer `recipient`. Returns the
    /// future `RespondBlock` returned by the remote peer.
    ///
    /// The rpc request can be canceled at any point by dropping the returned
    /// future.
    pub async fn request_block(
        &mut self,
        recipient: PeerId,
        req_msg: RequestBlock,
        timeout: Duration,
    ) -> Result<RespondBlock, RpcError> {
        let protocol = ProtocolId::from_static(CONSENSUS_RPC_PROTOCOL);
        let mut req_msg_enum = ConsensusMsg::new();
        req_msg_enum.set_request_block(req_msg);

        let mut res_msg_enum = self
            .unary_rpc(recipient, protocol, req_msg_enum, timeout)
            .await?;

        if res_msg_enum.has_respond_block() {
            Ok(res_msg_enum.take_respond_block())
        } else {
            // TODO: context
            Err(RpcError::InvalidRpcResponse)
        }
    }

    /// Send a RequestChunk RPC request to remote peer `recipient`. Returns the
    /// future `RespondChunk` returned by the remote peer.
    ///
    /// The rpc request can be canceled at any point by dropping the returned
    /// future.
    pub async fn request_chunk(
        &mut self,
        recipient: PeerId,
        req_msg: RequestChunk,
        timeout: Duration,
    ) -> Result<RespondChunk, RpcError> {
        let protocol = ProtocolId::from_static(CONSENSUS_RPC_PROTOCOL);
        let mut req_msg_enum = ConsensusMsg::new();
        req_msg_enum.set_request_chunk(req_msg);

        let mut res_msg_enum = self
            .unary_rpc(recipient, protocol, req_msg_enum, timeout)
            .await?;

        if res_msg_enum.has_respond_chunk() {
            Ok(res_msg_enum.take_respond_chunk())
        } else {
            // TODO: context
            Err(RpcError::InvalidRpcResponse)
        }
    }

    pub async fn update_eligible_nodes(
        &mut self,
        validators: Vec<ValidatorPublicKeys>,
    ) -> Result<(), NetworkError> {
        self.inner
            .send(NetworkRequest::UpdateEligibleNodes(
                validators
                    .into_iter()
                    .map(|keys| {
                        (
                            *keys.account_address(),
                            NetworkPublicKeys {
                                identity_public_key: keys.network_identity_public_key().clone(),
                                signing_public_key: keys.network_signing_public_key().clone(),
                            },
                        )
                    })
                    .collect(),
            ))
            .await?;
        Ok(())
    }

    /// Send a unary rpc request to remote peer `recipient`. Handles
    /// serialization and deserialization of the `ConsensusMsg` message enum.
    ///
    /// TODO(philiphayes): specify error cases
    async fn unary_rpc(
        &mut self,
        recipient: PeerId,
        protocol: ProtocolId,
        req_msg: ConsensusMsg,
        timeout: Duration,
    ) -> Result<ConsensusMsg, RpcError> {
        // serialize request
        let req_data = req_msg.write_to_bytes()?.into();

        // ask network to fulfill rpc request
        let (res_tx, res_rx) = oneshot::channel();
        let req = OutboundRpcRequest {
            protocol,
            data: req_data,
            res_tx,
            timeout,
        };
        self.inner
            .send(NetworkRequest::SendRpc(recipient, req))
            .await?;

        // wait for response and deserialize
        let res_data = res_rx.await??;
        let res_msg = ::protobuf::parse_from_bytes(res_data.as_ref())?;
        Ok(res_msg)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{proto::Vote, protocols::rpc::InboundRpcRequest};
    use futures::{executor::block_on, future::try_join};

    fn new_test_vote() -> ConsensusMsg {
        let mut vote = Vote::new();
        vote.set_proposed_block_id(Bytes::new());
        vote.set_executed_state_id(Bytes::new());
        vote.set_author(Bytes::new());
        vote.set_signature(Bytes::new());

        let mut consensus_msg = ConsensusMsg::new();
        consensus_msg.set_vote(vote);
        consensus_msg
    }

    // Direct send messages should get deserialized through the
    // `ConsensusNetworkEvents` stream.
    #[test]
    fn test_consensus_network_events() {
        let (mut consensus_tx, consensus_rx) = channel::new_test(8);
        let mut stream = ConsensusNetworkEvents::new(consensus_rx);

        let peer_id = PeerId::random();
        let consensus_msg = new_test_vote();
        let network_msg = Message {
            protocol: ProtocolId::from_static(CONSENSUS_DIRECT_SEND_PROTOCOL),
            mdata: consensus_msg.clone().write_to_bytes().unwrap().into(),
        };

        // Network sends inbound message to consensus
        block_on(consensus_tx.send(NetworkNotification::RecvMessage(peer_id, network_msg)))
            .unwrap();

        // Consensus should receive deserialized message event
        let event = block_on(stream.next()).unwrap().unwrap();
        assert_eq!(event, Event::Message((peer_id.into(), consensus_msg)));

        // Network notifies consensus about new peer
        block_on(consensus_tx.send(NetworkNotification::NewPeer(peer_id))).unwrap();

        // Consensus should receive notification
        let event = block_on(stream.next()).unwrap().unwrap();
        assert_eq!(event, Event::NewPeer(peer_id.into()));
    }

    // `ConsensusNetworkSender` should serialize outbound messages
    #[test]
    fn test_consensus_network_sender() {
        let (network_reqs_tx, mut network_reqs_rx) = channel::new_test(8);
        let mut sender = ConsensusNetworkSender::new(network_reqs_tx);

        let peer_id = PeerId::random();
        let consensus_msg = new_test_vote();
        let expected_network_msg = Message {
            protocol: ProtocolId::from_static(CONSENSUS_DIRECT_SEND_PROTOCOL),
            mdata: consensus_msg.clone().write_to_bytes().unwrap().into(),
        };

        // Send the message to network layer
        block_on(sender.send_to(peer_id.into(), consensus_msg)).unwrap();

        // Network layer should receive serialized message to send out
        let event = block_on(network_reqs_rx.next()).unwrap();
        match event {
            NetworkRequest::SendMessage(recv_peer_id, network_msg) => {
                assert_eq!(recv_peer_id, peer_id);
                assert_eq!(network_msg, expected_network_msg);
            }
            event => panic!("Unexpected event: {:?}", event),
        }
    }

    // `ConsensusNetworkEvents` should deserialize inbound RPC requests
    #[test]
    fn test_consensus_inbound_rpc() {
        let (mut consensus_tx, consensus_rx) = channel::new_test(8);
        let mut stream = ConsensusNetworkEvents::new(consensus_rx);

        // build rpc request
        let req_msg = RequestBlock::new();
        let mut req_msg_enum = ConsensusMsg::new();
        req_msg_enum.set_request_block(req_msg);
        let req_data = req_msg_enum.clone().write_to_bytes().unwrap().into();

        let (res_tx, _) = oneshot::channel();
        let rpc_req = InboundRpcRequest {
            protocol: ProtocolId::from_static(CONSENSUS_RPC_PROTOCOL),
            data: req_data,
            res_tx,
        };

        // mock receiving rpc request
        let peer_id = PeerId::random();
        let event = NetworkNotification::RecvRpc(peer_id, rpc_req);
        block_on(consensus_tx.send(event)).unwrap();

        // request should be properly deserialized
        let (res_tx, _) = oneshot::channel();
        let expected_event = Event::RpcRequest((peer_id.into(), req_msg_enum.clone(), res_tx));
        let event = block_on(stream.next()).unwrap().unwrap();
        assert_eq!(event, expected_event);
    }

    // When consensus sends an rpc request, network should get a `NetworkRequest::SendRpc`
    // with the serialized request.
    #[test]
    fn test_consensus_outbound_rpc() {
        let (network_reqs_tx, mut network_reqs_rx) = channel::new_test(8);
        let mut sender = ConsensusNetworkSender::new(network_reqs_tx);

        // send get_block rpc request
        let peer_id = PeerId::random();
        let req_msg = RequestBlock::new();
        let f_res_msg =
            sender.request_block(peer_id.into(), req_msg.clone(), Duration::from_secs(5));

        // build rpc response
        let res_msg = RespondBlock::new();
        let mut res_msg_enum = ConsensusMsg::new();
        res_msg_enum.set_respond_block(res_msg.clone());
        let res_data = res_msg_enum.write_to_bytes().unwrap().into();

        // the future response
        let f_recv = async move {
            match network_reqs_rx.next().await.unwrap() {
                NetworkRequest::SendRpc(recv_peer_id, req) => {
                    assert_eq!(recv_peer_id, peer_id);
                    assert_eq!(req.protocol.as_ref(), CONSENSUS_RPC_PROTOCOL);

                    // check request deserializes
                    let mut req_msg_enum: ConsensusMsg =
                        ::protobuf::parse_from_bytes(req.data.as_ref()).unwrap();
                    let recv_req_msg = req_msg_enum.take_request_block();
                    assert_eq!(recv_req_msg, req_msg);

                    // remote replies with some response message
                    req.res_tx.send(Ok(res_data)).unwrap();
                    Ok(())
                }
                event => panic!("Unexpected event: {:?}", event),
            }
        };

        let (recv_res_msg, _) = block_on(try_join(f_res_msg, f_recv)).unwrap();
        assert_eq!(recv_res_msg, res_msg);
    }
}
<commit_msg>Migrate Consensus network client to use unary_rpc util function<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! Interface between Consensus and Network layers.

use crate::{
    error::NetworkError,
    interface::{NetworkNotification, NetworkRequest},
    proto::{ConsensusMsg, RequestBlock, RequestChunk, RespondBlock, RespondChunk},
    protocols::{
        direct_send::Message,
        rpc::{self, error::RpcError},
    },
    validator_network::Event,
    NetworkPublicKeys, ProtocolId,
};
use bytes::Bytes;
use channel;
use futures::{
    stream::Map,
    task::{Context, Poll},
    SinkExt, Stream, StreamExt,
};
use pin_utils::unsafe_pinned;
use protobuf::Message as proto_msg;
use std::{pin::Pin, time::Duration};
use types::{validator_public_keys::ValidatorPublicKeys, PeerId};

/// Protocol id for consensus RPC calls
pub const CONSENSUS_RPC_PROTOCOL: &[u8] = b"/libra/consensus/rpc/0.1.0";
/// Protocol id for consensus direct-send calls
pub const CONSENSUS_DIRECT_SEND_PROTOCOL: &[u8] = b"/libra/consensus/direct-send/0.1.0";

/// The interface from Network to Consensus layer.
///
/// `ConsensusNetworkEvents` is a `Stream` of `NetworkNotification` where the
/// raw `Bytes` direct-send and rpc messages are deserialized into
/// `ConsensusMessage` types. `ConsensusNetworkEvents` is a thin wrapper around
/// an `channel::Receiver<NetworkNotification>`.
pub struct ConsensusNetworkEvents {
    inner: Map<
        channel::Receiver<NetworkNotification>,
        fn(NetworkNotification) -> Result<Event<ConsensusMsg>, NetworkError>,
    >,
}

impl ConsensusNetworkEvents {
    // This use of `unsafe_pinned` is safe because:
    //   1. This struct does not implement [`Drop`]
    //   2. This struct does not implement [`Unpin`]
    //   3. This struct is not `#[repr(packed)]`
    unsafe_pinned!(
        inner:
            Map<
                channel::Receiver<NetworkNotification>,
                fn(NetworkNotification) -> Result<Event<ConsensusMsg>, NetworkError>,
            >
    );

    pub fn new(receiver: channel::Receiver<NetworkNotification>) -> Self {
        let inner = receiver.map::<_, fn(_) -> _>(|notification| match notification {
            NetworkNotification::NewPeer(peer_id) => Ok(Event::NewPeer(peer_id)),
            NetworkNotification::LostPeer(peer_id) => Ok(Event::LostPeer(peer_id)),
            NetworkNotification::RecvRpc(peer_id, rpc_req) => {
                let req_msg = ::protobuf::parse_from_bytes(rpc_req.data.as_ref())?;
                Ok(Event::RpcRequest((peer_id, req_msg, rpc_req.res_tx)))
            }
            NetworkNotification::RecvMessage(peer_id, msg) => {
                let msg = ::protobuf::parse_from_bytes(msg.mdata.as_ref())?;
                Ok(Event::Message((peer_id, msg)))
            }
        });

        Self { inner }
    }
}

impl Stream for ConsensusNetworkEvents {
    type Item = Result<Event<ConsensusMsg>, NetworkError>;

    fn poll_next(self: Pin<&mut Self>, context: &mut Context) -> Poll<Option<Self::Item>> {
        self.inner().poll_next(context)
    }
}

/// The interface from Consensus to Networking layer.
///
/// This is a thin wrapper around an `channel::Sender<NetworkRequest>`, so it is
/// easy to clone and send off to a separate task. For example, the rpc requests
/// return Futures that encapsulate the whole flow, from sending the request to
/// remote, to finally receiving the response and deserializing. It therefore
/// makes the most sense to make the rpc call on a separate async task, which
/// requires the `ConsensusNetworkSender` to be `Clone` and `Send`.
#[derive(Clone)]
pub struct ConsensusNetworkSender {
    inner: channel::Sender<NetworkRequest>,
}

impl ConsensusNetworkSender {
    pub fn new(inner: channel::Sender<NetworkRequest>) -> Self {
        Self { inner }
    }

    /// Send a fire-and-forget "direct-send" message to remote peer `recipient`.
    ///
    /// Currently, the returned Future simply resolves when the message has been
    /// enqueued on the network actor's event queue. It therefore makes no
    /// reliable delivery guarantees.
    pub async fn send_to(
        &mut self,
        recipient: PeerId,
        message: ConsensusMsg,
    ) -> Result<(), NetworkError> {
        self.inner
            .send(NetworkRequest::SendMessage(
                recipient,
                Message {
                    protocol: ProtocolId::from_static(CONSENSUS_DIRECT_SEND_PROTOCOL),
                    mdata: Bytes::from(message.write_to_bytes().unwrap()),
                },
            ))
            .await?;
        Ok(())
    }

    /// Send a RequestBlock RPC request to remote peer `recipient`. Returns the
    /// future `RespondBlock` returned by the remote peer.
    ///
    /// The rpc request can be canceled at any point by dropping the returned
    /// future.
    pub async fn request_block(
        &mut self,
        recipient: PeerId,
        req_msg: RequestBlock,
        timeout: Duration,
    ) -> Result<RespondBlock, RpcError> {
        let protocol = ProtocolId::from_static(CONSENSUS_RPC_PROTOCOL);
        let mut req_msg_enum = ConsensusMsg::new();
        req_msg_enum.set_request_block(req_msg);
        let mut res_msg_enum = rpc::utils::unary_rpc(
            self.inner.clone(),
            recipient,
            protocol,
            req_msg_enum,
            timeout,
        )
        .await?;

        if res_msg_enum.has_respond_block() {
            Ok(res_msg_enum.take_respond_block())
        } else {
            // TODO: context
            Err(RpcError::InvalidRpcResponse)
        }
    }

    /// Send a RequestChunk RPC request to remote peer `recipient`. Returns the
    /// future `RespondChunk` returned by the remote peer.
    ///
    /// The rpc request can be canceled at any point by dropping the returned
    /// future.
    pub async fn request_chunk(
        &mut self,
        recipient: PeerId,
        req_msg: RequestChunk,
        timeout: Duration,
    ) -> Result<RespondChunk, RpcError> {
        let protocol = ProtocolId::from_static(CONSENSUS_RPC_PROTOCOL);
        let mut req_msg_enum = ConsensusMsg::new();
        req_msg_enum.set_request_chunk(req_msg);

        let mut res_msg_enum = rpc::utils::unary_rpc(
            self.inner.clone(),
            recipient,
            protocol,
            req_msg_enum,
            timeout,
        )
        .await?;

        if res_msg_enum.has_respond_chunk() {
            Ok(res_msg_enum.take_respond_chunk())
        } else {
            // TODO: context
            Err(RpcError::InvalidRpcResponse)
        }
    }

    pub async fn update_eligible_nodes(
        &mut self,
        validators: Vec<ValidatorPublicKeys>,
    ) -> Result<(), NetworkError> {
        self.inner
            .send(NetworkRequest::UpdateEligibleNodes(
                validators
                    .into_iter()
                    .map(|keys| {
                        (
                            *keys.account_address(),
                            NetworkPublicKeys {
                                identity_public_key: keys.network_identity_public_key().clone(),
                                signing_public_key: keys.network_signing_public_key().clone(),
                            },
                        )
                    })
                    .collect(),
            ))
            .await?;
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{proto::Vote, protocols::rpc::InboundRpcRequest};
    use futures::{channel::oneshot, executor::block_on, future::try_join};

    fn new_test_vote() -> ConsensusMsg {
        let mut vote = Vote::new();
        vote.set_proposed_block_id(Bytes::new());
        vote.set_executed_state_id(Bytes::new());
        vote.set_author(Bytes::new());
        vote.set_signature(Bytes::new());

        let mut consensus_msg = ConsensusMsg::new();
        consensus_msg.set_vote(vote);
        consensus_msg
    }

    // Direct send messages should get deserialized through the
    // `ConsensusNetworkEvents` stream.
    #[test]
    fn test_consensus_network_events() {
        let (mut consensus_tx, consensus_rx) = channel::new_test(8);
        let mut stream = ConsensusNetworkEvents::new(consensus_rx);

        let peer_id = PeerId::random();
        let consensus_msg = new_test_vote();
        let network_msg = Message {
            protocol: ProtocolId::from_static(CONSENSUS_DIRECT_SEND_PROTOCOL),
            mdata: consensus_msg.clone().write_to_bytes().unwrap().into(),
        };

        // Network sends inbound message to consensus
        block_on(consensus_tx.send(NetworkNotification::RecvMessage(peer_id, network_msg)))
            .unwrap();

        // Consensus should receive deserialized message event
        let event = block_on(stream.next()).unwrap().unwrap();
        assert_eq!(event, Event::Message((peer_id.into(), consensus_msg)));

        // Network notifies consensus about new peer
        block_on(consensus_tx.send(NetworkNotification::NewPeer(peer_id))).unwrap();

        // Consensus should receive notification
        let event = block_on(stream.next()).unwrap().unwrap();
        assert_eq!(event, Event::NewPeer(peer_id.into()));
    }

    // `ConsensusNetworkSender` should serialize outbound messages
    #[test]
    fn test_consensus_network_sender() {
        let (network_reqs_tx, mut network_reqs_rx) = channel::new_test(8);
        let mut sender = ConsensusNetworkSender::new(network_reqs_tx);

        let peer_id = PeerId::random();
        let consensus_msg = new_test_vote();
        let expected_network_msg = Message {
            protocol: ProtocolId::from_static(CONSENSUS_DIRECT_SEND_PROTOCOL),
            mdata: consensus_msg.clone().write_to_bytes().unwrap().into(),
        };

        // Send the message to network layer
        block_on(sender.send_to(peer_id.into(), consensus_msg)).unwrap();

        // Network layer should receive serialized message to send out
        let event = block_on(network_reqs_rx.next()).unwrap();
        match event {
            NetworkRequest::SendMessage(recv_peer_id, network_msg) => {
                assert_eq!(recv_peer_id, peer_id);
                assert_eq!(network_msg, expected_network_msg);
            }
            event => panic!("Unexpected event: {:?}", event),
        }
    }

    // `ConsensusNetworkEvents` should deserialize inbound RPC requests
    #[test]
    fn test_consensus_inbound_rpc() {
        let (mut consensus_tx, consensus_rx) = channel::new_test(8);
        let mut stream = ConsensusNetworkEvents::new(consensus_rx);

        // build rpc request
        let req_msg = RequestBlock::new();
        let mut req_msg_enum = ConsensusMsg::new();
        req_msg_enum.set_request_block(req_msg);
        let req_data = req_msg_enum.clone().write_to_bytes().unwrap().into();

        let (res_tx, _) = oneshot::channel();
        let rpc_req = InboundRpcRequest {
            protocol: ProtocolId::from_static(CONSENSUS_RPC_PROTOCOL),
            data: req_data,
            res_tx,
        };

        // mock receiving rpc request
        let peer_id = PeerId::random();
        let event = NetworkNotification::RecvRpc(peer_id, rpc_req);
        block_on(consensus_tx.send(event)).unwrap();

        // request should be properly deserialized
        let (res_tx, _) = oneshot::channel();
        let expected_event = Event::RpcRequest((peer_id.into(), req_msg_enum.clone(), res_tx));
        let event = block_on(stream.next()).unwrap().unwrap();
        assert_eq!(event, expected_event);
    }

    // When consensus sends an rpc request, network should get a `NetworkRequest::SendRpc`
    // with the serialized request.
    #[test]
    fn test_consensus_outbound_rpc() {
        let (network_reqs_tx, mut network_reqs_rx) = channel::new_test(8);
        let mut sender = ConsensusNetworkSender::new(network_reqs_tx);

        // send get_block rpc request
        let peer_id = PeerId::random();
        let req_msg = RequestBlock::new();
        let f_res_msg =
            sender.request_block(peer_id.into(), req_msg.clone(), Duration::from_secs(5));

        // build rpc response
        let res_msg = RespondBlock::new();
        let mut res_msg_enum = ConsensusMsg::new();
        res_msg_enum.set_respond_block(res_msg.clone());
        let res_data = res_msg_enum.write_to_bytes().unwrap().into();

        // the future response
        let f_recv = async move {
            match network_reqs_rx.next().await.unwrap() {
                NetworkRequest::SendRpc(recv_peer_id, req) => {
                    assert_eq!(recv_peer_id, peer_id);
                    assert_eq!(req.protocol.as_ref(), CONSENSUS_RPC_PROTOCOL);

                    // check request deserializes
                    let mut req_msg_enum: ConsensusMsg =
                        ::protobuf::parse_from_bytes(req.data.as_ref()).unwrap();
                    let recv_req_msg = req_msg_enum.take_request_block();
                    assert_eq!(recv_req_msg, req_msg);

                    // remote replies with some response message
                    req.res_tx.send(Ok(res_data)).unwrap();
                    Ok(())
                }
                event => panic!("Unexpected event: {:?}", event),
            }
        };

        let (recv_res_msg, _) = block_on(try_join(f_res_msg, f_recv)).unwrap();
        assert_eq!(recv_res_msg, res_msg);
    }
}
<|endoftext|>


<commit_before>use projection::{Projector};
use common::{R, Deg, Dim, pow};
use polynomial::{Polynomial, PolyBorrowingMons, approx_equiv};
use monomial::{Monomial, Mon2d, MaxMonDeg};
use mesh::{FENum, OShape};
use rectangle_mesh::{RectMesh, MeshCoord};
use wg_basis::{WgBasis};

use std::vec;

#[test]
fn test_int_L2_inner_products_3x2_deg2() {
  let rmesh: ~RectMesh<Mon2d> = RectMesh::new(~[0.,0.], ~[3.,2.], ~[MeshCoord(3),MeshCoord(2)]);
  let basis = WgBasis::new(rmesh, MaxMonDeg(2), MaxMonDeg(1));

  let projector: ~Projector<Mon2d,RectMesh<Mon2d>>  = Projector::new(basis);

  let int_ips = projector.ips_int_mons_by_oshape[0];
  assert_eq!(int_ips.get(0,0), 1.);    // one vs one
  assert_eq!(int_ips.get(0,1), 1./2.); // one vs y
  assert_eq!(int_ips.get(0,2), 1./3.); // one vs y^2
  assert_eq!(int_ips.get(0,3), 1./2.); // one vs x
  assert_eq!(int_ips.get(0,4), 1./4.); // one vs xy
  assert_eq!(int_ips.get(0,5), 1./3.); // one vs x^2
}

#[test]
fn test_side_L2_inner_products_3x2_deg2() {
  let rmesh: ~RectMesh<Mon2d> = RectMesh::new(~[0.,0.], ~[3.,2.], ~[MeshCoord(3),MeshCoord(2)]);
  let basis = WgBasis::new(rmesh, MaxMonDeg(2), MaxMonDeg(1));

  let projector: ~Projector<Mon2d,RectMesh<Mon2d>>  = Projector::new(basis);

  let right_ips = projector.ips_side_mons_by_oshape_side[0][3];
  assert_eq!(right_ips.get(0,0), 1.);    // one vs one
  assert_eq!(right_ips.get(0,1), 1./2.); // one vs y
  assert_eq!(right_ips.get(1,1), 1./3.); // y vs y

  let top_ips = projector.ips_side_mons_by_oshape_side[0][1];
  assert_eq!(top_ips.get(0,0), 1.);    // one vs one
  assert_eq!(top_ips.get(0,1), 1./2.); // one vs x
  assert_eq!(top_ips.get(1,1), 1./3.); // x vs x
}

#[test]
fn test_identity_proj_fe0() {
  let rmesh: ~RectMesh<Mon2d> = RectMesh::new(~[0.,0.], ~[3.,2.], ~[MeshCoord(3),MeshCoord(2)]);
  let basis = WgBasis::new(rmesh, MaxMonDeg(3), MaxMonDeg(4));
  let mut projector: ~Projector<Mon2d,RectMesh<Mon2d>>  = Projector::new(basis);

  // 0 x^0y^0 + -2 x^0y^1 + 0 x^0y^2 + -0 x^0y^3 + 1 x^1y^0 + -3 x^1y^1 + -2 x^1y^2 + 0 x^2y^0 + 1 x^2y^1 + -0 x^3y^0
  let p = PolyBorrowingMons::new(~[0., -2., 0., 0., 1., -3., -2., 0., 1., 0.], basis.int_mons());

  let g = |x: &[R]| p.value_at(x);

  let proj = projector.projs_to_span_int_supp_basis_els(g, &[FENum(0)], OShape(0));

  assert!(approx_equiv(&proj[0], &p, 1e-10));
}

#[test]
fn test_identity_proj_fe4() {
  let rmesh: ~RectMesh<Mon2d> = RectMesh::new(~[0.,0.], ~[3.,2.], ~[MeshCoord(3),MeshCoord(4)]);

  let fe = FENum(4);
  let int_orig_0 = rmesh.fe_interior_origin_comp(fe, Dim(0));
  let int_orig_1 = rmesh.fe_interior_origin_comp(fe, Dim(1));

  let basis = WgBasis::new(rmesh, MaxMonDeg(3), MaxMonDeg(4));
  let mut projector: ~Projector<Mon2d,RectMesh<Mon2d>>  = Projector::new(basis);

  let g = |x: &[R]| {
    // x^2 y - 2 x y^2
    pow(x[0] - int_orig_0, 2) * (x[1] - int_orig_1) - 2. *  pow(x[0] - int_orig_0, 1) * pow(x[1] - int_orig_1, 2)
  };

  let proj = projector.projs_to_span_int_supp_basis_els(g, &[fe], OShape(0));

  let p = PolyBorrowingMons::new(~[0., 0., 0., 0., 0., 0., -2., 0., 1., 0.], basis.int_mons()); // x^2 y - 2 x y^2

  assert!(approx_equiv(&proj[0], &p, 1e-10));
}

// TODO: Side projection tests.

<commit_msg>Add side projections test.<commit_after>use projection::{Projector};
use common::{R, pow};
use polynomial::{Polynomial, PolyBorrowingMons, approx_equiv};
use monomial::{Monomial, Mon2d, MaxMonDeg};
use mesh::{FENum, OShape, SideFace};
use rectangle_mesh::{RectMesh, MeshCoord};
use wg_basis::{WgBasis};

#[test]
fn test_int_L2_inner_products_3x2_deg2() {
  let rmesh: ~RectMesh<Mon2d> = RectMesh::new(~[0.,0.], ~[3.,2.], ~[MeshCoord(3),MeshCoord(2)]);
  let basis = WgBasis::new(rmesh, MaxMonDeg(2), MaxMonDeg(1));

  let projector: ~Projector<Mon2d,RectMesh<Mon2d>>  = Projector::new(basis);

  let int_ips = projector.ips_int_mons_by_oshape[0];
  assert_eq!(int_ips.get(0,0), 1.);    // one vs one
  assert_eq!(int_ips.get(0,1), 1./2.); // one vs y
  assert_eq!(int_ips.get(0,2), 1./3.); // one vs y^2
  assert_eq!(int_ips.get(0,3), 1./2.); // one vs x
  assert_eq!(int_ips.get(0,4), 1./4.); // one vs xy
  assert_eq!(int_ips.get(0,5), 1./3.); // one vs x^2
}

#[test]
fn test_side_L2_inner_products_3x2_deg2() {
  let rmesh: ~RectMesh<Mon2d> = RectMesh::new(~[0.,0.], ~[3.,2.], ~[MeshCoord(3),MeshCoord(2)]);
  let basis = WgBasis::new(rmesh, MaxMonDeg(2), MaxMonDeg(1));

  let projector: ~Projector<Mon2d,RectMesh<Mon2d>>  = Projector::new(basis);

  let right_ips = projector.ips_side_mons_by_oshape_side[0][3];
  assert_eq!(right_ips.get(0,0), 1.);    // one vs one
  assert_eq!(right_ips.get(0,1), 1./2.); // one vs y
  assert_eq!(right_ips.get(1,1), 1./3.); // y vs y

  let top_ips = projector.ips_side_mons_by_oshape_side[0][1];
  assert_eq!(top_ips.get(0,0), 1.);    // one vs one
  assert_eq!(top_ips.get(0,1), 1./2.); // one vs x
  assert_eq!(top_ips.get(1,1), 1./3.); // x vs x
}

#[test]
fn test_identity_proj_fe0() {
  let rmesh: ~RectMesh<Mon2d> = RectMesh::new(~[0.,0.], ~[3.,2.], ~[MeshCoord(3),MeshCoord(2)]);
  let basis = WgBasis::new(rmesh, MaxMonDeg(3), MaxMonDeg(2));
  let mut projector: ~Projector<Mon2d,RectMesh<Mon2d>>  = Projector::new(basis);

  // 0 x^0y^0 + -2 x^0y^1 + 0 x^0y^2 + -0 x^0y^3 + 1 x^1y^0 + -3 x^1y^1 + -2 x^1y^2 + 0 x^2y^0 + 1 x^2y^1 + -0 x^3y^0
  let p = PolyBorrowingMons::new(~[0., -2., 0., 0., 1., -3., -2., 0., 1., 0.], basis.int_mons());

  let g = |x: &[R]| p.value_at(x);

  let proj = projector.projs_to_span_int_supp_basis_els(g, &[FENum(0)], OShape(0));

  assert!(approx_equiv(&proj[0], &p, 1e-10));
}

#[test]
fn test_int_projs() {
  let rmesh: ~RectMesh<Mon2d> = RectMesh::new(~[0.,0.], ~[3.,4.], ~[MeshCoord(3),MeshCoord(4)]);

  let fe4_int_orig_0 = 1.;
  let fe4_int_orig_1 = 1.;

  let basis = WgBasis::new(rmesh, MaxMonDeg(3), MaxMonDeg(2));
  let mut projector: ~Projector<Mon2d,RectMesh<Mon2d>>  = Projector::with_rhs_cols_capacity(basis, 2); // force a reallocation of rhs buffer

  let g = |x: &[R]| {
    // polynomial x^2 y - 2 x y^2 relative to fe 4 interior origin
    pow(x[0] - fe4_int_orig_0, 2) * (x[1] - fe4_int_orig_1) - 2. *  pow(x[0] - fe4_int_orig_0, 1) * pow(x[1] - fe4_int_orig_1, 2)
  };

  let projs = projector.projs_to_span_int_supp_basis_els(g, &[FENum(0),FENum(4),FENum(0),FENum(4),FENum(0)], OShape(0));

  // interior mons: x^0y^0, x^0y^1, x^0y^2, x^0y^3, x^1y^0, x^1y^1, x^1y^2, x^2y^0, x^2y^1, x^3y^0

  // g is x^2 y - 2 x y^2 expressed locally on fe4's interior.
  let fe4_proj = PolyBorrowingMons::new(~[0., 0., 0., 0., 0., 0., -2., 0., 1., 0.], basis.int_mons());

  //  g is (x-1)^2 (y-1) - 2 (x-1)(y-1)^2 = x^2*y - 2*x*y^2 - x^2 + 2*x*y + 2*y^2 - 3*y + 1 expressed locally on fe0's interior.
  let fe0_proj = PolyBorrowingMons::new(~[1., -3., 2., 0., 0., 2., -2., -1., 1., 0.], basis.int_mons());

  assert!(approx_equiv(&projs[0], &fe0_proj, 1e-10));
  assert!(approx_equiv(&projs[1], &fe4_proj, 1e-10));
  assert!(approx_equiv(&projs[2], &fe0_proj, 1e-10));
  assert!(approx_equiv(&projs[3], &fe4_proj, 1e-10));
  assert!(approx_equiv(&projs[4], &fe0_proj, 1e-10));
}

#[test]
fn test_right_side_projs() {
  let rmesh: ~RectMesh<Mon2d> = RectMesh::new(~[0.,0.], ~[3.,4.], ~[MeshCoord(3),MeshCoord(4)]);

  let fe5_int_orig_0 = 2.;
  let fe5_int_orig_1 = 1.;

  let basis = WgBasis::new(rmesh, MaxMonDeg(3), MaxMonDeg(2));
  let mut projector: ~Projector<Mon2d,RectMesh<Mon2d>>  = Projector::with_rhs_cols_capacity(basis, 2); // force a reallocation of rhs buffer

  // The function to be projected is the polynomial whose representation relative to fe 5's interior is
  //   p_fe5(x,y) = 2x^2 - 3y^2 - 5x - 4y (relative to fe 5 origin at (2,1)).
  // which expressed relative to the global origin (or also fe 0's interior) is polynomial
  //   p(x,y) = 2(x-2)^2 - 3(y-1)^2 - 5(x-2) - 4(y-1)
  let g = |x: &[R]| {
    let (x,y) = (x[0] - fe5_int_orig_0,
                 x[1] - fe5_int_orig_1);
    2.*pow(x, 2) - 3.*pow(y, 2) - 5.*x - 4.*y
  };

  let projs = projector.projs_to_span_side_supp_basis_els(g, &[FENum(0),FENum(5),FENum(0),FENum(5),FENum(0)], OShape(0), SideFace(1));

  let right_side_mons = basis.side_mons_for_fe_side(FENum(5), SideFace(1)); // vertical side monomials: x^0y^0, x^0y^1, x^0y^2

  // At a point (x,y) on fe5's right side, the polynomial to be projected has value
  //   p(x,y) = 2(1^2) - 3y^2 - 5(1) - 4y
  //          = -3 - 4y - 3y^2
  let fe5_proj = PolyBorrowingMons::new(~[-3., -4., -3.], right_side_mons);

  // At a point (x,y) on fe0's right side, the polynomial to be projected has value
  //   p(x,y) = 2(1-2)^2 - 3(y-1)^2 - 5(1-2) - 4(y-1)
  //          = 8 + 2y - 3y^2
  let fe0_proj = PolyBorrowingMons::new(~[8., 2., -3.], right_side_mons);

  assert!(approx_equiv(&projs[0], &fe0_proj, 1e-10));
  assert!(approx_equiv(&projs[1], &fe5_proj, 1e-10));
  assert!(approx_equiv(&projs[2], &fe0_proj, 1e-10));
  assert!(approx_equiv(&projs[3], &fe5_proj, 1e-10));
  assert!(approx_equiv(&projs[4], &fe0_proj, 1e-10));
}

<|endoftext|>


<commit_before>use clap::ArgMatches;
use fork_choice::ForkChoiceAlgorithm;
use network::NetworkConfig;
use slog::error;
use std::fs;
use std::net::SocketAddr;
use std::net::{IpAddr, Ipv4Addr};
use std::path::PathBuf;
use types::multiaddr::Protocol;
use types::multiaddr::ToMultiaddr;
use types::Multiaddr;
use types::{ChainSpec, EthSpec, LighthouseTestnetEthSpec};

#[derive(Debug, Clone)]
pub enum DBType {
    Memory,
    Disk,
}

/// Stores the client configuration for this Lighthouse instance.
#[derive(Debug, Clone)]
pub struct ClientConfig {
    pub data_dir: PathBuf,
    pub spec: ChainSpec,
    pub net_conf: network::NetworkConfig,
    pub fork_choice: ForkChoiceAlgorithm,
    pub db_type: DBType,
    pub db_name: PathBuf,
    pub rpc_conf: rpc::RPCConfig,
    //pub ipc_conf:
}

impl Default for ClientConfig {
    /// Build a new lighthouse configuration from defaults.
    fn default() -> Self {
        let data_dir = {
            let home = dirs::home_dir().expect("Unable to determine home dir.");
            home.join(".lighthouse/")
        };
        fs::create_dir_all(&data_dir)
            .unwrap_or_else(|_| panic!("Unable to create {:?}", &data_dir));

        let default_spec = LighthouseTestnetEthSpec::spec();
        let default_net_conf = NetworkConfig::new(default_spec.boot_nodes.clone());

        Self {
            data_dir: data_dir.clone(),
            // default to foundation for chain specs
            spec: default_spec,
            net_conf: default_net_conf,
            // default to bitwise LMD Ghost
            fork_choice: ForkChoiceAlgorithm::BitwiseLMDGhost,
            // default to memory db for now
            db_type: DBType::Memory,
            // default db name for disk-based dbs
            db_name: data_dir.join("chain_db"),
            rpc_conf: rpc::RPCConfig::default(),
        }
    }
}

impl ClientConfig {
    /// Parses the CLI arguments into a `Config` struct.
    pub fn parse_args(args: ArgMatches, log: &slog::Logger) -> Result<Self, &'static str> {
        let mut config = ClientConfig::default();

        /* Network related arguments */

        // Custom p2p listen port
        if let Some(port_str) = args.value_of("port") {
            if let Ok(port) = port_str.parse::<u16>() {
                config.net_conf.listen_port = port;
                // update the listening multiaddrs
                for address in &mut config.net_conf.listen_addresses {
                    address.pop();
                    address.append(Protocol::Tcp(port));
                }
            } else {
                error!(log, "Invalid port"; "port" => port_str);
                return Err("Invalid port");
            }
        }
        // Custom listening address ipv4/ipv6
        // TODO: Handle list of addresses
        if let Some(listen_address_str) = args.value_of("listen-address") {
            if let Ok(listen_address) = listen_address_str.parse::<IpAddr>() {
                let multiaddr = SocketAddr::new(listen_address, config.net_conf.listen_port)
                    .to_multiaddr()
                    .expect("Invalid listen address format");
                config.net_conf.listen_addresses = vec![multiaddr];
            } else {
                error!(log, "Invalid IP Address"; "Address" => listen_address_str);
                return Err("Invalid IP Address");
            }
        }

        // Custom bootnodes
        // TODO: Handle list of addresses
        if let Some(boot_addresses_str) = args.value_of("boot-nodes") {
            if let Ok(boot_address) = boot_addresses_str.parse::<Multiaddr>() {
                config.net_conf.boot_nodes.append(&mut vec![boot_address]);
            } else {
                error!(log, "Invalid Bootnode multiaddress"; "Multiaddr" => boot_addresses_str);
                return Err("Invalid IP Address");
            }
        }

        /* Filesystem related arguments */

        // Custom datadir
        if let Some(dir) = args.value_of("datadir") {
            config.data_dir = PathBuf::from(dir.to_string());
        };

        /* RPC related arguments */

        if args.is_present("rpc") {
            config.rpc_conf.enabled = true;
        }

        if let Some(rpc_address) = args.value_of("rpc-address") {
            if let Ok(listen_address) = rpc_address.parse::<Ipv4Addr>() {
                config.rpc_conf.listen_address = listen_address;
            } else {
                error!(log, "Invalid RPC listen address"; "Address" => rpc_address);
                return Err("Invalid RPC listen address");
            }
        }

        if let Some(rpc_port) = args.value_of("rpc-port") {
            if let Ok(port) = rpc_port.parse::<u16>() {
                config.rpc_conf.port = port;
            } else {
                error!(log, "Invalid RPC port"; "port" => rpc_port);
                return Err("Invalid RPC port");
            }
        }

        match args.value_of("db") {
            Some("disk") => config.db_type = DBType::Disk,
            Some("memory") => config.db_type = DBType::Memory,
            _ => unreachable!(), // clap prevents this.
        };

        Ok(config)
    }
}
<commit_msg>Support multiple bootnodes<commit_after>use clap::ArgMatches;
use fork_choice::ForkChoiceAlgorithm;
use network::NetworkConfig;
use slog::error;
use std::fs;
use std::net::SocketAddr;
use std::net::{IpAddr, Ipv4Addr};
use std::path::PathBuf;
use types::multiaddr::Protocol;
use types::multiaddr::ToMultiaddr;
use types::Multiaddr;
use types::{ChainSpec, EthSpec, LighthouseTestnetEthSpec};

#[derive(Debug, Clone)]
pub enum DBType {
    Memory,
    Disk,
}

/// Stores the client configuration for this Lighthouse instance.
#[derive(Debug, Clone)]
pub struct ClientConfig {
    pub data_dir: PathBuf,
    pub spec: ChainSpec,
    pub net_conf: network::NetworkConfig,
    pub fork_choice: ForkChoiceAlgorithm,
    pub db_type: DBType,
    pub db_name: PathBuf,
    pub rpc_conf: rpc::RPCConfig,
    //pub ipc_conf:
}

impl Default for ClientConfig {
    /// Build a new lighthouse configuration from defaults.
    fn default() -> Self {
        let data_dir = {
            let home = dirs::home_dir().expect("Unable to determine home dir.");
            home.join(".lighthouse/")
        };
        fs::create_dir_all(&data_dir)
            .unwrap_or_else(|_| panic!("Unable to create {:?}", &data_dir));

        let default_spec = LighthouseTestnetEthSpec::spec();
        let default_net_conf = NetworkConfig::new(default_spec.boot_nodes.clone());

        Self {
            data_dir: data_dir.clone(),
            // default to foundation for chain specs
            spec: default_spec,
            net_conf: default_net_conf,
            // default to bitwise LMD Ghost
            fork_choice: ForkChoiceAlgorithm::BitwiseLMDGhost,
            // default to memory db for now
            db_type: DBType::Memory,
            // default db name for disk-based dbs
            db_name: data_dir.join("chain_db"),
            rpc_conf: rpc::RPCConfig::default(),
        }
    }
}

impl ClientConfig {
    /// Parses the CLI arguments into a `Config` struct.
    pub fn parse_args(args: ArgMatches, log: &slog::Logger) -> Result<Self, &'static str> {
        let mut config = ClientConfig::default();

        /* Network related arguments */

        // Custom p2p listen port
        if let Some(port_str) = args.value_of("port") {
            if let Ok(port) = port_str.parse::<u16>() {
                config.net_conf.listen_port = port;
                // update the listening multiaddrs
                for address in &mut config.net_conf.listen_addresses {
                    address.pop();
                    address.append(Protocol::Tcp(port));
                }
            } else {
                error!(log, "Invalid port"; "port" => port_str);
                return Err("Invalid port");
            }
        }
        // Custom listening address ipv4/ipv6
        // TODO: Handle list of addresses
        if let Some(listen_address_str) = args.value_of("listen-address") {
            if let Ok(listen_address) = listen_address_str.parse::<IpAddr>() {
                let multiaddr = SocketAddr::new(listen_address, config.net_conf.listen_port)
                    .to_multiaddr()
                    .expect("Invalid listen address format");
                config.net_conf.listen_addresses = vec![multiaddr];
            } else {
                error!(log, "Invalid IP Address"; "Address" => listen_address_str);
                return Err("Invalid IP Address");
            }
        }

        // Custom bootnodes
        if let Some(boot_addresses_str) = args.value_of("boot-nodes") {
            let mut boot_addresses_split = boot_addresses_str.split(",");
            for boot_address in boot_addresses_split {
                if let Ok(boot_address) = boot_address.parse::<Multiaddr>() {
                    config.net_conf.boot_nodes.append(&mut vec![boot_address]);
                } else {
                    error!(log, "Invalid Bootnode multiaddress"; "Multiaddr" => boot_addresses_str);
                    return Err("Invalid IP Address");
                }
            }
        }

        /* Filesystem related arguments */

        // Custom datadir
        if let Some(dir) = args.value_of("datadir") {
            config.data_dir = PathBuf::from(dir.to_string());
        };

        /* RPC related arguments */

        if args.is_present("rpc") {
            config.rpc_conf.enabled = true;
        }

        if let Some(rpc_address) = args.value_of("rpc-address") {
            if let Ok(listen_address) = rpc_address.parse::<Ipv4Addr>() {
                config.rpc_conf.listen_address = listen_address;
            } else {
                error!(log, "Invalid RPC listen address"; "Address" => rpc_address);
                return Err("Invalid RPC listen address");
            }
        }

        if let Some(rpc_port) = args.value_of("rpc-port") {
            if let Ok(port) = rpc_port.parse::<u16>() {
                config.rpc_conf.port = port;
            } else {
                error!(log, "Invalid RPC port"; "port" => rpc_port);
                return Err("Invalid RPC port");
            }
        }

        match args.value_of("db") {
            Some("disk") => config.db_type = DBType::Disk,
            Some("memory") => config.db_type = DBType::Memory,
            _ => unreachable!(), // clap prevents this.
        };

        Ok(config)
    }
}
<|endoftext|>