<commit_before>//! FIXME: write short doc here

use ra_db::SourceDatabase;
use ra_syntax::{
    algo::ancestors_at_offset,
    ast::{self, ArgListOwner},
    AstNode, SyntaxNode, TextUnit,
};
use test_utils::tested_by;

use crate::{db::RootDatabase, CallInfo, FilePosition, FunctionSignature};

/// Computes parameter information for the given call expression.
pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> {
    let parse = db.parse(position.file_id);
    let syntax = parse.tree().syntax().clone();

    // Find the calling expression and it's NameRef
    let calling_node = FnCallNode::with_node(&syntax, position.offset)?;
    let name_ref = calling_node.name_ref()?;

    let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None);
    let (mut call_info, has_self) = match &calling_node {
        FnCallNode::CallExpr(expr) => {
            //FIXME: apply subst
            let (callable_def, _subst) = analyzer.type_of(db, &expr.expr()?)?.as_callable()?;
            match callable_def {
                hir::CallableDef::Function(it) => {
                    (CallInfo::with_fn(db, it), it.data(db).has_self_param())
                }
                hir::CallableDef::Struct(it) => (CallInfo::with_struct(db, it), false),
                hir::CallableDef::EnumVariant(it) => (CallInfo::with_enum_variant(db, it), false),
            }
        }
        FnCallNode::MethodCallExpr(expr) => {
            let function = analyzer.resolve_method_call(&expr)?;
            (CallInfo::with_fn(db, function), function.data(db).has_self_param())
        }
    };

    // If we have a calling expression let's find which argument we are on
    let num_params = call_info.parameters().len();

    if num_params == 1 {
        if !has_self {
            call_info.active_parameter = Some(0);
        }
    } else if num_params > 1 {
        // Count how many parameters into the call we are.
        if let Some(arg_list) = calling_node.arg_list() {
            // Number of arguments specified at the call site
            let num_args_at_callsite = arg_list.args().count();

            let arg_list_range = arg_list.syntax().text_range();
            if !arg_list_range.contains_inclusive(position.offset) {
                tested_by!(call_info_bad_offset);
                return None;
            }

            let mut param = std::cmp::min(
                num_args_at_callsite,
                arg_list
                    .args()
                    .take_while(|arg| arg.syntax().text_range().end() < position.offset)
                    .count(),
            );

            // If we are in a method account for `self`
            if has_self {
                param += 1;
            }

            call_info.active_parameter = Some(param);
        }
    }

    Some(call_info)
}

enum FnCallNode {
    CallExpr(ast::CallExpr),
    MethodCallExpr(ast::MethodCallExpr),
}

impl FnCallNode {
    fn with_node(syntax: &SyntaxNode, offset: TextUnit) -> Option<FnCallNode> {
        ancestors_at_offset(syntax, offset).find_map(|node| {
            if let Some(expr) = ast::CallExpr::cast(node.clone()) {
                Some(FnCallNode::CallExpr(expr))
            } else if let Some(expr) = ast::MethodCallExpr::cast(node.clone()) {
                Some(FnCallNode::MethodCallExpr(expr))
            } else {
                None
            }
        })
    }

    fn name_ref(&self) -> Option<ast::NameRef> {
        match self {
            FnCallNode::CallExpr(call_expr) => Some(match call_expr.expr()? {
                ast::Expr::PathExpr(path_expr) => path_expr.path()?.segment()?.name_ref()?,
                _ => return None,
            }),

            FnCallNode::MethodCallExpr(call_expr) => {
                call_expr.syntax().children().filter_map(ast::NameRef::cast).nth(0)
            }
        }
    }

    fn arg_list(&self) -> Option<ast::ArgList> {
        match self {
            FnCallNode::CallExpr(expr) => expr.arg_list(),
            FnCallNode::MethodCallExpr(expr) => expr.arg_list(),
        }
    }
}

impl CallInfo {
    fn with_fn(db: &RootDatabase, function: hir::Function) -> Self {
        let signature = FunctionSignature::from_hir(db, function);

        CallInfo { signature, active_parameter: None }
    }

    fn with_struct(db: &RootDatabase, st: hir::Struct) -> Self {
        let signature = FunctionSignature::from_struct(db, st);

        CallInfo { signature, active_parameter: None }
    }

    fn with_enum_variant(db: &RootDatabase, variant: hir::EnumVariant) -> Self {
        let signature = FunctionSignature::from_enum_variant(db, variant);

        CallInfo { signature, active_parameter: None }
    }

    fn parameters(&self) -> &[String] {
        &self.signature.parameters
    }
}

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

    use crate::mock_analysis::single_file_with_position;

    use super::*;

    // These are only used when testing
    impl CallInfo {
        fn doc(&self) -> Option<hir::Documentation> {
            self.signature.doc.clone()
        }

        fn label(&self) -> String {
            self.signature.to_string()
        }
    }

    fn call_info(text: &str) -> CallInfo {
        let (analysis, position) = single_file_with_position(text);
        analysis.call_info(position).unwrap().unwrap()
    }

    #[test]
    fn test_fn_signature_two_args_firstx() {
        let info = call_info(
            r#"fn foo(x: u32, y: u32) -> u32 {x + y}
fn bar() { foo(<|>3, ); }"#,
        );

        assert_eq!(info.parameters(), ["x: u32", "y: u32"]);
        assert_eq!(info.active_parameter, Some(0));
    }

    #[test]
    fn test_fn_signature_two_args_second() {
        let info = call_info(
            r#"fn foo(x: u32, y: u32) -> u32 {x + y}
fn bar() { foo(3, <|>); }"#,
        );

        assert_eq!(info.parameters(), ["x: u32", "y: u32"]);
        assert_eq!(info.active_parameter, Some(1));
    }

    #[test]
    fn test_fn_signature_two_args_empty() {
        let info = call_info(
            r#"fn foo(x: u32, y: u32) -> u32 {x + y}
fn bar() { foo(<|>); }"#,
        );

        assert_eq!(info.parameters(), ["x: u32", "y: u32"]);
        assert_eq!(info.active_parameter, Some(0));
    }

    #[test]
    fn test_fn_signature_two_args_first_generics() {
        let info = call_info(
            r#"fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 where T: Copy + Display, U: Debug {x + y}
fn bar() { foo(<|>3, ); }"#,
        );

        assert_eq!(info.parameters(), ["x: T", "y: U"]);
        assert_eq!(
            info.label(),
            r#"
fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
where T: Copy + Display,
      U: Debug
    "#
            .trim()
        );
        assert_eq!(info.active_parameter, Some(0));
    }

    #[test]
    fn test_fn_signature_no_params() {
        let info = call_info(
            r#"fn foo<T>() -> T where T: Copy + Display {}
fn bar() { foo(<|>); }"#,
        );

        assert!(info.parameters().is_empty());
        assert_eq!(
            info.label(),
            r#"
fn foo<T>() -> T
where T: Copy + Display
    "#
            .trim()
        );
        assert!(info.active_parameter.is_none());
    }

    #[test]
    fn test_fn_signature_for_impl() {
        let info = call_info(
            r#"struct F; impl F { pub fn new() { F{}} }
fn bar() {let _ : F = F::new(<|>);}"#,
        );

        assert!(info.parameters().is_empty());
        assert_eq!(info.active_parameter, None);
    }

    #[test]
    fn test_fn_signature_for_method_self() {
        let info = call_info(
            r#"struct F;
impl F {
    pub fn new() -> F{
        F{}
    }

    pub fn do_it(&self) {}
}

fn bar() {
    let f : F = F::new();
    f.do_it(<|>);
}"#,
        );

        assert_eq!(info.parameters(), ["&self"]);
        assert_eq!(info.active_parameter, None);
    }

    #[test]
    fn test_fn_signature_for_method_with_arg() {
        let info = call_info(
            r#"struct F;
impl F {
    pub fn new() -> F{
        F{}
    }

    pub fn do_it(&self, x: i32) {}
}

fn bar() {
    let f : F = F::new();
    f.do_it(<|>);
}"#,
        );

        assert_eq!(info.parameters(), ["&self", "x: i32"]);
        assert_eq!(info.active_parameter, Some(1));
    }

    #[test]
    fn test_fn_signature_with_docs_simple() {
        let info = call_info(
            r#"
/// test
// non-doc-comment
fn foo(j: u32) -> u32 {
    j
}

fn bar() {
    let _ = foo(<|>);
}
"#,
        );

        assert_eq!(info.parameters(), ["j: u32"]);
        assert_eq!(info.active_parameter, Some(0));
        assert_eq!(info.label(), "fn foo(j: u32) -> u32");
        assert_eq!(info.doc().map(|it| it.into()), Some("test".to_string()));
    }

    #[test]
    fn test_fn_signature_with_docs() {
        let info = call_info(
            r#"
/// Adds one to the number given.
///
/// # Examples
///
/// ```
/// let five = 5;
///
/// assert_eq!(6, my_crate::add_one(5));
/// ```
pub fn add_one(x: i32) -> i32 {
    x + 1
}

pub fn do() {
    add_one(<|>
}"#,
        );

        assert_eq!(info.parameters(), ["x: i32"]);
        assert_eq!(info.active_parameter, Some(0));
        assert_eq!(info.label(), "pub fn add_one(x: i32) -> i32");
        assert_eq!(
            info.doc().map(|it| it.into()),
            Some(
                r#"Adds one to the number given.

# Examples

```
let five = 5;

assert_eq!(6, my_crate::add_one(5));
```"#
                    .to_string()
            )
        );
    }

    #[test]
    fn test_fn_signature_with_docs_impl() {
        let info = call_info(
            r#"
struct addr;
impl addr {
    /// Adds one to the number given.
    ///
    /// # Examples
    ///
    /// ```
    /// let five = 5;
    ///
    /// assert_eq!(6, my_crate::add_one(5));
    /// ```
    pub fn add_one(x: i32) -> i32 {
        x + 1
    }
}

pub fn do_it() {
    addr {};
    addr::add_one(<|>);
}"#,
        );

        assert_eq!(info.parameters(), ["x: i32"]);
        assert_eq!(info.active_parameter, Some(0));
        assert_eq!(info.label(), "pub fn add_one(x: i32) -> i32");
        assert_eq!(
            info.doc().map(|it| it.into()),
            Some(
                r#"Adds one to the number given.

# Examples

```
let five = 5;

assert_eq!(6, my_crate::add_one(5));
```"#
                    .to_string()
            )
        );
    }

    #[test]
    fn test_fn_signature_with_docs_from_actix() {
        let info = call_info(
            r#"
struct WriteHandler<E>;

impl<E> WriteHandler<E> {
    /// Method is called when writer emits error.
    ///
    /// If this method returns `ErrorAction::Continue` writer processing
    /// continues otherwise stream processing stops.
    fn error(&mut self, err: E, ctx: &mut Self::Context) -> Running {
        Running::Stop
    }

    /// Method is called when writer finishes.
    ///
    /// By default this method stops actor's `Context`.
    fn finished(&mut self, ctx: &mut Self::Context) {
        ctx.stop()
    }
}

pub fn foo(mut r: WriteHandler<()>) {
    r.finished(<|>);
}

"#,
        );

        assert_eq!(info.parameters(), ["&mut self", "ctx: &mut Self::Context"]);
        assert_eq!(info.active_parameter, Some(1));
        assert_eq!(
            info.doc().map(|it| it.into()),
            Some(
                r#"Method is called when writer finishes.

By default this method stops actor's `Context`."#
                    .to_string()
            )
        );
    }

    #[test]
    fn call_info_bad_offset() {
        covers!(call_info_bad_offset);
        let (analysis, position) = single_file_with_position(
            r#"fn foo(x: u32, y: u32) -> u32 {x + y}
               fn bar() { foo <|> (3, ); }"#,
        );
        let call_info = analysis.call_info(position).unwrap();
        assert!(call_info.is_none());
    }

    #[test]
    fn test_nested_method_in_lamba() {
        let info = call_info(
            r#"struct Foo;

impl Foo {
    fn bar(&self, _: u32) { }
}

fn bar(_: u32) { }

fn main() {
    let foo = Foo;
    std::thread::spawn(move || foo.bar(<|>));
}"#,
        );

        assert_eq!(info.parameters(), ["&self", "_: u32"]);
        assert_eq!(info.active_parameter, Some(1));
        assert_eq!(info.label(), "fn bar(&self, _: u32)");
    }

    fn works_for_tuple_structs() {
        let info = call_info(
            r#"
/// A cool tuple struct
struct TS(u32, i32);
fn main() {
    let s = TS(0, <|>);
}"#,
        );

        assert_eq!(info.label(), "struct TS(0: u32, 1: i32) -> TS");
        assert_eq!(info.doc().map(|it| it.into()), Some("A cool tuple struct".to_string()));
        assert_eq!(info.active_parameter, Some(1));
    }

    #[test]
    fn works_for_enum_variants() {
        let info = call_info(
            r#"
enum E {
    /// A Variant
    A(i32),
    /// Another
    B,
    /// And C
    C { a: i32, b: i32 }
}

fn main() {
    let a = E::A(<|>);
}
            "#,
        );

        assert_eq!(info.label(), "E::A(0: i32)");
        assert_eq!(info.doc().map(|it| it.into()), Some("A Variant".to_string()));
        assert_eq!(info.active_parameter, Some(0));
    }
}
<commit_msg>formatting<commit_after>//! FIXME: write short doc here

use ra_db::SourceDatabase;
use ra_syntax::{
    algo::ancestors_at_offset,
    ast::{self, ArgListOwner},
    AstNode, SyntaxNode, TextUnit,
};
use test_utils::tested_by;

use crate::{db::RootDatabase, CallInfo, FilePosition, FunctionSignature};

/// Computes parameter information for the given call expression.
pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> {
    let parse = db.parse(position.file_id);
    let syntax = parse.tree().syntax().clone();

    // Find the calling expression and it's NameRef
    let calling_node = FnCallNode::with_node(&syntax, position.offset)?;
    let name_ref = calling_node.name_ref()?;

    let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None);
    let (mut call_info, has_self) = match &calling_node {
        FnCallNode::CallExpr(expr) => {
            //FIXME: apply subst
            let (callable_def, _subst) = analyzer.type_of(db, &expr.expr()?)?.as_callable()?;
            match callable_def {
                hir::CallableDef::Function(it) => {
                    (CallInfo::with_fn(db, it), it.data(db).has_self_param())
                }
                hir::CallableDef::Struct(it) => (CallInfo::with_struct(db, it), false),
                hir::CallableDef::EnumVariant(it) => (CallInfo::with_enum_variant(db, it), false),
            }
        }
        FnCallNode::MethodCallExpr(expr) => {
            let function = analyzer.resolve_method_call(&expr)?;
            (CallInfo::with_fn(db, function), function.data(db).has_self_param())
        }
    };

    // If we have a calling expression let's find which argument we are on
    let num_params = call_info.parameters().len();

    if num_params == 1 {
        if !has_self {
            call_info.active_parameter = Some(0);
        }
    } else if num_params > 1 {
        // Count how many parameters into the call we are.
        if let Some(arg_list) = calling_node.arg_list() {
            // Number of arguments specified at the call site
            let num_args_at_callsite = arg_list.args().count();

            let arg_list_range = arg_list.syntax().text_range();
            if !arg_list_range.contains_inclusive(position.offset) {
                tested_by!(call_info_bad_offset);
                return None;
            }

            let mut param = std::cmp::min(
                num_args_at_callsite,
                arg_list
                    .args()
                    .take_while(|arg| arg.syntax().text_range().end() < position.offset)
                    .count(),
            );

            // If we are in a method account for `self`
            if has_self {
                param += 1;
            }

            call_info.active_parameter = Some(param);
        }
    }

    Some(call_info)
}

enum FnCallNode {
    CallExpr(ast::CallExpr),
    MethodCallExpr(ast::MethodCallExpr),
}

impl FnCallNode {
    fn with_node(syntax: &SyntaxNode, offset: TextUnit) -> Option<FnCallNode> {
        ancestors_at_offset(syntax, offset).find_map(|node| {
            if let Some(expr) = ast::CallExpr::cast(node.clone()) {
                Some(FnCallNode::CallExpr(expr))
            } else if let Some(expr) = ast::MethodCallExpr::cast(node.clone()) {
                Some(FnCallNode::MethodCallExpr(expr))
            } else {
                None
            }
        })
    }

    fn name_ref(&self) -> Option<ast::NameRef> {
        match self {
            FnCallNode::CallExpr(call_expr) => Some(match call_expr.expr()? {
                ast::Expr::PathExpr(path_expr) => path_expr.path()?.segment()?.name_ref()?,
                _ => return None,
            }),

            FnCallNode::MethodCallExpr(call_expr) => {
                call_expr.syntax().children().filter_map(ast::NameRef::cast).nth(0)
            }
        }
    }

    fn arg_list(&self) -> Option<ast::ArgList> {
        match self {
            FnCallNode::CallExpr(expr) => expr.arg_list(),
            FnCallNode::MethodCallExpr(expr) => expr.arg_list(),
        }
    }
}

impl CallInfo {
    fn with_fn(db: &RootDatabase, function: hir::Function) -> Self {
        let signature = FunctionSignature::from_hir(db, function);

        CallInfo { signature, active_parameter: None }
    }

    fn with_struct(db: &RootDatabase, st: hir::Struct) -> Self {
        let signature = FunctionSignature::from_struct(db, st);

        CallInfo { signature, active_parameter: None }
    }

    fn with_enum_variant(db: &RootDatabase, variant: hir::EnumVariant) -> Self {
        let signature = FunctionSignature::from_enum_variant(db, variant);

        CallInfo { signature, active_parameter: None }
    }

    fn parameters(&self) -> &[String] {
        &self.signature.parameters
    }
}

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

    use crate::mock_analysis::single_file_with_position;

    use super::*;

    // These are only used when testing
    impl CallInfo {
        fn doc(&self) -> Option<hir::Documentation> {
            self.signature.doc.clone()
        }

        fn label(&self) -> String {
            self.signature.to_string()
        }
    }

    fn call_info(text: &str) -> CallInfo {
        let (analysis, position) = single_file_with_position(text);
        analysis.call_info(position).unwrap().unwrap()
    }

    #[test]
    fn test_fn_signature_two_args_firstx() {
        let info = call_info(
            r#"fn foo(x: u32, y: u32) -> u32 {x + y}
fn bar() { foo(<|>3, ); }"#,
        );

        assert_eq!(info.parameters(), ["x: u32", "y: u32"]);
        assert_eq!(info.active_parameter, Some(0));
    }

    #[test]
    fn test_fn_signature_two_args_second() {
        let info = call_info(
            r#"fn foo(x: u32, y: u32) -> u32 {x + y}
fn bar() { foo(3, <|>); }"#,
        );

        assert_eq!(info.parameters(), ["x: u32", "y: u32"]);
        assert_eq!(info.active_parameter, Some(1));
    }

    #[test]
    fn test_fn_signature_two_args_empty() {
        let info = call_info(
            r#"fn foo(x: u32, y: u32) -> u32 {x + y}
fn bar() { foo(<|>); }"#,
        );

        assert_eq!(info.parameters(), ["x: u32", "y: u32"]);
        assert_eq!(info.active_parameter, Some(0));
    }

    #[test]
    fn test_fn_signature_two_args_first_generics() {
        let info = call_info(
            r#"fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 where T: Copy + Display, U: Debug {x + y}
fn bar() { foo(<|>3, ); }"#,
        );

        assert_eq!(info.parameters(), ["x: T", "y: U"]);
        assert_eq!(
            info.label(),
            r#"
fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
where T: Copy + Display,
      U: Debug
    "#
            .trim()
        );
        assert_eq!(info.active_parameter, Some(0));
    }

    #[test]
    fn test_fn_signature_no_params() {
        let info = call_info(
            r#"fn foo<T>() -> T where T: Copy + Display {}
fn bar() { foo(<|>); }"#,
        );

        assert!(info.parameters().is_empty());
        assert_eq!(
            info.label(),
            r#"
fn foo<T>() -> T
where T: Copy + Display
    "#
            .trim()
        );
        assert!(info.active_parameter.is_none());
    }

    #[test]
    fn test_fn_signature_for_impl() {
        let info = call_info(
            r#"struct F; impl F { pub fn new() { F{}} }
fn bar() {let _ : F = F::new(<|>);}"#,
        );

        assert!(info.parameters().is_empty());
        assert_eq!(info.active_parameter, None);
    }

    #[test]
    fn test_fn_signature_for_method_self() {
        let info = call_info(
            r#"struct F;
impl F {
    pub fn new() -> F{
        F{}
    }

    pub fn do_it(&self) {}
}

fn bar() {
    let f : F = F::new();
    f.do_it(<|>);
}"#,
        );

        assert_eq!(info.parameters(), ["&self"]);
        assert_eq!(info.active_parameter, None);
    }

    #[test]
    fn test_fn_signature_for_method_with_arg() {
        let info = call_info(
            r#"struct F;
impl F {
    pub fn new() -> F{
        F{}
    }

    pub fn do_it(&self, x: i32) {}
}

fn bar() {
    let f : F = F::new();
    f.do_it(<|>);
}"#,
        );

        assert_eq!(info.parameters(), ["&self", "x: i32"]);
        assert_eq!(info.active_parameter, Some(1));
    }

    #[test]
    fn test_fn_signature_with_docs_simple() {
        let info = call_info(
            r#"
/// test
// non-doc-comment
fn foo(j: u32) -> u32 {
    j
}

fn bar() {
    let _ = foo(<|>);
}
"#,
        );

        assert_eq!(info.parameters(), ["j: u32"]);
        assert_eq!(info.active_parameter, Some(0));
        assert_eq!(info.label(), "fn foo(j: u32) -> u32");
        assert_eq!(info.doc().map(|it| it.into()), Some("test".to_string()));
    }

    #[test]
    fn test_fn_signature_with_docs() {
        let info = call_info(
            r#"
/// Adds one to the number given.
///
/// # Examples
///
/// ```
/// let five = 5;
///
/// assert_eq!(6, my_crate::add_one(5));
/// ```
pub fn add_one(x: i32) -> i32 {
    x + 1
}

pub fn do() {
    add_one(<|>
}"#,
        );

        assert_eq!(info.parameters(), ["x: i32"]);
        assert_eq!(info.active_parameter, Some(0));
        assert_eq!(info.label(), "pub fn add_one(x: i32) -> i32");
        assert_eq!(
            info.doc().map(|it| it.into()),
            Some(
                r#"Adds one to the number given.

# Examples

```
let five = 5;

assert_eq!(6, my_crate::add_one(5));
```"#
                    .to_string()
            )
        );
    }

    #[test]
    fn test_fn_signature_with_docs_impl() {
        let info = call_info(
            r#"
struct addr;
impl addr {
    /// Adds one to the number given.
    ///
    /// # Examples
    ///
    /// ```
    /// let five = 5;
    ///
    /// assert_eq!(6, my_crate::add_one(5));
    /// ```
    pub fn add_one(x: i32) -> i32 {
        x + 1
    }
}

pub fn do_it() {
    addr {};
    addr::add_one(<|>);
}"#,
        );

        assert_eq!(info.parameters(), ["x: i32"]);
        assert_eq!(info.active_parameter, Some(0));
        assert_eq!(info.label(), "pub fn add_one(x: i32) -> i32");
        assert_eq!(
            info.doc().map(|it| it.into()),
            Some(
                r#"Adds one to the number given.

# Examples

```
let five = 5;

assert_eq!(6, my_crate::add_one(5));
```"#
                    .to_string()
            )
        );
    }

    #[test]
    fn test_fn_signature_with_docs_from_actix() {
        let info = call_info(
            r#"
struct WriteHandler<E>;

impl<E> WriteHandler<E> {
    /// Method is called when writer emits error.
    ///
    /// If this method returns `ErrorAction::Continue` writer processing
    /// continues otherwise stream processing stops.
    fn error(&mut self, err: E, ctx: &mut Self::Context) -> Running {
        Running::Stop
    }

    /// Method is called when writer finishes.
    ///
    /// By default this method stops actor's `Context`.
    fn finished(&mut self, ctx: &mut Self::Context) {
        ctx.stop()
    }
}

pub fn foo(mut r: WriteHandler<()>) {
    r.finished(<|>);
}

"#,
        );

        assert_eq!(info.parameters(), ["&mut self", "ctx: &mut Self::Context"]);
        assert_eq!(info.active_parameter, Some(1));
        assert_eq!(
            info.doc().map(|it| it.into()),
            Some(
                r#"Method is called when writer finishes.

By default this method stops actor's `Context`."#
                    .to_string()
            )
        );
    }

    #[test]
    fn call_info_bad_offset() {
        covers!(call_info_bad_offset);
        let (analysis, position) = single_file_with_position(
            r#"fn foo(x: u32, y: u32) -> u32 {x + y}
               fn bar() { foo <|> (3, ); }"#,
        );
        let call_info = analysis.call_info(position).unwrap();
        assert!(call_info.is_none());
    }

    #[test]
    fn test_nested_method_in_lamba() {
        let info = call_info(
            r#"struct Foo;

impl Foo {
    fn bar(&self, _: u32) { }
}

fn bar(_: u32) { }

fn main() {
    let foo = Foo;
    std::thread::spawn(move || foo.bar(<|>));
}"#,
        );

        assert_eq!(info.parameters(), ["&self", "_: u32"]);
        assert_eq!(info.active_parameter, Some(1));
        assert_eq!(info.label(), "fn bar(&self, _: u32)");
    }

    fn works_for_tuple_structs() {
        let info = call_info(
            r#"
/// A cool tuple struct
struct TS(u32, i32);
fn main() {
    let s = TS(0, <|>);
}"#,
        );

        assert_eq!(info.label(), "struct TS(0: u32, 1: i32) -> TS");
        assert_eq!(info.doc().map(|it| it.into()), Some("A cool tuple struct".to_string()));
        assert_eq!(info.active_parameter, Some(1));
    }

    #[test]
    fn works_for_enum_variants() {
        let info = call_info(
            r#"
enum E {
    /// A Variant
    A(i32),
    /// Another
    B,
    /// And C
    C { a: i32, b: i32 }
}

fn main() {
    let a = E::A(<|>);
}
            "#,
        );

        assert_eq!(info.label(), "E::A(0: i32)");
        assert_eq!(info.doc().map(|it| it.into()), Some("A Variant".to_string()));
        assert_eq!(info.active_parameter, Some(0));
    }
}
<|endoftext|>


<commit_before>#![cfg(test)]

extern crate chrono;
extern crate tina;

use chrono::*;
use tina::*;

enum Diff { Up, Down, Same }

fn make_dummy_eew(maximum_intensity: Option<f32>) -> EEW
{
	EEW {
		issue_pattern: IssuePattern::HighAccuracy,
		source: Source::Tokyo, kind: Kind::Normal, issued_at: UTC.timestamp(12345, 0),
		occurred_at: UTC.timestamp(12345, 0), id: "XXX".to_owned(),
		status: Status::Normal, number: 1,
		detail: Some(EEWDetail {
			epicenter_name: "YYY".to_owned(),
			epicenter: (38.0, 142.0), depth: Some(10.0), magnitude: Some(5.9),
			maximum_intensity: maximum_intensity.map(|i| IntensityClass::new(i)),
			epicenter_accuracy: EpicenterAccuracy::Single, depth_accuracy: DepthAccuracy::Single,
			magnitude_accuracy: MagnitudeAccuracy::PWave,
			epicenter_category: EpicenterCategory::Sea, warning_status: WarningStatus::Forecast,
			intensity_change: IntensityChange::Unknown, change_reason: ChangeReason::Unknown,
			area_info: vec!{}
		})
	}
}

fn expect_eew_string(maximum_intensity: Option<IntensityClass>, updown: Diff) -> String
{
	let i_str = match maximum_intensity {
		None => "震度不明",
		Some(IntensityClass::Zero) => "震度0",
		Some(IntensityClass::One) => "震度1",
		Some(IntensityClass::Two) => "震度2",
		Some(IntensityClass::Three) => "震度3",
		Some(IntensityClass::Four) => "震度4",
		Some(IntensityClass::FiveLower) => "震度5弱",
		Some(IntensityClass::FiveUpper) => "震度5強",
		Some(IntensityClass::SixLower) => "震度6弱",
		Some(IntensityClass::SixUpper) => "震度6強",
		Some(IntensityClass::Seven) => "震度7"
	};
	let updown_str = match updown {
		Diff::Up => "↑",
		Diff::Down => "↓",
		Diff::Same => ""
	};
	return format!("[予報{}] YYY {} M5.9 10km (N38.0/E142.0) 12:25:45発生 | 第1報 XXX",
		updown_str, i_str);
}

#[test]
fn it_should_format_with_intensity_same_1()
{
	let eew1 = make_dummy_eew(Some(4.0));
	let eew2 = make_dummy_eew(Some(4.0));
	let expected = expect_eew_string(Some(IntensityClass::Four), Diff::Same);
	let result = ja_format_eew_short(&eew2, Some(&eew1));

	assert!(result.is_some());
	assert_eq!(result.unwrap(), expected);
}

#[test]
fn it_should_format_with_intensity_same_2()
{
	let eew1 = make_dummy_eew(Some(4.0));
	let eew2 = make_dummy_eew(Some(4.0));
	let expected = expect_eew_string(Some(IntensityClass::Four), Diff::Same);
	let result = ja_format_eew_short(&eew2, Some(&eew1));

	assert!(result.is_some());
	assert_eq!(result.unwrap(), expected);
}

#[test]
fn it_should_format_with_intensity_up_1()
{
	let eew1 = make_dummy_eew(Some(2.0));
	let eew2 = make_dummy_eew(Some(4.0));
	let expected = expect_eew_string(Some(IntensityClass::Four), Diff::Up);
	let result = ja_format_eew_short(&eew2, Some(&eew1));

	assert!(result.is_some());
	assert_eq!(result.unwrap(), expected);
}

#[test]
fn it_should_format_with_intensity_up_2()
{
	let eew1 = make_dummy_eew(None);
	let eew2 = make_dummy_eew(Some(4.0));
	let expected = expect_eew_string(Some(IntensityClass::Four), Diff::Up);
	let result = ja_format_eew_short(&eew2, Some(&eew1));

	assert!(result.is_some());
	assert_eq!(result.unwrap(), expected);
}

#[test]
fn it_should_format_with_intensity_down_1()
{
	let eew1 = make_dummy_eew(Some(4.0));
	let eew2 = make_dummy_eew(Some(2.0));
	let expected = expect_eew_string(Some(IntensityClass::Two), Diff::Down);
	let result = ja_format_eew_short(&eew2, Some(&eew1));

	assert!(result.is_some());
	assert_eq!(result.unwrap(), expected);
}

#[test]
fn it_should_format_with_intensity_down_2()
{
	let eew1 = make_dummy_eew(Some(4.0));
	let eew2 = make_dummy_eew(None);
	let expected = expect_eew_string(None, Diff::Down);
	let result = ja_format_eew_short(&eew2, Some(&eew1));

	assert!(result.is_some());
	assert_eq!(result.unwrap(), expected);
}
<commit_msg>Add more tests for ja_format_eew_short<commit_after>#![cfg(test)]

extern crate chrono;
extern crate tina;

use chrono::*;
use tina::*;

enum Diff { Up, Down, Same }

fn make_normal_eew(maximum_intensity: Option<IntensityClass>) -> EEW
{
	EEW {
		issue_pattern: IssuePattern::HighAccuracy,
		source: Source::Tokyo, kind: Kind::Normal, issued_at: UTC.timestamp(12345, 0),
		occurred_at: UTC.timestamp(12345, 0), id: "XXX".to_owned(),
		status: Status::Normal, number: 1,
		detail: Some(EEWDetail {
			epicenter_name: "YYY".to_owned(),
			epicenter: (38.0, 142.0), depth: Some(10.0), magnitude: Some(5.9),
			maximum_intensity: maximum_intensity,
			epicenter_accuracy: EpicenterAccuracy::Single, depth_accuracy: DepthAccuracy::Single,
			magnitude_accuracy: MagnitudeAccuracy::PWave,
			epicenter_category: EpicenterCategory::Sea, warning_status: WarningStatus::Forecast,
			intensity_change: IntensityChange::Unknown, change_reason: ChangeReason::Unknown,
			area_info: vec!{}
		})
	}
}

fn make_cancel_eew() -> EEW
{
	EEW {
		issue_pattern: IssuePattern::Cancel, source: Source::Tokyo, kind: Kind::Cancel,
		issued_at: UTC.timestamp(12345, 0), occurred_at: UTC.timestamp(12345, 0),
		id: "ZZZ".to_string(), status: Status::Normal, number: 1, detail: None
	}
}

fn expect_normal_eew_string(maximum_intensity: Option<IntensityClass>, updown: Diff) -> String
{
	let i_str = match maximum_intensity {
		None => "震度不明",
		Some(IntensityClass::Zero) => "震度0",
		Some(IntensityClass::One) => "震度1",
		Some(IntensityClass::Two) => "震度2",
		Some(IntensityClass::Three) => "震度3",
		Some(IntensityClass::Four) => "震度4",
		Some(IntensityClass::FiveLower) => "震度5弱",
		Some(IntensityClass::FiveUpper) => "震度5強",
		Some(IntensityClass::SixLower) => "震度6弱",
		Some(IntensityClass::SixUpper) => "震度6強",
		Some(IntensityClass::Seven) => "震度7"
	};
	let updown_str = match updown {
		Diff::Up => "↑",
		Diff::Down => "↓",
		Diff::Same => ""
	};
	return format!("[予報{}] YYY {} M5.9 10km (N38.0/E142.0) 12:25:45発生 | 第1報 XXX",
		updown_str, i_str);
}

fn expect_cancel_eew_string() -> String
{
	"[取消] --- | 第1報 ZZZ".to_string()
}

#[test]
fn it_should_format_with_intensity_same()
{
	let eew1 = make_normal_eew(Some(IntensityClass::Four));
	let eew2 = make_normal_eew(Some(IntensityClass::Four));
	let expected = expect_normal_eew_string(Some(IntensityClass::Four), Diff::Same);
	let result = ja_format_eew_short(&eew2, Some(&eew1));

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_with_intensity_up()
{
	let eew1 = make_normal_eew(Some(IntensityClass::Zero));
	let eew2 = make_normal_eew(Some(IntensityClass::Four));
	let expected = expect_normal_eew_string(Some(IntensityClass::Four), Diff::Up);
	let result = ja_format_eew_short(&eew2, Some(&eew1));

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_with_intensity_up_from_unknown()
{
	let eew1 = make_normal_eew(None);
	let eew2 = make_normal_eew(Some(IntensityClass::Zero));
	let expected = expect_normal_eew_string(Some(IntensityClass::Zero), Diff::Up);
	let result = ja_format_eew_short(&eew2, Some(&eew1));

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_with_intensity_down()
{
	let eew1 = make_normal_eew(Some(IntensityClass::Four));
	let eew2 = make_normal_eew(Some(IntensityClass::Zero));
	let expected = expect_normal_eew_string(Some(IntensityClass::Zero), Diff::Down);
	let result = ja_format_eew_short(&eew2, Some(&eew1));

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_with_intensity_down_to_unknown()
{
	let eew1 = make_normal_eew(Some(IntensityClass::Four));
	let eew2 = make_normal_eew(None);
	let expected = expect_normal_eew_string(None, Diff::Down);
	let result = ja_format_eew_short(&eew2, Some(&eew1));

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_from_normal_to_cancel()
{
	let eew1 = make_normal_eew(Some(IntensityClass::Four));
	let eew2 = make_cancel_eew();
	let expected = expect_cancel_eew_string();
	let result = ja_format_eew_short(&eew2, Some(&eew1));

	assert_eq!(result, Some(expected));
}

#[test]
fn it_should_format_from_cancel_to_normal()
{
	let eew1 = make_cancel_eew();
	let eew2 = make_normal_eew(Some(IntensityClass::Four));
	let expected = expect_normal_eew_string(Some(IntensityClass::Four), Diff::Same);
	let result = ja_format_eew_short(&eew2, Some(&eew1));

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


<commit_before>#[macro_use] extern crate rocket;
extern crate redis;
use redis::Commands;

use serde::{Serialize, Deserialize};
use rocket::serde::json::Json;

#[derive(Serialize, Deserialize, Debug)]
struct User {
    name: String,
    status: String
}

fn getcon() -> Result<redis::Connection,redis::RedisError> {
    let client = redis::Client::open("redis://127.0.0.1/")?;
    client.get_connection()
}

fn get(id:String) -> Result<String,redis::RedisError> {
    let x:Result<String,redis::RedisError> = getcon()?.get(id);
    x.or(Ok("".to_string()))
}
fn set(id:String,val:String) -> Result<(),redis::RedisError> {
    getcon()?.set(&id,val)
}

#[get("/r/<id>")]
fn r(id:String) -> Json<User> {
    let u = User { name: id.to_string(), status: get(id).unwrap() };
    Json(u)
}

// s/b post
#[get("/s/<id>?<val>")]
fn s(id:String, val:String) -> Json<User> {
    set(id.to_string(),val).unwrap();
    r(id)
}

#[launch]
fn rocket() -> _ {
    rocket::build().mount("/", routes![r,s])
}
<commit_msg>add batch<commit_after>#[macro_use] extern crate rocket;
extern crate redis;
use redis::Commands;

use serde::{Serialize, Deserialize};
use rocket::serde::json::Json;

#[derive(Serialize, Deserialize, Debug)]
struct User {
    name: String,
    status: String
}

fn getcon() -> Result<redis::Connection,redis::RedisError> {
    let client = redis::Client::open("redis://127.0.0.1/")?;
    client.get_connection()
}

fn get(id:String) -> Result<String,redis::RedisError> {
    let x:Result<String,redis::RedisError> = getcon()?.get(id);
    x.or(Ok("".to_string()))
}
fn set(id:String,val:String) -> Result<(),redis::RedisError> {
    getcon()?.set(&id,val)
}

#[get("/r/<id>")]
fn r(id:String) -> Json<User> {
    let u = User { name: id.to_string(), status: get(id).unwrap() };
    Json(u)
}

// s/b post
#[get("/s/<id>?<val>")]
fn s(id:String, val:String) -> Json<User> {
    set(id.to_string(),val).unwrap();
    r(id)
}

// curl http://127.0.0.1:8000/ra -X POST -H 'Content-Type: application/json' -d '["1","2"]'
#[post("/ra",format="json",data="<message>")]
fn ra(message:Json<Vec<String>>) -> Json<Vec<User>> {
    let v:Vec<User> = message.to_vec().iter().map(|m| {
      let id = m.to_string();
      let u = User { name: id.to_string(), status: get(id).unwrap() };
      u
    }).collect();
    Json(v)
}

#[launch]
fn rocket() -> _ {
    rocket::build().mount("/", routes![r,s,ra])
}
<|endoftext|>


<commit_before>
use super::ir::*;

// Overload priority
// =================
//
// Testing the priority of functions when passed arguments of a given type:
//
// bool (+ bool literals):           bool     -> uint/int/float/double                              -> half
// int (+ type casted int literals): int      -> uint                  -> bool -> float/double      -> half
// untyped int literal:                          uint/int              -> bool -> float/double/half
// uint (+ uint literals):           uint     -> int                   -> bool -> float/double      -> half
// half:                             half     -> float/double                  -> bool/int/uint
// float:                            float    -> double                        -> bool/int/uint/half
// double:                           double                                    -> bool/int/uint/float/half
//
// lvalue / rvalue didn't seem to make a difference. These don't seem consistent with C or C++
// rules.
//
// Priority:
// 1) Exact matches fit first (untyped int literal could be either)
// 2) Promotion
// 3) Bool if the source is an int
// 4) Any convertible type, except:
// 5) Halfs if you're an bool/int/uint, unless it's an untyped literal (something to do with halfs being smaller than int/uint but not literals???)
//
// I was going to try to implement nice logic in here, but I honestly have no idea what rules govern these priorities.

#[derive(PartialEq, Debug, Clone)]
pub enum ConversionRank {
    Exact,
    Promotion,
    IntToBool,
    Conversion,
    HalfIsASecondClassCitizen,
}

#[derive(PartialEq, Debug, Clone)]
pub enum ConversionPriority {
    Better,
    Equal,
    Worse,
}

#[derive(PartialEq, Debug, Clone, Copy)]
enum NumericDimension {
    Scalar,
    Vector(u32),
    Matrix(u32, u32),
}

#[derive(PartialEq, Debug, Clone)]
struct NumericCast(ScalarType, ScalarType, NumericDimension);

#[derive(PartialEq, Debug, Clone)]
struct ValueTypeCast(Type, ValueType, ValueType);

#[derive(PartialEq, Debug, Clone)]
pub struct ImplicitConversion(ExpressionType, Option<ValueTypeCast>, Option<NumericCast>);

impl ConversionRank {
    pub fn compare(&self, other: &ConversionRank) -> ConversionPriority {
        let my_order = self.order();
        let other_order = other.order();
        match (my_order < other_order, my_order <= other_order) {
            (false, false) => ConversionPriority::Worse,
            (false, true) => ConversionPriority::Equal,
            (true, false) => unreachable!(),
            (true, true) => ConversionPriority::Better,
        }
    }

    fn order(&self) -> u32 {
        match *self {
            ConversionRank::Exact => 0,
            ConversionRank::Promotion => 1,
            ConversionRank::IntToBool => 2,
            ConversionRank::Conversion => 3,
            ConversionRank::HalfIsASecondClassCitizen => 4,
        }
    }
}

impl NumericCast {

    fn new(source: &ScalarType, dest: &ScalarType, dim: NumericDimension) -> Result<NumericCast, ()> {
        match *dest {
            _ if source == dest => Err(()),
            ScalarType::Bool | ScalarType::Int | ScalarType::UInt | ScalarType::Half | ScalarType::Float | ScalarType::Double => {
                Ok(NumericCast(source.clone(), dest.clone(), dim))
            },
            ScalarType::UntypedInt => Err(()),
        }
    }

    fn get_rank(&self) -> ConversionRank {
        match *self {
            NumericCast(ScalarType::Bool, ref dest, _) => {
                match *dest {
                    ScalarType::Bool => ConversionRank::Exact,
                    ScalarType::Int | ScalarType::UInt | ScalarType::Float | ScalarType::Double => ConversionRank::Conversion,
                    ScalarType::Half => ConversionRank::HalfIsASecondClassCitizen,
                    ScalarType::UntypedInt => panic!(),
                }
            },
            NumericCast(ScalarType::UntypedInt, ref dest, _) => {
                match *dest {
                    ScalarType::Int | ScalarType::UInt => ConversionRank::Promotion,
                    ScalarType::Bool => ConversionRank::IntToBool,
                    ScalarType::Float | ScalarType::Double | ScalarType::Half => ConversionRank::Conversion,
                    ScalarType::UntypedInt => panic!(),
                }
            },
            NumericCast(ScalarType::Int, ref dest, _) => {
                match *dest {
                    ScalarType::Int => ConversionRank::Exact,
                    ScalarType::UInt => ConversionRank::Promotion,
                    ScalarType::Bool => ConversionRank::IntToBool,
                    ScalarType::Float | ScalarType::Double => ConversionRank::Conversion,
                    ScalarType::Half => ConversionRank::HalfIsASecondClassCitizen,
                    ScalarType::UntypedInt => panic!(),
                }
            },
            NumericCast(ScalarType::UInt, ref dest, _) => {
                match *dest {
                    ScalarType::UInt => ConversionRank::Exact,
                    ScalarType::Int => ConversionRank::Promotion,
                    ScalarType::Bool => ConversionRank::IntToBool,
                    ScalarType::Float | ScalarType::Double => ConversionRank::Conversion,
                    ScalarType::Half => ConversionRank::HalfIsASecondClassCitizen,
                    ScalarType::UntypedInt => panic!(),
                }
            },
            NumericCast(ScalarType::Half, ref dest, _) => {
                match *dest {
                    ScalarType::Half => ConversionRank::Exact,
                    ScalarType::Float | ScalarType::Double => ConversionRank::Promotion,
                    ScalarType::Bool | ScalarType::Int | ScalarType::UInt => ConversionRank::Conversion,
                    ScalarType::UntypedInt => panic!(),
                }
            },
            NumericCast(ScalarType::Float, ref dest, _) => {
                match *dest {
                    ScalarType::Float => ConversionRank::Exact,
                    ScalarType::Double => ConversionRank::Promotion,
                    ScalarType::Bool | ScalarType::Int | ScalarType::UInt | ScalarType::Half => ConversionRank::Conversion,
                    ScalarType::UntypedInt => panic!(),
                }
            },
            NumericCast(ScalarType::Double, ref dest, _) => {
                match *dest {
                    ScalarType::Double => ConversionRank::Exact,
                    ScalarType::Bool | ScalarType::Int | ScalarType::UInt | ScalarType::Half | ScalarType::Float => ConversionRank::Conversion,
                    ScalarType::UntypedInt => panic!(),
                }
            },
        }
    }

    fn get_target_type(&self) -> ExpressionType {
        Type::from_layout(match self.2 {
            NumericDimension::Scalar => TypeLayout::Scalar(self.1.clone()),
            NumericDimension::Vector(ref x) => TypeLayout::Vector(self.1.clone(), *x),
            NumericDimension::Matrix(ref x, ref y) => TypeLayout::Matrix(self.1.clone(), *x, *y),
        }).to_rvalue()
    }

    fn apply(&self, expr: Expression) -> Expression {
        let &NumericCast(_, ref dest, ref dim) = self;
        let to_type_data = match *dim {
            NumericDimension::Scalar => TypeLayout::Scalar(dest.clone()),
            NumericDimension::Vector(ref x) => TypeLayout::Vector(dest.clone(), *x),
            NumericDimension::Matrix(ref x, ref y) => TypeLayout::Matrix(dest.clone(), *x, *y),
        };
        Expression::Cast(Type::from_layout(to_type_data), Box::new(expr))
    }
}

impl ValueTypeCast {
    fn get_target_type(&self) -> ExpressionType {
        ExpressionType(self.0.clone(), self.2.clone())
    }
}

impl ImplicitConversion {

    pub fn find(source: &ExpressionType, dest: &ExpressionType) -> Result<ImplicitConversion, ()> {

        let source_copy = source.clone();
        let (source_type, dest_type, value_type_cast) = match (&source.1, &dest.1) {
            (&ValueType::Rvalue, &ValueType::Lvalue) => return Err(()),
            (&ValueType::Rvalue, &ValueType::Rvalue) | (&ValueType::Lvalue, &ValueType::Lvalue) => (&source.0, &dest.0, None),
            (&ValueType::Lvalue, &ValueType::Rvalue) => (&source.0, &dest.0, Some(ValueTypeCast(source.0.clone(), ValueType::Lvalue, ValueType::Rvalue))),
        };

        let &Type(ref source_l, ref mods) = source_type;
        assert!(mods.is_empty());
        let &Type(ref dest_l, ref modd) = dest_type;
        assert!(modd.is_empty());
        let numeric_cast = match (source_l, dest_l) {
            (ref ty1, ref ty2) if ty1 == ty2 => None,
            (&TypeLayout::Scalar(ref s1), &TypeLayout::Scalar(ref s2)) => {
                let cast = try!(NumericCast::new(s1, s2, NumericDimension::Scalar));
                Some(cast)
            },
            (&TypeLayout::Vector(ref s1, ref x1), &TypeLayout::Vector(ref s2, ref x2)) if x1 == x2 => {
                let cast = try!(NumericCast::new(s1, s2, NumericDimension::Vector(*x2)));
                Some(cast)
            },
            (&TypeLayout::Matrix(ref s1, ref x1, ref y1), &TypeLayout::Matrix(ref s2, ref x2, ref y2)) if x1 == x2 && y1 == y2 => {
                let cast = try!(NumericCast::new(s1, s2, NumericDimension::Matrix(*x2, *y2)));
                Some(cast)
            },
            // Vector <-> Matrix casts not implemented
            // Struct casts only supported for same type structs
            _ => return Err(()),
        };
        Ok(ImplicitConversion(source_copy, value_type_cast, numeric_cast))
    }

    pub fn get_rank(&self) -> ConversionRank {
        match *self {
            ImplicitConversion(_, _, None) => ConversionRank::Exact,
            ImplicitConversion(_, _, Some(ref numeric)) => numeric.get_rank(),
        }
    }

     pub fn get_target_type(&self) -> ExpressionType {
        match *self {
            ImplicitConversion(ref source_type, None, None) => match source_type.clone() {
                ExpressionType(ty, _) => ExpressionType(ty, ValueType::Rvalue)
            },
            ImplicitConversion(_, Some(ref vtc), None) => vtc.get_target_type(),
            ImplicitConversion(_, _, Some(ref numeric)) => numeric.get_target_type(),
        }
    }

    pub fn apply(&self, expr: Expression) -> Expression {
        match *self {
            ImplicitConversion(_, _, None) => expr,
            ImplicitConversion(_, _, Some(ref cast)) => cast.apply(expr),
        }
    }
}
<commit_msg>Add a few casting related tests<commit_after>
use super::ir::*;

// Overload priority
// =================
//
// Testing the priority of functions when passed arguments of a given type:
//
// bool (+ bool literals):           bool     -> uint/int/float/double                              -> half
// int (+ type casted int literals): int      -> uint                  -> bool -> float/double      -> half
// untyped int literal:                          uint/int              -> bool -> float/double/half
// uint (+ uint literals):           uint     -> int                   -> bool -> float/double      -> half
// half:                             half     -> float/double                  -> bool/int/uint
// float:                            float    -> double                        -> bool/int/uint/half
// double:                           double                                    -> bool/int/uint/float/half
//
// lvalue / rvalue didn't seem to make a difference. These don't seem consistent with C or C++
// rules.
//
// Priority:
// 1) Exact matches fit first (untyped int literal could be either)
// 2) Promotion
// 3) Bool if the source is an int
// 4) Any convertible type, except:
// 5) Halfs if you're an bool/int/uint, unless it's an untyped literal (something to do with halfs being smaller than int/uint but not literals???)
//
// I was going to try to implement nice logic in here, but I honestly have no idea what rules govern these priorities.

#[derive(PartialEq, Debug, Clone)]
pub enum ConversionRank {
    Exact,
    Promotion,
    IntToBool,
    Conversion,
    HalfIsASecondClassCitizen,
}

#[derive(PartialEq, Debug, Clone)]
pub enum ConversionPriority {
    Better,
    Equal,
    Worse,
}

#[derive(PartialEq, Debug, Clone, Copy)]
enum NumericDimension {
    Scalar,
    Vector(u32),
    Matrix(u32, u32),
}

#[derive(PartialEq, Debug, Clone)]
struct NumericCast(ScalarType, ScalarType, NumericDimension);

#[derive(PartialEq, Debug, Clone)]
struct ValueTypeCast(Type, ValueType, ValueType);

#[derive(PartialEq, Debug, Clone)]
pub struct ImplicitConversion(ExpressionType, Option<ValueTypeCast>, Option<NumericCast>);

impl ConversionRank {
    pub fn compare(&self, other: &ConversionRank) -> ConversionPriority {
        let my_order = self.order();
        let other_order = other.order();
        match (my_order < other_order, my_order <= other_order) {
            (false, false) => ConversionPriority::Worse,
            (false, true) => ConversionPriority::Equal,
            (true, false) => unreachable!(),
            (true, true) => ConversionPriority::Better,
        }
    }

    fn order(&self) -> u32 {
        match *self {
            ConversionRank::Exact => 0,
            ConversionRank::Promotion => 1,
            ConversionRank::IntToBool => 2,
            ConversionRank::Conversion => 3,
            ConversionRank::HalfIsASecondClassCitizen => 4,
        }
    }
}

impl NumericCast {

    fn new(source: &ScalarType, dest: &ScalarType, dim: NumericDimension) -> Result<NumericCast, ()> {
        match *dest {
            _ if source == dest => Err(()),
            ScalarType::Bool | ScalarType::Int | ScalarType::UInt | ScalarType::Half | ScalarType::Float | ScalarType::Double => {
                Ok(NumericCast(source.clone(), dest.clone(), dim))
            },
            ScalarType::UntypedInt => Err(()),
        }
    }

    fn get_rank(&self) -> ConversionRank {
        match *self {
            NumericCast(ScalarType::Bool, ref dest, _) => {
                match *dest {
                    ScalarType::Bool => ConversionRank::Exact,
                    ScalarType::Int | ScalarType::UInt | ScalarType::Float | ScalarType::Double => ConversionRank::Conversion,
                    ScalarType::Half => ConversionRank::HalfIsASecondClassCitizen,
                    ScalarType::UntypedInt => panic!(),
                }
            },
            NumericCast(ScalarType::UntypedInt, ref dest, _) => {
                match *dest {
                    ScalarType::Int | ScalarType::UInt => ConversionRank::Promotion,
                    ScalarType::Bool => ConversionRank::IntToBool,
                    ScalarType::Float | ScalarType::Double | ScalarType::Half => ConversionRank::Conversion,
                    ScalarType::UntypedInt => panic!(),
                }
            },
            NumericCast(ScalarType::Int, ref dest, _) => {
                match *dest {
                    ScalarType::Int => ConversionRank::Exact,
                    ScalarType::UInt => ConversionRank::Promotion,
                    ScalarType::Bool => ConversionRank::IntToBool,
                    ScalarType::Float | ScalarType::Double => ConversionRank::Conversion,
                    ScalarType::Half => ConversionRank::HalfIsASecondClassCitizen,
                    ScalarType::UntypedInt => panic!(),
                }
            },
            NumericCast(ScalarType::UInt, ref dest, _) => {
                match *dest {
                    ScalarType::UInt => ConversionRank::Exact,
                    ScalarType::Int => ConversionRank::Promotion,
                    ScalarType::Bool => ConversionRank::IntToBool,
                    ScalarType::Float | ScalarType::Double => ConversionRank::Conversion,
                    ScalarType::Half => ConversionRank::HalfIsASecondClassCitizen,
                    ScalarType::UntypedInt => panic!(),
                }
            },
            NumericCast(ScalarType::Half, ref dest, _) => {
                match *dest {
                    ScalarType::Half => ConversionRank::Exact,
                    ScalarType::Float | ScalarType::Double => ConversionRank::Promotion,
                    ScalarType::Bool | ScalarType::Int | ScalarType::UInt => ConversionRank::Conversion,
                    ScalarType::UntypedInt => panic!(),
                }
            },
            NumericCast(ScalarType::Float, ref dest, _) => {
                match *dest {
                    ScalarType::Float => ConversionRank::Exact,
                    ScalarType::Double => ConversionRank::Promotion,
                    ScalarType::Bool | ScalarType::Int | ScalarType::UInt | ScalarType::Half => ConversionRank::Conversion,
                    ScalarType::UntypedInt => panic!(),
                }
            },
            NumericCast(ScalarType::Double, ref dest, _) => {
                match *dest {
                    ScalarType::Double => ConversionRank::Exact,
                    ScalarType::Bool | ScalarType::Int | ScalarType::UInt | ScalarType::Half | ScalarType::Float => ConversionRank::Conversion,
                    ScalarType::UntypedInt => panic!(),
                }
            },
        }
    }

    fn get_target_type(&self) -> ExpressionType {
        Type::from_layout(match self.2 {
            NumericDimension::Scalar => TypeLayout::Scalar(self.1.clone()),
            NumericDimension::Vector(ref x) => TypeLayout::Vector(self.1.clone(), *x),
            NumericDimension::Matrix(ref x, ref y) => TypeLayout::Matrix(self.1.clone(), *x, *y),
        }).to_rvalue()
    }

    fn apply(&self, expr: Expression) -> Expression {
        let &NumericCast(_, ref dest, ref dim) = self;
        let to_type_data = match *dim {
            NumericDimension::Scalar => TypeLayout::Scalar(dest.clone()),
            NumericDimension::Vector(ref x) => TypeLayout::Vector(dest.clone(), *x),
            NumericDimension::Matrix(ref x, ref y) => TypeLayout::Matrix(dest.clone(), *x, *y),
        };
        Expression::Cast(Type::from_layout(to_type_data), Box::new(expr))
    }
}

impl ValueTypeCast {
    fn get_target_type(&self) -> ExpressionType {
        ExpressionType(self.0.clone(), self.2.clone())
    }
}

impl ImplicitConversion {

    pub fn find(source: &ExpressionType, dest: &ExpressionType) -> Result<ImplicitConversion, ()> {

        let source_copy = source.clone();
        let (source_type, dest_type, value_type_cast) = match (&source.1, &dest.1) {
            (&ValueType::Rvalue, &ValueType::Lvalue) => return Err(()),
            (&ValueType::Rvalue, &ValueType::Rvalue) | (&ValueType::Lvalue, &ValueType::Lvalue) => (&source.0, &dest.0, None),
            (&ValueType::Lvalue, &ValueType::Rvalue) => (&source.0, &dest.0, Some(ValueTypeCast(source.0.clone(), ValueType::Lvalue, ValueType::Rvalue))),
        };

        let &Type(ref source_l, ref mods) = source_type;
        assert!(mods.is_empty());
        let &Type(ref dest_l, ref modd) = dest_type;
        assert!(modd.is_empty());
        let numeric_cast = match (source_l, dest_l) {
            (ref ty1, ref ty2) if ty1 == ty2 => None,
            (&TypeLayout::Scalar(ref s1), &TypeLayout::Scalar(ref s2)) => {
                let cast = try!(NumericCast::new(s1, s2, NumericDimension::Scalar));
                Some(cast)
            },
            (&TypeLayout::Vector(ref s1, ref x1), &TypeLayout::Vector(ref s2, ref x2)) if x1 == x2 => {
                let cast = try!(NumericCast::new(s1, s2, NumericDimension::Vector(*x2)));
                Some(cast)
            },
            (&TypeLayout::Matrix(ref s1, ref x1, ref y1), &TypeLayout::Matrix(ref s2, ref x2, ref y2)) if x1 == x2 && y1 == y2 => {
                let cast = try!(NumericCast::new(s1, s2, NumericDimension::Matrix(*x2, *y2)));
                Some(cast)
            },
            // Vector <-> Matrix casts not implemented
            // Struct casts only supported for same type structs
            _ => return Err(()),
        };
        Ok(ImplicitConversion(source_copy, value_type_cast, numeric_cast))
    }

    pub fn get_rank(&self) -> ConversionRank {
        match *self {
            ImplicitConversion(_, _, None) => ConversionRank::Exact,
            ImplicitConversion(_, _, Some(ref numeric)) => numeric.get_rank(),
        }
    }

     pub fn get_target_type(&self) -> ExpressionType {
        match *self {
            ImplicitConversion(ref source_type, None, None) => match source_type.clone() {
                ExpressionType(ty, _) => ExpressionType(ty, ValueType::Rvalue)
            },
            ImplicitConversion(_, Some(ref vtc), None) => vtc.get_target_type(),
            ImplicitConversion(_, _, Some(ref numeric)) => numeric.get_target_type(),
        }
    }

    pub fn apply(&self, expr: Expression) -> Expression {
        match *self {
            ImplicitConversion(_, _, None) => expr,
            ImplicitConversion(_, _, Some(ref cast)) => cast.apply(expr),
        }
    }
}

#[test]
fn test_implicitconversion() {

    let basic_types = &[Type::bool(), Type::int(), Type::uint(), Type::float(), Type::floatn(4)];

    for ty in basic_types {
        assert_eq!(ImplicitConversion::find(&ty.to_rvalue(), &ty.to_rvalue()), Ok(ImplicitConversion(ty.to_rvalue(), None, None)));
        assert_eq!(ImplicitConversion::find(&ty.to_lvalue(), &ty.to_rvalue()), Ok(ImplicitConversion(ty.to_lvalue(), Some(ValueTypeCast(ty.clone(), ValueType::Lvalue, ValueType::Rvalue)), None)));
        assert_eq!(ImplicitConversion::find(&ty.to_rvalue(), &ty.to_lvalue()), Err(()));
        assert_eq!(ImplicitConversion::find(&ty.to_lvalue(), &ty.to_lvalue()), Ok(ImplicitConversion(ty.to_lvalue(), None, None)));
    }

    assert_eq!(ImplicitConversion::find(&Type::from_layout(TypeLayout::SamplerState).to_lvalue(), &Type::uint().to_lvalue()), Err(()));
    assert_eq!(ImplicitConversion::find(&Type::from_object(ObjectType::Buffer(DataType(DataLayout::Vector(ScalarType::Float, 4), TypeModifier::default()))).to_lvalue(), &Type::uint().to_lvalue()), Err(()));
}
<|endoftext|>


<commit_before>use std::convert::TryFrom;
use std::io::{self, Cursor, Read};
use std::marker::PhantomData;
use std::mem;

use crate::color::ColorType;
use crate::image::ImageDecoder;
use crate::error::{ImageError, ImageResult};

/// JPEG decoder
pub struct JpegDecoder<R> {
    decoder: jpeg::Decoder<R>,
    metadata: jpeg::ImageInfo,
}

impl<R: Read> JpegDecoder<R> {
    /// Create a new decoder that decodes from the stream ```r```
    pub fn new(r: R) -> ImageResult<JpegDecoder<R>> {
        let mut decoder = jpeg::Decoder::new(r);

        decoder.read_info().map_err(ImageError::from_jpeg)?;
        let mut metadata = decoder.info().unwrap();

        // We convert CMYK data to RGB before returning it to the user.
        if metadata.pixel_format == jpeg::PixelFormat::CMYK32 {
            metadata.pixel_format = jpeg::PixelFormat::RGB24;
        }

        Ok(JpegDecoder {
            decoder,
            metadata,
        })
    }
}

/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct JpegReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for JpegReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        if self.0.position() == 0 && buf.is_empty() {
            mem::swap(buf, self.0.get_mut());
            Ok(buf.len())
        } else {
            self.0.read_to_end(buf)
        }
    }
}

impl<'a, R: 'a + Read> ImageDecoder<'a> for JpegDecoder<R> {
    type Reader = JpegReader<R>;

    fn dimensions(&self) -> (u32, u32) {
        (u32::from(self.metadata.width), u32::from(self.metadata.height))
    }

    fn color_type(&self) -> ColorType {
        ColorType::from_jpeg(self.metadata.pixel_format)
    }

    fn into_reader(mut self) -> ImageResult<Self::Reader> {
        let mut data = self.decoder.decode().map_err(ImageError::from_jpeg)?;
        data = match self.decoder.info().unwrap().pixel_format {
            jpeg::PixelFormat::CMYK32 => cmyk_to_rgb(&data),
            _ => data,
        };

        Ok(JpegReader(Cursor::new(data), PhantomData))
    }

    fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
        assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));

        let mut data = self.decoder.decode().map_err(ImageError::from_jpeg)?;
        data = match self.decoder.info().unwrap().pixel_format {
            jpeg::PixelFormat::CMYK32 => cmyk_to_rgb(&data),
            _ => data,
        };

        buf.copy_from_slice(&data);
        Ok(())
    }
}

fn cmyk_to_rgb(input: &[u8]) -> Vec<u8> {
    let size = input.len() - input.len() / 4;
    let mut output = Vec::with_capacity(size);

    for pixel in input.chunks(4) {
        let c = f32::from(pixel[0]) / 255.0;
        let m = f32::from(pixel[1]) / 255.0;
        let y = f32::from(pixel[2]) / 255.0;
        let k = f32::from(pixel[3]) / 255.0;

        // CMYK -> CMY
        let c = c * (1.0 - k) + k;
        let m = m * (1.0 - k) + k;
        let y = y * (1.0 - k) + k;

        // CMY -> RGB
        let r = (1.0 - c) * 255.0;
        let g = (1.0 - m) * 255.0;
        let b = (1.0 - y) * 255.0;

        output.push(r as u8);
        output.push(g as u8);
        output.push(b as u8);
    }

    output
}

impl ColorType {
    fn from_jpeg(pixel_format: jpeg::PixelFormat) -> ColorType {
        use jpeg::PixelFormat::*;
        match pixel_format {
            L8 => ColorType::L8,
            RGB24 => ColorType::Rgb8,
            CMYK32 => panic!(),
        }
    }
}

impl ImageError {
    fn from_jpeg(err: jpeg::Error) -> ImageError {
        use jpeg::Error::*;
        match err {
            Format(desc) => ImageError::FormatError(desc),
            Unsupported(desc) => ImageError::UnsupportedError(format!("{:?}", desc)),
            Io(err) => ImageError::IoError(err),
            Internal(err) => ImageError::FormatError(err.to_string()),
        }
    }
}
<commit_msg>Fix cmyk_to_rgb causing off by one rounding errors.<commit_after>use std::convert::TryFrom;
use std::io::{self, Cursor, Read};
use std::marker::PhantomData;
use std::mem;

use crate::color::ColorType;
use crate::image::ImageDecoder;
use crate::error::{ImageError, ImageResult};

/// JPEG decoder
pub struct JpegDecoder<R> {
    decoder: jpeg::Decoder<R>,
    metadata: jpeg::ImageInfo,
}

impl<R: Read> JpegDecoder<R> {
    /// Create a new decoder that decodes from the stream ```r```
    pub fn new(r: R) -> ImageResult<JpegDecoder<R>> {
        let mut decoder = jpeg::Decoder::new(r);

        decoder.read_info().map_err(ImageError::from_jpeg)?;
        let mut metadata = decoder.info().unwrap();

        // We convert CMYK data to RGB before returning it to the user.
        if metadata.pixel_format == jpeg::PixelFormat::CMYK32 {
            metadata.pixel_format = jpeg::PixelFormat::RGB24;
        }

        Ok(JpegDecoder {
            decoder,
            metadata,
        })
    }
}

/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct JpegReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for JpegReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        if self.0.position() == 0 && buf.is_empty() {
            mem::swap(buf, self.0.get_mut());
            Ok(buf.len())
        } else {
            self.0.read_to_end(buf)
        }
    }
}

impl<'a, R: 'a + Read> ImageDecoder<'a> for JpegDecoder<R> {
    type Reader = JpegReader<R>;

    fn dimensions(&self) -> (u32, u32) {
        (u32::from(self.metadata.width), u32::from(self.metadata.height))
    }

    fn color_type(&self) -> ColorType {
        ColorType::from_jpeg(self.metadata.pixel_format)
    }

    fn into_reader(mut self) -> ImageResult<Self::Reader> {
        let mut data = self.decoder.decode().map_err(ImageError::from_jpeg)?;
        data = match self.decoder.info().unwrap().pixel_format {
            jpeg::PixelFormat::CMYK32 => cmyk_to_rgb(&data),
            _ => data,
        };

        Ok(JpegReader(Cursor::new(data), PhantomData))
    }

    fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
        assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));

        let mut data = self.decoder.decode().map_err(ImageError::from_jpeg)?;
        data = match self.decoder.info().unwrap().pixel_format {
            jpeg::PixelFormat::CMYK32 => cmyk_to_rgb(&data),
            _ => data,
        };

        buf.copy_from_slice(&data);
        Ok(())
    }
}

fn cmyk_to_rgb(input: &[u8]) -> Vec<u8> {
    let size = input.len() - input.len() / 4;
    let mut output = Vec::with_capacity(size);

    for pixel in input.chunks(4) {
        let c = f32::from(pixel[0]);
        let m = f32::from(pixel[1]);
        let y = f32::from(pixel[2]);
        let k = 255.0 - f32::from(pixel[3]);

        let k_sub = k / 255.0;

        // CMY -> RGB
        let r = k - c * k_sub;
        let g = k - m * k_sub;
        let b = k - y * k_sub;

        output.push(r as u8);
        output.push(g as u8);
        output.push(b as u8);
    }

    output
}

impl ColorType {
    fn from_jpeg(pixel_format: jpeg::PixelFormat) -> ColorType {
        use jpeg::PixelFormat::*;
        match pixel_format {
            L8 => ColorType::L8,
            RGB24 => ColorType::Rgb8,
            CMYK32 => panic!(),
        }
    }
}

impl ImageError {
    fn from_jpeg(err: jpeg::Error) -> ImageError {
        use jpeg::Error::*;
        match err {
            Format(desc) => ImageError::FormatError(desc),
            Unsupported(desc) => ImageError::UnsupportedError(format!("{:?}", desc)),
            Io(err) => ImageError::IoError(err),
            Internal(err) => ImageError::FormatError(err.to_string()),
        }
    }
}
<|endoftext|>


<commit_before>// extern crate rand;
extern crate timely;
extern crate differential_dataflow;
extern crate graph_map;
extern crate core_affinity;

use std::rc::Rc;

// use rand::{Rng, SeedableRng, StdRng};

use timely::dataflow::*;

use timely::progress::nested::product::Product;
use timely::progress::timestamp::RootTimestamp;
use timely::dataflow::operators::ToStream;

use differential_dataflow::input::Input;
use differential_dataflow::Collection;
use differential_dataflow::operators::*;
use differential_dataflow::trace::Trace;
use differential_dataflow::operators::arrange::ArrangeByKey;
use differential_dataflow::operators::arrange::ArrangeBySelf;
use differential_dataflow::operators::arrange::Arrange;
use differential_dataflow::trace::implementations::spine_fueled::Spine;
use differential_dataflow::AsCollection;

use graph_map::GraphMMap;

type Node = u32;
type Diff = i32;

// use differential_dataflow::trace::implementations::graph::GraphBatch;
// type GraphTrace = Spine<Node, Node, Product<RootTimestamp, ()>, isize, Rc<GraphBatch<Node>>>;

use differential_dataflow::trace::implementations::ord::OrdValBatch;
type GraphTrace = Spine<Node, Node, Product<RootTimestamp, ()>, Diff, Rc<OrdValBatch<Node, Node, Product<RootTimestamp, ()>, Diff>>>;

fn main() {

    // let nodes: Node = std::env::args().nth(1).unwrap().parse().unwrap();
    // let edges: usize = std::env::args().nth(2).unwrap().parse().unwrap();

    let filename = std::env::args().nth(1).expect("Must supply filename");
    let rootnode = std::env::args().nth(2).expect("Must supply root node").parse().expect("Invalid root node");

    timely::execute_from_args(std::env::args(), move |worker| {

        let index = worker.index();
        let peers = worker.peers();
        let timer = ::std::time::Instant::now();

        let core_ids = core_affinity::get_core_ids().unwrap();
        core_affinity::set_for_current(core_ids[index]);

        // Phase 1: Forward index.
        let mut forward = worker.dataflow(|scope| {

            let graph = GraphMMap::new(&filename);
            let nodes = graph.nodes();
            let edges = (0..nodes).filter(move |node| node % peers == index)
                                  .flat_map(move |node| {
                                      let vec = graph.edges(node).to_vec();
                                      vec.into_iter().map(move |edge| ((node as Node, edge as Node), Default::default(), 1))
                                  })
                                  .to_stream(scope)
                                  .as_collection();

            edges.arrange(GraphTrace::new()).trace
        });

        while worker.step() { }
        if index == 0 { println!("{:?}\tphase 1:\tforward graph indexed", timer.elapsed()); }

        // Phase 2: Reachability.
        let mut roots = worker.dataflow(|scope| {
            let (roots_input, roots) = scope.new_collection();
            reach(&mut forward, roots);
            roots_input
        });

        if index == 0 { roots.update(rootnode, 1); }
        roots.close();
        while worker.step() { }
        if index == 0 { println!("{:?}\tphase 2:\treach complete", timer.elapsed()); }

        // Phase 3: Breadth-first distance labeling.
        let mut roots = worker.dataflow(|scope| {
            let (roots_input, roots) = scope.new_collection();
            bfs(&mut forward, roots);
            roots_input
        });

        if index == 0 { roots.update(rootnode, 1); }
        roots.close();
        while worker.step() { }
        if index == 0 { println!("{:?}\tphase 3:\tbfs complete", timer.elapsed()); }

        // Phase 4: Reverse index.
        let mut reverse = worker.dataflow(|scope| {
            forward
                .import(scope)
                .as_collection(|&k,&v| (v,k))
                .arrange(GraphTrace::new())
                .trace
        });
        while worker.step() { }
        if index == 0 { println!("{:?}\tphase 4:\treverse graph indexed", timer.elapsed()); }

        // Phase 5: Undirected connectivity.
        worker.dataflow(|scope| { connected_components(scope, &mut forward, &mut reverse); });

        while worker.step() { }
        if index == 0 { println!("{:?}\tphase 5:\tcc complete", timer.elapsed()); }

    }).unwrap();
}

// use differential_dataflow::trace::implementations::ord::OrdValSpine;
use differential_dataflow::operators::arrange::TraceAgent;

type TraceHandle = TraceAgent<Node, Node, Product<RootTimestamp, ()>, Diff, GraphTrace>;

fn reach<G: Scope<Timestamp = Product<RootTimestamp, ()>>> (
    graph: &mut TraceHandle,
    roots: Collection<G, Node, Diff>
) -> Collection<G, Node, Diff> {

    let graph = graph.import(&roots.scope());

    roots.iterate(|inner| {

        let graph = graph.enter(&inner.scope());
        let roots = roots.enter(&inner.scope());

        graph.join_core(&inner.arrange_by_self(), |_src,&dst,&()| Some(dst))
             .concat(&roots)
             // .distinct_total()
             .threshold_total(|c| if c == 0 { 0 } else { 1 })
        })
}

fn bfs<G: Scope<Timestamp = Product<RootTimestamp, ()>>> (
    graph: &mut TraceHandle,
    roots: Collection<G, Node, Diff>
) -> Collection<G, (Node, u32), Diff> {

    let graph = graph.import(&roots.scope());
    let roots = roots.map(|r| (r,0));

    roots.iterate(|inner| {

        let graph = graph.enter(&inner.scope());
        let roots = roots.enter(&inner.scope());

        graph.join_map(&inner, |_src,&dest,&dist| (dest, dist+1))
             .concat(&roots)
             .group(|_key, input, output| output.push((*input[0].0,1)))
    })
}

fn connected_components<G: Scope<Timestamp = Product<RootTimestamp, ()>>>(
    scope: &mut G,
    forward: &mut TraceHandle,
    reverse: &mut TraceHandle,
) -> Collection<G, (Node, Node), Diff> {

    let forward = forward.import(scope);
    let reverse = reverse.import(scope);

    // each edge (x,y) means that we need at least a label for the min of x and y.
    let nodes =
    forward
        .as_collection(|&k,&v| {
            let min = std::cmp::min(k,v);
            (min, min)
        })
        .consolidate();

    // don't actually use these labels, just grab the type
    nodes
        .filter(|_| false)
        .iterate(|inner| {

            let forward = forward.enter(&inner.scope());
            let reverse = reverse.enter(&inner.scope());
            let nodes = nodes.enter_at(&inner.scope(), |r| 256 * (64 - r.1.leading_zeros() as u64));

            let inner = inner.arrange_by_key();

            let f_prop = inner.join_core(&forward, |_k,l,d| Some((*d,*l)));
            let r_prop = inner.join_core(&reverse, |_k,l,d| Some((*d,*l)));

            nodes
                .concat(&f_prop).concat(&r_prop)
                .group(|_, s, t| { t.push((*s[0].0, 1)); })
        })
}
<commit_msg>tighten<commit_after>// extern crate rand;
extern crate timely;
extern crate differential_dataflow;
extern crate graph_map;
extern crate core_affinity;

use std::rc::Rc;

// use rand::{Rng, SeedableRng, StdRng};

use timely::dataflow::*;

use timely::progress::nested::product::Product;
use timely::progress::timestamp::RootTimestamp;
use timely::dataflow::operators::ToStream;

use differential_dataflow::input::Input;
use differential_dataflow::Collection;
use differential_dataflow::operators::*;
use differential_dataflow::trace::Trace;
use differential_dataflow::operators::arrange::ArrangeByKey;
use differential_dataflow::operators::arrange::ArrangeBySelf;
use differential_dataflow::operators::arrange::Arrange;
use differential_dataflow::trace::implementations::spine_fueled::Spine;
use differential_dataflow::AsCollection;

use graph_map::GraphMMap;

type Node = u32;
type Diff = i32;

// use differential_dataflow::trace::implementations::graph::GraphBatch;
// type GraphTrace = Spine<Node, Node, Product<RootTimestamp, ()>, isize, Rc<GraphBatch<Node>>>;

use differential_dataflow::trace::implementations::ord::OrdValBatch;
type GraphTrace = Spine<Node, Node, Product<RootTimestamp, ()>, Diff, Rc<OrdValBatch<Node, Node, Product<RootTimestamp, ()>, Diff>>>;

fn main() {

    // let nodes: Node = std::env::args().nth(1).unwrap().parse().unwrap();
    // let edges: usize = std::env::args().nth(2).unwrap().parse().unwrap();

    let filename = std::env::args().nth(1).expect("Must supply filename");
    let rootnode = std::env::args().nth(2).expect("Must supply root node").parse().expect("Invalid root node");

    timely::execute_from_args(std::env::args(), move |worker| {

        let index = worker.index();
        let peers = worker.peers();
        let timer = ::std::time::Instant::now();

        let core_ids = core_affinity::get_core_ids().unwrap();
        core_affinity::set_for_current(core_ids[index % core_ids.len()]);

        // Phase 1: Forward index.
        let mut forward = worker.dataflow(|scope| {

            let graph = GraphMMap::new(&filename);
            let nodes = graph.nodes();
            let edges = (0..nodes).filter(move |node| node % peers == index)
                                  .flat_map(move |node| {
                                      let vec = graph.edges(node).to_vec();
                                      vec.into_iter().map(move |edge| ((node as Node, edge as Node), Default::default(), 1))
                                  })
                                  .to_stream(scope)
                                  .as_collection();

            edges.arrange(GraphTrace::new()).trace
        });

        while worker.step() { }
        if index == 0 { println!("{:?}\tphase 1:\tforward graph indexed", timer.elapsed()); }
        let timer = ::std::time::Instant::now();

        // Phase 2: Reachability.
        let mut roots = worker.dataflow(|scope| {
            let (roots_input, roots) = scope.new_collection();
            reach(&mut forward, roots);
            roots_input
        });

        if index == 0 { roots.update(rootnode, 1); }
        roots.close();
        while worker.step() { }
        if index == 0 { println!("{:?}\tphase 2:\treach complete", timer.elapsed()); }
        let timer = ::std::time::Instant::now();

        // Phase 3: Breadth-first distance labeling.
        let mut roots = worker.dataflow(|scope| {
            let (roots_input, roots) = scope.new_collection();
            bfs(&mut forward, roots);
            roots_input
        });

        if index == 0 { roots.update(rootnode, 1); }
        roots.close();
        while worker.step() { }
        if index == 0 { println!("{:?}\tphase 3:\tbfs complete", timer.elapsed()); }
        let timer = ::std::time::Instant::now();

        // Phase 4: Reverse index.
        let mut reverse = worker.dataflow(|scope| {
            forward
                .import(scope)
                .as_collection(|&k,&v| (v,k))
                .arrange(GraphTrace::new())
                .trace
        });
        while worker.step() { }
        if index == 0 { println!("{:?}\tphase 4:\treverse graph indexed", timer.elapsed()); }
        let timer = ::std::time::Instant::now();

        // Phase 5: Undirected connectivity.
        worker.dataflow(|scope| { connected_components(scope, &mut forward, &mut reverse); });

        while worker.step() { }
        if index == 0 { println!("{:?}\tphase 5:\tcc complete", timer.elapsed()); }

    }).unwrap();
}

// use differential_dataflow::trace::implementations::ord::OrdValSpine;
use differential_dataflow::operators::arrange::TraceAgent;

type TraceHandle = TraceAgent<Node, Node, Product<RootTimestamp, ()>, Diff, GraphTrace>;

fn reach<G: Scope<Timestamp = Product<RootTimestamp, ()>>> (
    graph: &mut TraceHandle,
    roots: Collection<G, Node, Diff>
) -> Collection<G, Node, Diff> {

    let graph = graph.import(&roots.scope());

    roots.iterate(|inner| {

        let graph = graph.enter(&inner.scope());
        let roots = roots.enter(&inner.scope());

        graph.join_core(&inner.arrange_by_self(), |_src,&dst,&()| Some(dst))
             .concat(&roots)
             // .distinct_total()
             .threshold_total(|c| if c == 0 { 0 } else { 1 })
        })
}

fn bfs<G: Scope<Timestamp = Product<RootTimestamp, ()>>> (
    graph: &mut TraceHandle,
    roots: Collection<G, Node, Diff>
) -> Collection<G, (Node, u32), Diff> {

    let graph = graph.import(&roots.scope());
    let roots = roots.map(|r| (r,0));

    roots.iterate(|inner| {

        let graph = graph.enter(&inner.scope());
        let roots = roots.enter(&inner.scope());

        graph.join_map(&inner, |_src,&dest,&dist| (dest, dist+1))
             .concat(&roots)
             .group(|_key, input, output| output.push((*input[0].0,1)))
    })
}

fn connected_components<G: Scope<Timestamp = Product<RootTimestamp, ()>>>(
    scope: &mut G,
    forward: &mut TraceHandle,
    reverse: &mut TraceHandle,
) -> Collection<G, (Node, Node), Diff> {

    let forward = forward.import(scope);
    let reverse = reverse.import(scope);

    // each edge (x,y) means that we need at least a label for the min of x and y.
    let nodes =
    forward
        .as_collection(|&k,&v| {
            let min = std::cmp::min(k,v);
            (min, min)
        })
        .consolidate();

    // don't actually use these labels, just grab the type
    nodes
        .filter(|_| false)
        .iterate(|inner| {

            let forward = forward.enter(&inner.scope());
            let reverse = reverse.enter(&inner.scope());
            let nodes = nodes.enter_at(&inner.scope(), |r| 256 * (64 - r.1.leading_zeros() as u64));

            let inner = inner.arrange_by_key();

            let f_prop = inner.join_core(&forward, |_k,l,d| Some((*d,*l)));
            let r_prop = inner.join_core(&reverse, |_k,l,d| Some((*d,*l)));

            nodes
                .concat(&f_prop).concat(&r_prop)
                .group(|_, s, t| { t.push((*s[0].0, 1)); })
        })
}
<|endoftext|>


<commit_before>// The following are copied from cairo/src/{cairo-fixed-private.h, cairo-fixed-type-private.h}

const CAIRO_FIXED_FRAC_BITS: u64 = 8;
const CAIRO_MAGIC_NUMBER_FIXED: f64 = (1u64 << (52 - CAIRO_FIXED_FRAC_BITS)) as f64 * 1.5;

fn cairo_magic_double(d: f64) -> f64 {
    d + CAIRO_MAGIC_NUMBER_FIXED
}

fn cairo_fixed_from_double(d: f64) -> i32 {
    let bits = cairo_magic_double(d).to_bits();
    let lower = bits & 0xffffffff;
    lower as i32
}

/// Implements a method to check whether two `f64` numbers would have
/// the same fixed-point representation in Cairo.
///
/// This generally means that the absolute difference between them,
/// when taken as floating-point numbers, is less than the smallest
/// representable fraction that Cairo can represent in fixed-point.
///
/// Implementation detail: Cairo fixed-point numbers use 24 bits for
/// the integral part, and 8 bits for the fractional part.  That is,
/// the smallest fraction they can represent is 1/256.
pub trait FixedEqCairo {
    fn fixed_eq_cairo(&self, other: &Self) -> bool;
}

impl FixedEqCairo for f64 {
    fn fixed_eq_cairo(&self, other: &f64) -> bool {
        // FIXME: Here we have the same problem as Cairo itself: we
        // don't check for overflow in the conversion of double to
        // fixed-point.
        cairo_fixed_from_double(*self) == cairo_fixed_from_double(*other)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn numbers_equal_in_cairo_fixed_point() {
        assert!(1.0_f64.fixed_eq_cairo(&1.0_f64));

        assert!(1.0_f64.fixed_eq_cairo(&1.001953125_f64)); // 1 + 1/512 - cairo rounds to 1

        assert!(!1.0_f64.fixed_eq_cairo(&1.00390625_f64)); // 1 + 1/256 - cairo can represent it
    }
}
<commit_msg>New trait ApproxEqCairo<commit_after>// The following are copied from cairo/src/{cairo-fixed-private.h, cairo-fixed-type-private.h}

const CAIRO_FIXED_FRAC_BITS: u64 = 8;
const CAIRO_MAGIC_NUMBER_FIXED: f64 = (1u64 << (52 - CAIRO_FIXED_FRAC_BITS)) as f64 * 1.5;

fn cairo_magic_double(d: f64) -> f64 {
    d + CAIRO_MAGIC_NUMBER_FIXED
}

fn cairo_fixed_from_double(d: f64) -> i32 {
    let bits = cairo_magic_double(d).to_bits();
    let lower = bits & 0xffffffff;
    lower as i32
}

/// Implements a method to check whether two `f64` numbers would have
/// the same fixed-point representation in Cairo.
///
/// This generally means that the absolute difference between them,
/// when taken as floating-point numbers, is less than the smallest
/// representable fraction that Cairo can represent in fixed-point.
///
/// Implementation detail: Cairo fixed-point numbers use 24 bits for
/// the integral part, and 8 bits for the fractional part.  That is,
/// the smallest fraction they can represent is 1/256.
pub trait FixedEqCairo {
    fn fixed_eq_cairo(&self, other: &Self) -> bool;
}

impl FixedEqCairo for f64 {
    fn fixed_eq_cairo(&self, other: &f64) -> bool {
        // FIXME: Here we have the same problem as Cairo itself: we
        // don't check for overflow in the conversion of double to
        // fixed-point.
        cairo_fixed_from_double(*self) == cairo_fixed_from_double(*other)
    }
}

/// Checks whether two floating-point numbers are approximately equal,
/// considering Cairo's limitations on numeric representation.
///
/// Cairo uses fixed-point numbers internally.  We implement this
/// trait for `f64`, so that two numbers can be considered "close
/// enough to equal" if their absolute difference is smaller than the
/// smallest fixed-point fraction that Cairo can represent.
///
/// Note that this trait is reliable even if the given numbers are
/// outside of the range that Cairo's fixed-point numbers can
/// represent.
pub trait ApproxEqCairo {
    fn approx_eq_cairo(&self, other: &Self) -> bool;
}

impl ApproxEqCairo for f64 {
    fn approx_eq_cairo(&self, other: &f64) -> bool {
        let abs_diff = (self - other).abs();
        let cairo_smallest_fraction = 1.0 / f64::from(1 << CAIRO_FIXED_FRAC_BITS);
        abs_diff < cairo_smallest_fraction
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn numbers_equal_in_cairo_fixed_point() {
        assert!(1.0_f64.fixed_eq_cairo(&1.0_f64));

        assert!(1.0_f64.fixed_eq_cairo(&1.001953125_f64)); // 1 + 1/512 - cairo rounds to 1

        assert!(!1.0_f64.fixed_eq_cairo(&1.00390625_f64)); // 1 + 1/256 - cairo can represent it
    }

    #[test]
    fn numbers_approx_equal() {
        assert!(0.0_f64.approx_eq_cairo(&0.001953125_f64)); // 1/512
        assert!(1.0_f64.approx_eq_cairo(&1.001953125_f64)); // 1 + 1/512
    }
}
<|endoftext|>


<commit_before>//! Endpoints for room membership.

pub mod ban_user;
pub mod forget_room;
pub mod get_member_events;
pub mod invite_user;
pub mod join_room_by_id;
pub mod join_room_by_id_or_alias;
pub mod joined_members;
pub mod joined_rooms;
pub mod kick_user;
pub mod leave_room;
pub mod unban_user;

use std::collections::BTreeMap;

use ruma_common::thirdparty::Medium;
use ruma_common::Outgoing;
use ruma_identifiers::{ServerKeyId, ServerNameBox};
use serde::Serialize;

/// A signature of an `m.third_party_invite` token to prove that this user owns a third party
/// identity which has been invited to the room.
#[derive(Clone, Debug, Outgoing, Serialize)]
pub struct ThirdPartySigned<'a> {
    /// The Matrix ID of the user who issued the invite.
    pub sender: &'a str,

    /// The Matrix ID of the invitee.
    pub mxid: &'a str,

    /// The state key of the m.third_party_invite event.
    pub token: &'a str,

    /// A signatures object containing a signature of the entire signed object.
    pub signatures: BTreeMap<ServerNameBox, BTreeMap<ServerKeyId, String>>,
}

/// Represents third party IDs to invite to the room.
#[derive(Clone, Debug, PartialEq, Outgoing, Serialize)]
#[incoming_derive(PartialEq)]
pub struct Invite3pid<'a> {
    /// Hostname and port of identity server to be used for account lookups.
    pub id_server: &'a str,

    /// An access token registered with the identity server.
    pub id_access_token: &'a str,

    /// Type of third party ID.
    pub medium: Medium,

    /// Third party identifier.
    pub address: &'a str,
}
<commit_msg>client-api: Merge imports<commit_after>//! Endpoints for room membership.

pub mod ban_user;
pub mod forget_room;
pub mod get_member_events;
pub mod invite_user;
pub mod join_room_by_id;
pub mod join_room_by_id_or_alias;
pub mod joined_members;
pub mod joined_rooms;
pub mod kick_user;
pub mod leave_room;
pub mod unban_user;

use std::collections::BTreeMap;

use ruma_common::{thirdparty::Medium, Outgoing};
use ruma_identifiers::{ServerKeyId, ServerNameBox};
use serde::Serialize;

/// A signature of an `m.third_party_invite` token to prove that this user owns a third party
/// identity which has been invited to the room.
#[derive(Clone, Debug, Outgoing, Serialize)]
pub struct ThirdPartySigned<'a> {
    /// The Matrix ID of the user who issued the invite.
    pub sender: &'a str,

    /// The Matrix ID of the invitee.
    pub mxid: &'a str,

    /// The state key of the m.third_party_invite event.
    pub token: &'a str,

    /// A signatures object containing a signature of the entire signed object.
    pub signatures: BTreeMap<ServerNameBox, BTreeMap<ServerKeyId, String>>,
}

/// Represents third party IDs to invite to the room.
#[derive(Clone, Debug, PartialEq, Outgoing, Serialize)]
#[incoming_derive(PartialEq)]
pub struct Invite3pid<'a> {
    /// Hostname and port of identity server to be used for account lookups.
    pub id_server: &'a str,

    /// An access token registered with the identity server.
    pub id_access_token: &'a str,

    /// Type of third party ID.
    pub medium: Medium,

    /// Third party identifier.
    pub address: &'a str,
}
<|endoftext|>


<commit_before>use std::io;

/// Circular buffer to store a stream. Read/write boundaries are not preserved.
pub struct StreamBuffer {
    buf: Box<[u8]>,
    head: usize,
    tail: usize,
}

impl StreamBuffer {
    pub fn new(capacity: usize) -> Self {
        Self {
            buf: vec![0; capacity + 1].into_boxed_slice(),
            head: 0,
            tail: 0,
        }
    }

    pub fn is_empty(&self) -> bool{
        self.head == self.tail
    }

    pub fn size(&self) -> usize {
        if self.head < self.tail {
            self.head + self.buf.len() - self.tail
        } else {
            self.head - self.tail
        }
    }

    pub fn remaining(&self) -> usize {
        self.buf.len() - self.size()
    }

    pub fn write_to<W: io::Write>(&mut self, destination: &mut W) -> io::Result<usize> {
        if self.head == self.tail {
            // buffer is empty, nothing to do
            Ok(0)
        } else {
            let w;
            if self.head > self.tail {
                let source_slice = &self.buf[self.tail..self.head];
                w = destination.write(source_slice)?;
                self.tail += w;
            } else { // self.head < self.tail
                let source_slice = &self.buf[self.tail..];
                w = destination.write(source_slice)?;
                self.tail = (self.tail + w) % self.buf.len();
            }
            self.optimize();
            Ok(w)
        }
    }

    pub fn read_from(&mut self, source: &[u8]) {
        assert!(self.remaining() >= source.len(), "StreamBuffer must have enough space, check remaining() space before calling read_from()");
        let source_len = source.len();
        let buf_len = self.buf.len();
        if source_len <= buf_len - self.head {
            let target_slice = &mut self.buf[self.head..self.head + source_len];
            target_slice.copy_from_slice(source);
        } else {
            {
                // fill until the right-end of the buffer
                let target_slice = &mut self.buf[self.head..];
                let source_slice = &source[..source_len - self.head];
                target_slice.copy_from_slice(source_slice);
            }
            // fill the remaining from the left-end of the buffer
            let target_slice = &mut self.buf[..self.head + source_len - buf_len];
            let source_slice = &source[source_len - self.head..];
            target_slice.copy_from_slice(source_slice);
        }
        self.head = (self.head + source_len) % buf_len;
    }

    /// To avoid unnecessary copies, StreamBuffer writes at most until the "end" of the circular
    /// buffer, which is suboptimal (it could have written more data if they have been contiguous).
    ///
    /// In order to minimize the occurrence of this event, reset the head and tail to 0 when the
    /// buffer is empty (no copy is involved).
    ///
    /// This is especially useful when the StreamBuffer is used to read/write one packet at a time,
    /// so the "end" of the buffer is guaranteed to never be reached.
    fn optimize(&mut self) {
        if self.is_empty() {
            self.head = 0;
            self.tail = 0;
        }
    }
}
<commit_msg>Make StreamBuffer.read_from() return Result<commit_after>use std::io;

/// Circular buffer to store a stream. Read/write boundaries are not preserved.
pub struct StreamBuffer {
    buf: Box<[u8]>,
    head: usize,
    tail: usize,
}

impl StreamBuffer {
    pub fn new(capacity: usize) -> Self {
        Self {
            buf: vec![0; capacity + 1].into_boxed_slice(),
            head: 0,
            tail: 0,
        }
    }

    pub fn is_empty(&self) -> bool{
        self.head == self.tail
    }

    pub fn size(&self) -> usize {
        if self.head < self.tail {
            self.head + self.buf.len() - self.tail
        } else {
            self.head - self.tail
        }
    }

    pub fn remaining(&self) -> usize {
        self.buf.len() - self.size()
    }

    pub fn write_to<W: io::Write>(&mut self, destination: &mut W) -> io::Result<usize> {
        if self.head == self.tail {
            // buffer is empty, nothing to do
            Ok(0)
        } else {
            let w;
            if self.head > self.tail {
                let source_slice = &self.buf[self.tail..self.head];
                w = destination.write(source_slice)?;
                self.tail += w;
            } else { // self.head < self.tail
                let source_slice = &self.buf[self.tail..];
                w = destination.write(source_slice)?;
                self.tail = (self.tail + w) % self.buf.len();
            }
            self.optimize();
            Ok(w)
        }
    }

    pub fn read_from(&mut self, source: &[u8]) -> io::Result<()> {
        if self.remaining() < source.len() {
            return Err(io::Error::new(io::ErrorKind::Other, "StreamBuffer is full"));
        }
        let source_len = source.len();
        let buf_len = self.buf.len();
        if source_len <= buf_len - self.head {
            let target_slice = &mut self.buf[self.head..self.head + source_len];
            target_slice.copy_from_slice(source);
        } else {
            {
                // fill until the right-end of the buffer
                let target_slice = &mut self.buf[self.head..];
                let source_slice = &source[..source_len - self.head];
                target_slice.copy_from_slice(source_slice);
            }
            // fill the remaining from the left-end of the buffer
            let target_slice = &mut self.buf[..self.head + source_len - buf_len];
            let source_slice = &source[source_len - self.head..];
            target_slice.copy_from_slice(source_slice);
        }
        self.head = (self.head + source_len) % buf_len;
        Ok(())
    }

    /// To avoid unnecessary copies, StreamBuffer writes at most until the "end" of the circular
    /// buffer, which is suboptimal (it could have written more data if they have been contiguous).
    ///
    /// In order to minimize the occurrence of this event, reset the head and tail to 0 when the
    /// buffer is empty (no copy is involved).
    ///
    /// This is especially useful when the StreamBuffer is used to read/write one packet at a time,
    /// so the "end" of the buffer is guaranteed to never be reached.
    fn optimize(&mut self) {
        if self.is_empty() {
            self.head = 0;
            self.tail = 0;
        }
    }
}
<|endoftext|>