<commit_before>//! Defines hir-level representation of visibility (e.g. `pub` and `pub(crate)`).

use std::sync::Arc;

use hir_expand::{hygiene::Hygiene, InFile};
use la_arena::ArenaMap;
use syntax::ast;

use crate::{
    db::DefDatabase,
    nameres::DefMap,
    path::{ModPath, PathKind},
    resolver::HasResolver,
    FunctionId, HasModule, LocalFieldId, ModuleDefId, ModuleId, VariantId,
};

/// Visibility of an item, not yet resolved.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RawVisibility {
    /// `pub(in module)`, `pub(crate)` or `pub(super)`. Also private, which is
    /// equivalent to `pub(self)`.
    Module(ModPath),
    /// `pub`.
    Public,
}

impl RawVisibility {
    pub(crate) const fn private() -> RawVisibility {
        RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)))
    }

    pub(crate) fn from_ast(
        db: &dyn DefDatabase,
        node: InFile<Option<ast::Visibility>>,
    ) -> RawVisibility {
        Self::from_ast_with_hygiene(node.value, &Hygiene::new(db.upcast(), node.file_id))
    }

    pub(crate) fn from_ast_with_hygiene(
        node: Option<ast::Visibility>,
        hygiene: &Hygiene,
    ) -> RawVisibility {
        Self::from_ast_with_hygiene_and_default(node, RawVisibility::private(), hygiene)
    }

    pub(crate) fn from_ast_with_hygiene_and_default(
        node: Option<ast::Visibility>,
        default: RawVisibility,
        hygiene: &Hygiene,
    ) -> RawVisibility {
        let node = match node {
            None => return default,
            Some(node) => node,
        };
        match node.kind() {
            ast::VisibilityKind::In(path) => {
                let path = ModPath::from_src(path, hygiene);
                let path = match path {
                    None => return RawVisibility::private(),
                    Some(path) => path,
                };
                RawVisibility::Module(path)
            }
            ast::VisibilityKind::PubCrate => {
                let path = ModPath::from_kind(PathKind::Crate);
                RawVisibility::Module(path)
            }
            ast::VisibilityKind::PubSuper => {
                let path = ModPath::from_kind(PathKind::Super(1));
                RawVisibility::Module(path)
            }
            ast::VisibilityKind::PubSelf => {
                let path = ModPath::from_kind(PathKind::Plain);
                RawVisibility::Module(path)
            }
            ast::VisibilityKind::Pub => RawVisibility::Public,
        }
    }

    pub fn resolve(
        &self,
        db: &dyn DefDatabase,
        resolver: &crate::resolver::Resolver,
    ) -> Visibility {
        // we fall back to public visibility (i.e. fail open) if the path can't be resolved
        resolver.resolve_visibility(db, self).unwrap_or(Visibility::Public)
    }
}

/// Visibility of an item, with the path resolved.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Visibility {
    /// Visibility is restricted to a certain module.
    Module(ModuleId),
    /// Visibility is unrestricted.
    Public,
}

impl Visibility {
    pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool {
        let to_module = match self {
            Visibility::Module(m) => m,
            Visibility::Public => return true,
        };
        // if they're not in the same crate, it can't be visible
        if from_module.krate != to_module.krate {
            return false;
        }
        let def_map = from_module.def_map(db);
        self.is_visible_from_def_map(db, &def_map, from_module.local_id)
    }

    pub(crate) fn is_visible_from_other_crate(self) -> bool {
        match self {
            Visibility::Module(_) => false,
            Visibility::Public => true,
        }
    }

    pub(crate) fn is_visible_from_def_map(
        self,
        db: &dyn DefDatabase,
        def_map: &DefMap,
        mut from_module: crate::LocalModuleId,
    ) -> bool {
        let to_module = match self {
            Visibility::Module(m) => m,
            Visibility::Public => return true,
        };

        // from_module needs to be a descendant of to_module
        let mut def_map = def_map;
        let mut parent_arc;
        loop {
            if def_map.module_id(from_module) == to_module {
                return true;
            }
            match def_map[from_module].parent {
                Some(parent) => {
                    from_module = parent;
                }
                None => {
                    match def_map.parent() {
                        Some(module) => {
                            parent_arc = module.def_map(db);
                            def_map = &*parent_arc;
                            from_module = module.local_id;
                        }
                        None => {
                            // Reached the root module, nothing left to check.
                            return false;
                        }
                    }
                }
            }
        }
    }

    /// Returns the most permissive visibility of `self` and `other`.
    ///
    /// If there is no subset relation between `self` and `other`, returns `None` (ie. they're only
    /// visible in unrelated modules).
    pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
        match (self, other) {
            (Visibility::Module(_), Visibility::Public)
            | (Visibility::Public, Visibility::Module(_))
            | (Visibility::Public, Visibility::Public) => Some(Visibility::Public),
            (Visibility::Module(mod_a), Visibility::Module(mod_b)) => {
                if mod_a.krate != mod_b.krate {
                    return None;
                }

                let mut a_ancestors = std::iter::successors(Some(mod_a.local_id), |m| {
                    let parent_id = def_map[*m].parent?;
                    Some(parent_id)
                });
                let mut b_ancestors = std::iter::successors(Some(mod_b.local_id), |m| {
                    let parent_id = def_map[*m].parent?;
                    Some(parent_id)
                });

                if a_ancestors.any(|m| m == mod_b.local_id) {
                    // B is above A
                    return Some(Visibility::Module(mod_b));
                }

                if b_ancestors.any(|m| m == mod_a.local_id) {
                    // A is above B
                    return Some(Visibility::Module(mod_a));
                }

                None
            }
        }
    }
}

/// Resolve visibility of all specific fields of a struct or union variant.
pub(crate) fn field_visibilities_query(
    db: &dyn DefDatabase,
    variant_id: VariantId,
) -> Arc<ArenaMap<LocalFieldId, Visibility>> {
    let var_data = match variant_id {
        VariantId::StructId(it) => db.struct_data(it).variant_data.clone(),
        VariantId::UnionId(it) => db.union_data(it).variant_data.clone(),
        VariantId::EnumVariantId(it) => {
            db.enum_data(it.parent).variants[it.local_id].variant_data.clone()
        }
    };
    let resolver = variant_id.module(db).resolver(db);
    let mut res = ArenaMap::default();
    for (field_id, field_data) in var_data.fields().iter() {
        res.insert(field_id, field_data.visibility.resolve(db, &resolver))
    }
    Arc::new(res)
}

/// Resolve visibility of a function.
pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility {
    let resolver = ModuleDefId::from(def).module(db).unwrap().resolver(db);
    db.function_data(def).visibility.resolve(db, &resolver)
}
<commit_msg>simplify visibility.rs<commit_after>//! Defines hir-level representation of visibility (e.g. `pub` and `pub(crate)`).

use std::sync::Arc;

use hir_expand::{hygiene::Hygiene, InFile};
use la_arena::ArenaMap;
use syntax::ast;

use crate::{
    db::DefDatabase,
    nameres::DefMap,
    path::{ModPath, PathKind},
    resolver::HasResolver,
    FunctionId, HasModule, LocalFieldId, ModuleId, VariantId,
};

/// Visibility of an item, not yet resolved.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RawVisibility {
    /// `pub(in module)`, `pub(crate)` or `pub(super)`. Also private, which is
    /// equivalent to `pub(self)`.
    Module(ModPath),
    /// `pub`.
    Public,
}

impl RawVisibility {
    pub(crate) fn private() -> RawVisibility {
        RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)))
    }

    pub(crate) fn from_ast(
        db: &dyn DefDatabase,
        node: InFile<Option<ast::Visibility>>,
    ) -> RawVisibility {
        Self::from_ast_with_hygiene(node.value, &Hygiene::new(db.upcast(), node.file_id))
    }

    pub(crate) fn from_ast_with_hygiene(
        node: Option<ast::Visibility>,
        hygiene: &Hygiene,
    ) -> RawVisibility {
        Self::from_ast_with_hygiene_and_default(node, RawVisibility::private(), hygiene)
    }

    pub(crate) fn from_ast_with_hygiene_and_default(
        node: Option<ast::Visibility>,
        default: RawVisibility,
        hygiene: &Hygiene,
    ) -> RawVisibility {
        let node = match node {
            None => return default,
            Some(node) => node,
        };
        match node.kind() {
            ast::VisibilityKind::In(path) => {
                let path = ModPath::from_src(path, hygiene);
                let path = match path {
                    None => return RawVisibility::private(),
                    Some(path) => path,
                };
                RawVisibility::Module(path)
            }
            ast::VisibilityKind::PubCrate => {
                let path = ModPath::from_kind(PathKind::Crate);
                RawVisibility::Module(path)
            }
            ast::VisibilityKind::PubSuper => {
                let path = ModPath::from_kind(PathKind::Super(1));
                RawVisibility::Module(path)
            }
            ast::VisibilityKind::PubSelf => {
                let path = ModPath::from_kind(PathKind::Plain);
                RawVisibility::Module(path)
            }
            ast::VisibilityKind::Pub => RawVisibility::Public,
        }
    }

    pub fn resolve(
        &self,
        db: &dyn DefDatabase,
        resolver: &crate::resolver::Resolver,
    ) -> Visibility {
        // we fall back to public visibility (i.e. fail open) if the path can't be resolved
        resolver.resolve_visibility(db, self).unwrap_or(Visibility::Public)
    }
}

/// Visibility of an item, with the path resolved.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Visibility {
    /// Visibility is restricted to a certain module.
    Module(ModuleId),
    /// Visibility is unrestricted.
    Public,
}

impl Visibility {
    pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool {
        let to_module = match self {
            Visibility::Module(m) => m,
            Visibility::Public => return true,
        };
        // if they're not in the same crate, it can't be visible
        if from_module.krate != to_module.krate {
            return false;
        }
        let def_map = from_module.def_map(db);
        self.is_visible_from_def_map(db, &def_map, from_module.local_id)
    }

    pub(crate) fn is_visible_from_other_crate(self) -> bool {
        match self {
            Visibility::Module(_) => false,
            Visibility::Public => true,
        }
    }

    pub(crate) fn is_visible_from_def_map(
        self,
        db: &dyn DefDatabase,
        def_map: &DefMap,
        mut from_module: crate::LocalModuleId,
    ) -> bool {
        let to_module = match self {
            Visibility::Module(m) => m,
            Visibility::Public => return true,
        };

        // from_module needs to be a descendant of to_module
        let mut def_map = def_map;
        let mut parent_arc;
        loop {
            if def_map.module_id(from_module) == to_module {
                return true;
            }
            match def_map[from_module].parent {
                Some(parent) => {
                    from_module = parent;
                }
                None => {
                    match def_map.parent() {
                        Some(module) => {
                            parent_arc = module.def_map(db);
                            def_map = &*parent_arc;
                            from_module = module.local_id;
                        }
                        None => {
                            // Reached the root module, nothing left to check.
                            return false;
                        }
                    }
                }
            }
        }
    }

    /// Returns the most permissive visibility of `self` and `other`.
    ///
    /// If there is no subset relation between `self` and `other`, returns `None` (ie. they're only
    /// visible in unrelated modules).
    pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
        match (self, other) {
            (Visibility::Module(_), Visibility::Public)
            | (Visibility::Public, Visibility::Module(_))
            | (Visibility::Public, Visibility::Public) => Some(Visibility::Public),
            (Visibility::Module(mod_a), Visibility::Module(mod_b)) => {
                if mod_a.krate != mod_b.krate {
                    return None;
                }

                let mut a_ancestors = std::iter::successors(Some(mod_a.local_id), |m| {
                    let parent_id = def_map[*m].parent?;
                    Some(parent_id)
                });
                let mut b_ancestors = std::iter::successors(Some(mod_b.local_id), |m| {
                    let parent_id = def_map[*m].parent?;
                    Some(parent_id)
                });

                if a_ancestors.any(|m| m == mod_b.local_id) {
                    // B is above A
                    return Some(Visibility::Module(mod_b));
                }

                if b_ancestors.any(|m| m == mod_a.local_id) {
                    // A is above B
                    return Some(Visibility::Module(mod_a));
                }

                None
            }
        }
    }
}

/// Resolve visibility of all specific fields of a struct or union variant.
pub(crate) fn field_visibilities_query(
    db: &dyn DefDatabase,
    variant_id: VariantId,
) -> Arc<ArenaMap<LocalFieldId, Visibility>> {
    let var_data = match variant_id {
        VariantId::StructId(it) => db.struct_data(it).variant_data.clone(),
        VariantId::UnionId(it) => db.union_data(it).variant_data.clone(),
        VariantId::EnumVariantId(it) => {
            db.enum_data(it.parent).variants[it.local_id].variant_data.clone()
        }
    };
    let resolver = variant_id.module(db).resolver(db);
    let mut res = ArenaMap::default();
    for (field_id, field_data) in var_data.fields().iter() {
        res.insert(field_id, field_data.visibility.resolve(db, &resolver))
    }
    Arc::new(res)
}

/// Resolve visibility of a function.
pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility {
    let resolver = def.resolver(db);
    db.function_data(def).visibility.resolve(db, &resolver)
}
<|endoftext|>


<commit_before>//! Entry point for call-hierarchy

use indexmap::IndexMap;

use hir::Semantics;
use ide_db::call_info::FnCallNode;
use ide_db::RootDatabase;
use syntax::{ast, match_ast, AstNode, TextRange};

use crate::{
    display::TryToNav, goto_definition, references, FilePosition, NavigationTarget, RangeInfo,
};

#[derive(Debug, Clone)]
pub struct CallItem {
    pub target: NavigationTarget,
    pub ranges: Vec<TextRange>,
}

impl CallItem {
    #[cfg(test)]
    pub(crate) fn assert_match(&self, expected: &str) {
        let actual = self.debug_render();
        test_utils::assert_eq_text!(expected.trim(), actual.trim(),);
    }

    #[cfg(test)]
    pub(crate) fn debug_render(&self) -> String {
        format!("{} : {:?}", self.target.debug_render(), self.ranges)
    }
}

pub(crate) fn call_hierarchy(
    db: &RootDatabase,
    position: FilePosition,
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
    goto_definition::goto_definition(db, position)
}

pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Option<Vec<CallItem>> {
    let sema = Semantics::new(db);

    // 1. Find all refs
    // 2. Loop through refs and determine unique fndef. This will become our `from: CallHierarchyItem,` in the reply.
    // 3. Add ranges relative to the start of the fndef.
    let refs = references::find_all_refs(&sema, position, None)?;

    let mut calls = CallLocations::default();

    for reference in refs.info.references() {
        let file_id = reference.file_range.file_id;
        let file = sema.parse(file_id);
        let file = file.syntax();
        let token = file.token_at_offset(reference.file_range.range.start()).next()?;
        let token = sema.descend_into_macros(token);
        let syntax = token.parent();

        // This target is the containing function
        if let Some(nav) = syntax.ancestors().find_map(|node| {
            match_ast! {
                match node {
                    ast::Fn(it) => {
                        let def = sema.to_def(&it)?;
                        def.try_to_nav(sema.db)
                    },
                    _ => None,
                }
            }
        }) {
            let relative_range = reference.file_range.range;
            calls.add(&nav, relative_range);
        }
    }

    Some(calls.into_items())
}

pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Option<Vec<CallItem>> {
    let sema = Semantics::new(db);
    let file_id = position.file_id;
    let file = sema.parse(file_id);
    let file = file.syntax();
    let token = file.token_at_offset(position.offset).next()?;
    let token = sema.descend_into_macros(token);
    let syntax = token.parent();

    let mut calls = CallLocations::default();

    syntax
        .descendants()
        .filter_map(|node| FnCallNode::with_node_exact(&node))
        .filter_map(|call_node| {
            let name_ref = call_node.name_ref()?;

            if let Some(func_target) = match &call_node {
                FnCallNode::CallExpr(expr) => {
                    //FIXME: Type::as_callable is broken
                    let callable = sema.type_of_expr(&expr.expr()?)?.as_callable(db)?;
                    match callable.kind() {
                        hir::CallableKind::Function(it) => {
                            let fn_def: hir::Function = it.into();
                            let nav = fn_def.try_to_nav(db)?;
                            Some(nav)
                        }
                        _ => None,
                    }
                }
                FnCallNode::MethodCallExpr(expr) => {
                    let function = sema.resolve_method_call(&expr)?;
                    function.try_to_nav(db)
                }
            } {
                Some((func_target, name_ref.syntax().text_range()))
            } else {
                None
            }
        })
        .for_each(|(nav, range)| calls.add(&nav, range));

    Some(calls.into_items())
}

#[derive(Default)]
struct CallLocations {
    funcs: IndexMap<NavigationTarget, Vec<TextRange>>,
}

impl CallLocations {
    fn add(&mut self, target: &NavigationTarget, range: TextRange) {
        self.funcs.entry(target.clone()).or_default().push(range);
    }

    fn into_items(self) -> Vec<CallItem> {
        self.funcs.into_iter().map(|(target, ranges)| CallItem { target, ranges }).collect()
    }
}

#[cfg(test)]
mod tests {
    use ide_db::base_db::FilePosition;

    use crate::fixture;

    fn check_hierarchy(
        ra_fixture: &str,
        expected: &str,
        expected_incoming: &[&str],
        expected_outgoing: &[&str],
    ) {
        let (analysis, pos) = fixture::position(ra_fixture);

        let mut navs = analysis.call_hierarchy(pos).unwrap().unwrap().info;
        assert_eq!(navs.len(), 1);
        let nav = navs.pop().unwrap();
        nav.assert_match(expected);

        let item_pos =
            FilePosition { file_id: nav.file_id, offset: nav.focus_or_full_range().start() };
        let incoming_calls = analysis.incoming_calls(item_pos).unwrap().unwrap();
        assert_eq!(incoming_calls.len(), expected_incoming.len());

        for call in 0..incoming_calls.len() {
            incoming_calls[call].assert_match(expected_incoming[call]);
        }

        let outgoing_calls = analysis.outgoing_calls(item_pos).unwrap().unwrap();
        assert_eq!(outgoing_calls.len(), expected_outgoing.len());

        for call in 0..outgoing_calls.len() {
            outgoing_calls[call].assert_match(expected_outgoing[call]);
        }
    }

    #[test]
    fn test_call_hierarchy_on_ref() {
        check_hierarchy(
            r#"
//- /lib.rs
fn callee() {}
fn caller() {
    call$0ee();
}
"#,
            "callee Function FileId(0) 0..14 3..9",
            &["caller Function FileId(0) 15..44 18..24 : [33..39]"],
            &[],
        );
    }

    #[test]
    fn test_call_hierarchy_on_def() {
        check_hierarchy(
            r#"
//- /lib.rs
fn call$0ee() {}
fn caller() {
    callee();
}
"#,
            "callee Function FileId(0) 0..14 3..9",
            &["caller Function FileId(0) 15..44 18..24 : [33..39]"],
            &[],
        );
    }

    #[test]
    fn test_call_hierarchy_in_same_fn() {
        check_hierarchy(
            r#"
//- /lib.rs
fn callee() {}
fn caller() {
    call$0ee();
    callee();
}
"#,
            "callee Function FileId(0) 0..14 3..9",
            &["caller Function FileId(0) 15..58 18..24 : [33..39, 47..53]"],
            &[],
        );
    }

    #[test]
    fn test_call_hierarchy_in_different_fn() {
        check_hierarchy(
            r#"
//- /lib.rs
fn callee() {}
fn caller1() {
    call$0ee();
}

fn caller2() {
    callee();
}
"#,
            "callee Function FileId(0) 0..14 3..9",
            &[
                "caller1 Function FileId(0) 15..45 18..25 : [34..40]",
                "caller2 Function FileId(0) 47..77 50..57 : [66..72]",
            ],
            &[],
        );
    }

    #[test]
    fn test_call_hierarchy_in_tests_mod() {
        check_hierarchy(
            r#"
//- /lib.rs cfg:test
fn callee() {}
fn caller1() {
    call$0ee();
}

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

    #[test]
    fn test_caller() {
        callee();
    }
}
"#,
            "callee Function FileId(0) 0..14 3..9",
            &[
                "caller1 Function FileId(0) 15..45 18..25 : [34..40]",
                "test_caller Function FileId(0) 95..149 110..121 : [134..140]",
            ],
            &[],
        );
    }

    #[test]
    fn test_call_hierarchy_in_different_files() {
        check_hierarchy(
            r#"
//- /lib.rs
mod foo;
use foo::callee;

fn caller() {
    call$0ee();
}

//- /foo/mod.rs
pub fn callee() {}
"#,
            "callee Function FileId(1) 0..18 7..13",
            &["caller Function FileId(0) 27..56 30..36 : [45..51]"],
            &[],
        );
    }

    #[test]
    fn test_call_hierarchy_outgoing() {
        check_hierarchy(
            r#"
//- /lib.rs
fn callee() {}
fn call$0er() {
    callee();
    callee();
}
"#,
            "caller Function FileId(0) 15..58 18..24",
            &[],
            &["callee Function FileId(0) 0..14 3..9 : [33..39, 47..53]"],
        );
    }

    #[test]
    fn test_call_hierarchy_outgoing_in_different_files() {
        check_hierarchy(
            r#"
//- /lib.rs
mod foo;
use foo::callee;

fn call$0er() {
    callee();
}

//- /foo/mod.rs
pub fn callee() {}
"#,
            "caller Function FileId(0) 27..56 30..36",
            &[],
            &["callee Function FileId(1) 0..18 7..13 : [45..51]"],
        );
    }

    #[test]
    fn test_call_hierarchy_incoming_outgoing() {
        check_hierarchy(
            r#"
//- /lib.rs
fn caller1() {
    call$0er2();
}

fn caller2() {
    caller3();
}

fn caller3() {

}
"#,
            "caller2 Function FileId(0) 33..64 36..43",
            &["caller1 Function FileId(0) 0..31 3..10 : [19..26]"],
            &["caller3 Function FileId(0) 66..83 69..76 : [52..59]"],
        );
    }

    #[test]
    fn test_call_hierarchy_issue_5103() {
        check_hierarchy(
            r#"
fn a() {
    b()
}

fn b() {}

fn main() {
    a$0()
}
"#,
            "a Function FileId(0) 0..18 3..4",
            &["main Function FileId(0) 31..52 34..38 : [47..48]"],
            &["b Function FileId(0) 20..29 23..24 : [13..14]"],
        );

        check_hierarchy(
            r#"
fn a() {
    b$0()
}

fn b() {}

fn main() {
    a()
}
"#,
            "b Function FileId(0) 20..29 23..24",
            &["a Function FileId(0) 0..18 3..4 : [13..14]"],
            &[],
        );
    }
}
<commit_msg>Simplify<commit_after>//! Entry point for call-hierarchy

use indexmap::IndexMap;

use hir::Semantics;
use ide_db::call_info::FnCallNode;
use ide_db::RootDatabase;
use syntax::{ast, AstNode, TextRange};

use crate::{
    display::TryToNav, goto_definition, references, FilePosition, NavigationTarget, RangeInfo,
};

#[derive(Debug, Clone)]
pub struct CallItem {
    pub target: NavigationTarget,
    pub ranges: Vec<TextRange>,
}

impl CallItem {
    #[cfg(test)]
    pub(crate) fn assert_match(&self, expected: &str) {
        let actual = self.debug_render();
        test_utils::assert_eq_text!(expected.trim(), actual.trim(),);
    }

    #[cfg(test)]
    pub(crate) fn debug_render(&self) -> String {
        format!("{} : {:?}", self.target.debug_render(), self.ranges)
    }
}

pub(crate) fn call_hierarchy(
    db: &RootDatabase,
    position: FilePosition,
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
    goto_definition::goto_definition(db, position)
}

pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Option<Vec<CallItem>> {
    let sema = Semantics::new(db);

    // 1. Find all refs
    // 2. Loop through refs and determine unique fndef. This will become our `from: CallHierarchyItem,` in the reply.
    // 3. Add ranges relative to the start of the fndef.
    let refs = references::find_all_refs(&sema, position, None)?;

    let mut calls = CallLocations::default();

    for reference in refs.info.references() {
        let file_id = reference.file_range.file_id;
        let file = sema.parse(file_id);
        let file = file.syntax();
        let token = file.token_at_offset(reference.file_range.range.start()).next()?;
        let token = sema.descend_into_macros(token);
        let syntax = token.parent();

        // This target is the containing function
        if let Some(nav) = syntax.ancestors().find_map(|node| {
            let fn_ = ast::Fn::cast(node)?;
            let def = sema.to_def(&fn_)?;
            def.try_to_nav(sema.db)
        }) {
            let relative_range = reference.file_range.range;
            calls.add(&nav, relative_range);
        }
    }

    Some(calls.into_items())
}

pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Option<Vec<CallItem>> {
    let sema = Semantics::new(db);
    let file_id = position.file_id;
    let file = sema.parse(file_id);
    let file = file.syntax();
    let token = file.token_at_offset(position.offset).next()?;
    let token = sema.descend_into_macros(token);
    let syntax = token.parent();

    let mut calls = CallLocations::default();

    syntax
        .descendants()
        .filter_map(|node| FnCallNode::with_node_exact(&node))
        .filter_map(|call_node| {
            let name_ref = call_node.name_ref()?;
            let func_target = match call_node {
                FnCallNode::CallExpr(expr) => {
                    //FIXME: Type::as_callable is broken
                    let callable = sema.type_of_expr(&expr.expr()?)?.as_callable(db)?;
                    match callable.kind() {
                        hir::CallableKind::Function(it) => it.try_to_nav(db),
                        _ => None,
                    }
                }
                FnCallNode::MethodCallExpr(expr) => {
                    let function = sema.resolve_method_call(&expr)?;
                    function.try_to_nav(db)
                }
            }?;
            Some((func_target, name_ref.syntax().text_range()))
        })
        .for_each(|(nav, range)| calls.add(&nav, range));

    Some(calls.into_items())
}

#[derive(Default)]
struct CallLocations {
    funcs: IndexMap<NavigationTarget, Vec<TextRange>>,
}

impl CallLocations {
    fn add(&mut self, target: &NavigationTarget, range: TextRange) {
        self.funcs.entry(target.clone()).or_default().push(range);
    }

    fn into_items(self) -> Vec<CallItem> {
        self.funcs.into_iter().map(|(target, ranges)| CallItem { target, ranges }).collect()
    }
}

#[cfg(test)]
mod tests {
    use ide_db::base_db::FilePosition;

    use crate::fixture;

    fn check_hierarchy(
        ra_fixture: &str,
        expected: &str,
        expected_incoming: &[&str],
        expected_outgoing: &[&str],
    ) {
        let (analysis, pos) = fixture::position(ra_fixture);

        let mut navs = analysis.call_hierarchy(pos).unwrap().unwrap().info;
        assert_eq!(navs.len(), 1);
        let nav = navs.pop().unwrap();
        nav.assert_match(expected);

        let item_pos =
            FilePosition { file_id: nav.file_id, offset: nav.focus_or_full_range().start() };
        let incoming_calls = analysis.incoming_calls(item_pos).unwrap().unwrap();
        assert_eq!(incoming_calls.len(), expected_incoming.len());

        for call in 0..incoming_calls.len() {
            incoming_calls[call].assert_match(expected_incoming[call]);
        }

        let outgoing_calls = analysis.outgoing_calls(item_pos).unwrap().unwrap();
        assert_eq!(outgoing_calls.len(), expected_outgoing.len());

        for call in 0..outgoing_calls.len() {
            outgoing_calls[call].assert_match(expected_outgoing[call]);
        }
    }

    #[test]
    fn test_call_hierarchy_on_ref() {
        check_hierarchy(
            r#"
//- /lib.rs
fn callee() {}
fn caller() {
    call$0ee();
}
"#,
            "callee Function FileId(0) 0..14 3..9",
            &["caller Function FileId(0) 15..44 18..24 : [33..39]"],
            &[],
        );
    }

    #[test]
    fn test_call_hierarchy_on_def() {
        check_hierarchy(
            r#"
//- /lib.rs
fn call$0ee() {}
fn caller() {
    callee();
}
"#,
            "callee Function FileId(0) 0..14 3..9",
            &["caller Function FileId(0) 15..44 18..24 : [33..39]"],
            &[],
        );
    }

    #[test]
    fn test_call_hierarchy_in_same_fn() {
        check_hierarchy(
            r#"
//- /lib.rs
fn callee() {}
fn caller() {
    call$0ee();
    callee();
}
"#,
            "callee Function FileId(0) 0..14 3..9",
            &["caller Function FileId(0) 15..58 18..24 : [33..39, 47..53]"],
            &[],
        );
    }

    #[test]
    fn test_call_hierarchy_in_different_fn() {
        check_hierarchy(
            r#"
//- /lib.rs
fn callee() {}
fn caller1() {
    call$0ee();
}

fn caller2() {
    callee();
}
"#,
            "callee Function FileId(0) 0..14 3..9",
            &[
                "caller1 Function FileId(0) 15..45 18..25 : [34..40]",
                "caller2 Function FileId(0) 47..77 50..57 : [66..72]",
            ],
            &[],
        );
    }

    #[test]
    fn test_call_hierarchy_in_tests_mod() {
        check_hierarchy(
            r#"
//- /lib.rs cfg:test
fn callee() {}
fn caller1() {
    call$0ee();
}

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

    #[test]
    fn test_caller() {
        callee();
    }
}
"#,
            "callee Function FileId(0) 0..14 3..9",
            &[
                "caller1 Function FileId(0) 15..45 18..25 : [34..40]",
                "test_caller Function FileId(0) 95..149 110..121 : [134..140]",
            ],
            &[],
        );
    }

    #[test]
    fn test_call_hierarchy_in_different_files() {
        check_hierarchy(
            r#"
//- /lib.rs
mod foo;
use foo::callee;

fn caller() {
    call$0ee();
}

//- /foo/mod.rs
pub fn callee() {}
"#,
            "callee Function FileId(1) 0..18 7..13",
            &["caller Function FileId(0) 27..56 30..36 : [45..51]"],
            &[],
        );
    }

    #[test]
    fn test_call_hierarchy_outgoing() {
        check_hierarchy(
            r#"
//- /lib.rs
fn callee() {}
fn call$0er() {
    callee();
    callee();
}
"#,
            "caller Function FileId(0) 15..58 18..24",
            &[],
            &["callee Function FileId(0) 0..14 3..9 : [33..39, 47..53]"],
        );
    }

    #[test]
    fn test_call_hierarchy_outgoing_in_different_files() {
        check_hierarchy(
            r#"
//- /lib.rs
mod foo;
use foo::callee;

fn call$0er() {
    callee();
}

//- /foo/mod.rs
pub fn callee() {}
"#,
            "caller Function FileId(0) 27..56 30..36",
            &[],
            &["callee Function FileId(1) 0..18 7..13 : [45..51]"],
        );
    }

    #[test]
    fn test_call_hierarchy_incoming_outgoing() {
        check_hierarchy(
            r#"
//- /lib.rs
fn caller1() {
    call$0er2();
}

fn caller2() {
    caller3();
}

fn caller3() {

}
"#,
            "caller2 Function FileId(0) 33..64 36..43",
            &["caller1 Function FileId(0) 0..31 3..10 : [19..26]"],
            &["caller3 Function FileId(0) 66..83 69..76 : [52..59]"],
        );
    }

    #[test]
    fn test_call_hierarchy_issue_5103() {
        check_hierarchy(
            r#"
fn a() {
    b()
}

fn b() {}

fn main() {
    a$0()
}
"#,
            "a Function FileId(0) 0..18 3..4",
            &["main Function FileId(0) 31..52 34..38 : [47..48]"],
            &["b Function FileId(0) 20..29 23..24 : [13..14]"],
        );

        check_hierarchy(
            r#"
fn a() {
    b$0()
}

fn b() {}

fn main() {
    a()
}
"#,
            "b Function FileId(0) 20..29 23..24",
            &["a Function FileId(0) 0..18 3..4 : [13..14]"],
            &[],
        );
    }
}
<|endoftext|>


<commit_before>//
// Copyright:: Copyright (c) 2016 Chef Software, Inc.
// License:: Apache License, Version 2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use errors::{DeliveryError, Kind};
use std::path::{Path, PathBuf};
use std::fs::File;
use std::io::prelude::*;
use utils::read_file;
use utils::say::{say, sayln};
use utils::path_ext::is_file;
use git;
use project;
use regex::Regex;

// Return the path to the metadata.rb file
fn metadata_file(path: &PathBuf) -> String {
    let mut metadata = path.to_str().unwrap().to_string();
    metadata.push_str("/metadata.rb");
    return metadata
}

// Vefiry if the provided path is a cookbook, or not
fn is_cookbook(path: &PathBuf) -> bool {
    let meta_f = metadata_file(path);
    is_file(&Path::new(&meta_f))
}

// Extract the cookbook version from the provided metadata content
//
// This function expects you to read the metadata in advance and
// pass just the content of the file. From there it will read every
// line and search for the version to return it.
fn metadata_version_from(content: String) -> Result<String, DeliveryError> {
    for l in content.lines() {
        let r = Regex::new(r"version\s+'(?P<version>[0-9]*\.[0-9]*\.[0-9]*)'").unwrap();
        if let Some(version) = r.captures(l) {
            return Ok(version.name("version").unwrap().to_string())
        };
    };
    return Err(DeliveryError{ kind: Kind::MissingMetadataVersion, detail: None })
}

// Bump the metadata version, only if:
// * The project is a cookbook
// * The version hasn't been updated
//
// @param p_root [&PathBuf] The project root path
// @param pipeline [&str] Pipeline the change is targeting to
// @return ()
pub fn bump_version(p_root: &PathBuf, pipeline: &str) -> Result<(), DeliveryError> {
    if is_cookbook(&p_root) {
        let project = try!(project::project_from_cwd());
        say("white", "Project ");
        say("yellow", &project);
        sayln("white", " is a cookbook");
        sayln("white", "Validating version in metadata");

        let meta_f_p = PathBuf::from(metadata_file(&p_root));
        let current_v = try!(metadata_version_from(try!(read_file(&meta_f_p))));
        let t_file = [pipeline, ":metadata.rb"].concat();
        let pipeline_meta = try!(git::git_command(&["show", &t_file], &p_root));
        let pipeline_v = try!(metadata_version_from(pipeline_meta.stdout));

        if current_v == pipeline_v {
            say("yellow", "The version hasn't been updated (");
            say("red", &pipeline_v);
            sayln("yellow", ")");
            let s = pipeline_v.split(".");
            let vec: Vec<&str> = s.collect();
            let patch = vec[2].parse::<u32>().unwrap();
            let new_patch: String = (patch + 1).to_string();
            let new_version = [vec[0], ".", vec[1], ".", new_patch.trim()].concat();
            say("white", "Bumping version to: ");
            sayln("green", &new_version);

            let current_meta = try!(read_file(&meta_f_p));
            let new_meta = current_meta.replace(&*current_v, &*new_version);

            // Recreate the file and dump the processed contents to it
            let mut recreate_meta = try!(File::create(metadata_file(&p_root)));
            try!(recreate_meta.write_fmt(format_args!("{}", &new_meta)));

            let commit_msg = ["Bump version to ", new_version.trim()].concat();
            try!(git::git_command(&["add", &metadata_file(&p_root)], &p_root));
            try!(git::git_command(&["commit", "-m", &commit_msg], &p_root));
        } else {
            say("white", "Version already updated (");
            say("magenta", &pipeline_v);
            say("white", "/");
            say("green", &current_v);
            sayln("white", ")");
        }
    }
    Ok(())
}
<commit_msg>Separate bump_version fn<commit_after>//
// Copyright:: Copyright (c) 2016 Chef Software, Inc.
// License:: Apache License, Version 2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use errors::{DeliveryError, Kind};
use std::path::{Path, PathBuf};
use std::fs::File;
use std::io::prelude::*;
use utils::{self, read_file};
use utils::say::{say, sayln};
use utils::path_ext::is_file;
use git;
use project;
use regex::Regex;

// Return the path to the metadata.rb file
fn metadata_file(path: &PathBuf) -> String {
    let mut metadata = path.to_str().unwrap().to_string();
    metadata.push_str("/metadata.rb");
    return metadata
}

// Verify if the provided path is a cookbook, or not
fn is_cookbook(path: &PathBuf) -> bool {
    let meta_f = metadata_file(path);
    is_file(&Path::new(&meta_f))
}

// Extract the cookbook version from the provided metadata content
//
// This function expects you to read the metadata in advance and
// pass just the content of the file. From there it will read every
// line and search for the version to return it.
fn metadata_version_from(content: String) -> Result<String, DeliveryError> {
    for l in content.lines() {
        let r = Regex::new(r"version\s+'(?P<version>[0-9]*\.[0-9]*\.[0-9]*)'").unwrap();
        if let Some(version) = r.captures(l) {
            return Ok(version.name("version").unwrap().to_string())
        };
    };
    return Err(DeliveryError{ kind: Kind::MissingMetadataVersion, detail: None })
}

// Bump the patchset of the provided version
fn bump_patchset(version: String) -> Result<String, DeliveryError> {
    let s = version.split(".");
    let m_m_p: Vec<&str> = s.collect();
    let patch = try!(m_m_p[2].parse::<u32>());
    let new_patch: String = (patch + 1).to_string();
    let mut new_version: String = m_m_p[0].to_string();
    new_version.push_str(".");
    new_version.push_str(m_m_p[1]);
    new_version.push_str(".");
    new_version.push_str(&new_patch);
    Ok(new_version)
}

// Saves the new version to the metadata and commit the changes
fn save_version(metadata: &PathBuf, version: String) -> Result<(), DeliveryError> {
    let current_meta = try!(read_file(metadata));
    let current_version = try!(metadata_version_from(current_meta.clone()));
    let new_metadata = current_meta.replace(&*current_version, &*version);

    // Recreate the file and dump the processed contents to it
    let mut recreate_meta = try!(File::create(metadata));
    try!(recreate_meta.write_fmt(format_args!("{}", &new_metadata)));

    // Commit the changes made to the metadata
    let mut commit_msg = String::from("Bump version to ");
    commit_msg.push_str(&version);
    try!(git::git_command(&["add", metadata.to_str().unwrap()], &utils::cwd()));
    try!(git::git_command(&["commit", "-m", &commit_msg], &utils::cwd()));
    Ok(())
}

// @Public

// Bump the metadata version, only if:
// * The project is a cookbook
// * The version hasn't been updated
//
// @param p_root [&PathBuf] The project root path
// @param pipeline [&str] Pipeline the change is targeting to
// @return () if success
pub fn bump_version(p_root: &PathBuf, pipeline: &str) -> Result<(), DeliveryError> {
    if is_cookbook(&p_root) {
        let project = try!(project::project_from_cwd());
        say("white", "Project ");
        say("yellow", &project);
        sayln("white", " is a cookbook");
        sayln("white", "Validating version in metadata");

        let meta_f_p = PathBuf::from(metadata_file(&p_root));
        let current_v = try!(metadata_version_from(try!(read_file(&meta_f_p))));
        let mut t_file = pipeline.to_string();
        t_file.push_str(":metadata.rb");
        let pipeline_meta = try!(git::git_command(&["show", &t_file], &p_root));
        let pipeline_v = try!(metadata_version_from(pipeline_meta.stdout));

        if current_v == pipeline_v {
            say("yellow", "The version hasn't been updated (");
            say("red", &pipeline_v);
            sayln("yellow", ")");
            let new_version = try!(bump_patchset(pipeline_v));
            say("white", "Bumping version to: ");
            sayln("green", &new_version);
            try!(save_version(&meta_f_p, new_version));
        } else {
            say("white", "Version already updated (");
            say("magenta", &pipeline_v);
            say("white", "/");
            say("green", &current_v);
            sayln("white", ")");
        }
    }
    Ok(())
}

#[cfg(test)]
mod tests {
    use std::path::PathBuf;

    #[test]
    fn verify_version_bumping_using_bump_patchset() {
        let version = String::from("1.2.3");
        assert_eq!(String::from("1.2.4"), super::bump_patchset(version).unwrap());
    }

    #[test]
    fn return_the_metadata_file_path() {
        let project_path = PathBuf::from("/cookbook");
        assert_eq!(String::from("/cookbook/metadata.rb"), super::metadata_file(&project_path));
    }
}
<|endoftext|>


<commit_before>//! Compute eigenvalues and eigenvectors of symmetric matrices.

use ndarray::{ArrayBase, Array, DataMut, Data, Ix};
use lapack::c::{ssyev};
use super::types::{Solution, EigenError};
use matrix::*;

pub trait SymEigen : Sized
{
    type Solution;

    /// Return the real eigenvalues of a symmetric matrix.
    ///
    /// The input matrix is mutated as part of the computation. Use
    /// [`.values()`](#tymethod.values) if you need to preserve the original
    /// matrix.
    fn compute_mut<D>(mat: &mut ArrayBase<D, (Ix, Ix)>,
                      uplo: Symmetric,
                      with_vectors: bool) -> Result<Array<Self, Ix>, EigenError> where D: DataMut<Elem=Self>;

    /// Return the eigenvalues of a symmetric matrix.
    ///
    /// # Remarks
    ///
    /// The input matrix is copied before the calculation takes place.
    fn compute<D>(mat: &ArrayBase<D, (Ix, Ix)>, uplo: Symmetric, with_vectors: bool) -> Result<Self::Solution, EigenError> where D: Data<Elem=Self>;
}

impl SymEigen for f32 {
    type Solution = Solution<Self, Self>;

    fn compute_mut<D>(mat: &mut ArrayBase<D, (Ix, Ix)>, uplo: Symmetric, with_vectors: bool) ->
        Result<Array<Self, Ix>, EigenError> where D:DataMut<Elem=Self>
    {
        let n = mat.dim().0 as i32;

        let (mut data_slice, layout, ld) = match slice_and_layout_mut(mat) {
            Some(x) => x,
            None => return Err(EigenError::BadLayout)
        };

        let mut values = vec![0.0; n as usize];

        let info = ssyev(layout, if with_vectors { b'V' } else { b'N' }, uplo as u8, n, data_slice,
                         ld as i32, &mut values);

        if info  == 0 {
            Ok(ArrayBase::from_vec(values))
        } else if info < 0 {
            Err(EigenError::BadParameter(-info))
        } else {
            Err(EigenError::Failed)
        }
    }

    fn compute<D>(mat: &ArrayBase<D, (Ix, Ix)>, uplo: Symmetric, with_vectors: bool) -> Result<Self::Solution, EigenError> where D: Data<Elem=Self> {
        let vec: Vec<Self> = mat.iter().cloned().collect();
        let mut new_mat = Array::from_shape_vec(mat.dim(), vec).unwrap();
        Self::compute_mut(&mut new_mat, uplo, with_vectors).map(|values| {
            Solution {
                values: values,
                left_vectors: None,
                right_vectors: if with_vectors { Some(new_mat) } else { None }
            }
        })
    }
}

#[cfg(test)]
mod tests {
    use super::SymEigen;
    use ndarray::prelude::*;
    use matrix::Symmetric;

    #[test]
    fn try_eig() {
        let mut m = arr2(&[[1.0 as f32, 2.0], [2.0, 1.0]]);

        let r = SymEigen::compute_mut(&mut m, Symmetric::Upper, false);
        assert!(r.is_ok());

        assert_in_tol!(r.unwrap(), arr1(&[-1.0, 3.0]), 0.01);
    }

}
<commit_msg>implement symmetric eigenvalues for all types<commit_after>//! Compute eigenvalues and eigenvectors of symmetric matrices.

use ndarray::{ArrayBase, Array, DataMut, Data, Ix};
use lapack::c::{ssyev, dsyev, cheev, zheev};
use lapack::{c32, c64};
use super::types::{Solution, EigenError};
use matrix::*;

pub trait SymEigen : Sized
{
    type SingularValue;
    type Solution;

    /// Return the real eigenvalues of a symmetric matrix.
    ///
    /// The input matrix is mutated as part of the computation. Use
    /// [`.values()`](#tymethod.values) if you need to preserve the original
    /// matrix.
    fn compute_mut<D>(mat: &mut ArrayBase<D, (Ix, Ix)>, uplo: Symmetric, with_vectors: bool) ->
        Result<Array<Self::SingularValue, Ix>, EigenError> where D: DataMut<Elem=Self>;

    /// Return the eigenvalues of a symmetric matrix.
    ///
    /// # Remarks
    ///
    /// The input matrix is copied before the calculation takes place.
    fn compute<D>(mat: &ArrayBase<D, (Ix, Ix)>, uplo: Symmetric, with_vectors: bool) ->
        Result<Self::Solution, EigenError> where D: Data<Elem=Self>;
}

macro_rules! impl_sym_eigen {
    ($impl_type:ident, $eigen_type:ident, $func:ident) => (
        impl SymEigen for $impl_type {
            type SingularValue = $eigen_type;
            type Solution = Solution<Self, Self::SingularValue>;

            fn compute_mut<D>(mat: &mut ArrayBase<D, (Ix, Ix)>, uplo: Symmetric, with_vectors: bool) ->
                Result<Array<Self::SingularValue, Ix>, EigenError> where D: DataMut<Elem=Self>
            {
                let n = mat.dim().0 as i32;

                let (mut data_slice, layout, ld) = match slice_and_layout_mut(mat) {
                    Some(x) => x,
                    None => return Err(EigenError::BadLayout)
                };

                let mut values = Array::default(n as Ix);
                let job = if with_vectors { b'V' } else { b'N' };

                let info = $func(layout, job, uplo as u8, n, data_slice,
                                 ld as i32, values.as_slice_mut().unwrap());

                if info  == 0 {
                    Ok(values)
                } else if info < 0 {
                    Err(EigenError::BadParameter(-info))
                } else {
                    Err(EigenError::Failed)
                }
            }

            fn compute<D>(mat: &ArrayBase<D, (Ix, Ix)>, uplo: Symmetric, with_vectors: bool) -> Result<Self::Solution, EigenError> where D: Data<Elem=Self> {
                let vec: Vec<Self> = mat.iter().cloned().collect();
                let mut new_mat = Array::from_shape_vec(mat.dim(), vec).unwrap();
                Self::compute_mut(&mut new_mat, uplo, with_vectors).map(|values| {
                    Solution {
                        values: values,
                        left_vectors: None,
                        right_vectors: if with_vectors { Some(new_mat) } else { None }
                    }
                })
            }
        }
    )
}

impl_sym_eigen!(f32, f32, ssyev);
impl_sym_eigen!(c32, f32, cheev);
impl_sym_eigen!(f64, f64, dsyev);
impl_sym_eigen!(c64, f64, zheev);

#[cfg(test)]
mod tests {
    use super::SymEigen;
    use ndarray::prelude::*;
    use matrix::Symmetric;

    #[test]
    fn try_eig() {
        let mut m = arr2(&[[1.0 as f32, 2.0], [2.0, 1.0]]);

        let r = SymEigen::compute_mut(&mut m, Symmetric::Upper, false);
        assert!(r.is_ok());

        assert_in_tol!(r.unwrap(), arr1(&[-1.0, 3.0]), 0.01);
    }

}
<|endoftext|>


<commit_before>use std::io;
use super::{
    Deserialize, Serialize, Error, VarUint7, VarInt7, VarUint32, VarUint1,
    ValueType, TableElementType
};

/// Global definition struct
#[derive(Debug, Clone)]
pub struct GlobalType {
    content_type: ValueType,
    is_mutable: bool,
}

impl GlobalType {
    /// New global type
    pub fn new(content_type: ValueType, is_mutable: bool) -> Self {
        GlobalType {
            content_type: content_type,
            is_mutable: is_mutable,
        }
    }

    /// Type of the global entry
    pub fn content_type(&self) -> ValueType { self.content_type }

    /// Is global entry is declared as mutable
    pub fn is_mutable(&self) -> bool { self.is_mutable }
}

impl Deserialize for GlobalType {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let content_type = ValueType::deserialize(reader)?;
        let is_mutable = VarUint1::deserialize(reader)?;
        Ok(GlobalType {
            content_type: content_type,
            is_mutable: is_mutable.into(),
        })
    }
}

impl Serialize for GlobalType {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        self.content_type.serialize(writer)?;
        VarUint1::from(self.is_mutable).serialize(writer)?;
        Ok(())
    }
}

/// Table entry
#[derive(Debug, Clone)]
pub struct TableType {
    elem_type: TableElementType,
    limits: ResizableLimits,
}

impl TableType {
    /// New table definition
    pub fn new(min: u32, max: Option<u32>) -> Self {
        TableType {
            elem_type: TableElementType::AnyFunc,
            limits: ResizableLimits::new(min, max),
        }
    }

    /// Table memory specification
    pub fn limits(&self) -> &ResizableLimits { &self.limits }

    /// Table element type
    pub fn elem_type(&self) -> TableElementType { self.elem_type }
}

impl Deserialize for TableType {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let elem_type = TableElementType::deserialize(reader)?;
        let limits = ResizableLimits::deserialize(reader)?;
        Ok(TableType {
            elem_type: elem_type,
            limits: limits,
        })
    }
}

impl Serialize for TableType {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        self.elem_type.serialize(writer)?;
        self.limits.serialize(writer)
    }
}

/// Memory limits
#[derive(Debug, Clone)]
pub struct ResizableLimits {
    initial: u32,
    maximum: Option<u32>,
}

impl ResizableLimits {
    /// New memory limits definition
    pub fn new(min: u32, max: Option<u32>) -> Self {
        ResizableLimits {
            initial: min,
            maximum: max,
        }
    }
    /// Initial size
    pub fn initial(&self) -> u32 { self.initial }
    /// Maximum size
    pub fn maximum(&self) -> Option<u32> { self.maximum }
}

impl Deserialize for ResizableLimits {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let has_max = VarUint1::deserialize(reader)?;
        let initial = VarUint32::deserialize(reader)?;
        let maximum = if has_max.into() {
            Some(VarUint32::deserialize(reader)?.into())
        } else {
            None
        };

        Ok(ResizableLimits {
            initial: initial.into(),
            maximum: maximum,
        })
    }
}

impl Serialize for ResizableLimits {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        let max = self.maximum;
        VarUint1::from(max.is_some()).serialize(writer)?;
        VarUint32::from(self.initial).serialize(writer)?;
        if let Some(val) = max {
            VarUint32::from(val).serialize(writer)?;
        }
        Ok(())
    }
}

/// Memory entry.
#[derive(Debug, Clone)]
pub struct MemoryType(ResizableLimits);

impl MemoryType {
    /// New memory definition
    pub fn new(min: u32, max: Option<u32>) -> Self {
        MemoryType(ResizableLimits::new(min, max))
    }
    /// Limits of the memory entry.
    pub fn limits(&self) -> &ResizableLimits {
        &self.0
    }
}

impl Deserialize for MemoryType {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        Ok(MemoryType(ResizableLimits::deserialize(reader)?))
    }
}

impl Serialize for MemoryType {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        self.0.serialize(writer)
    }
}

/// External to local binding.
#[derive(Debug, Clone)]
pub enum External {
    /// Binds to function with index.
    Function(u32),
    /// Describes local table definition to be imported as.
    Table(TableType),
    /// Describes local memory definition to be imported as.
    Memory(MemoryType),
    /// Describes local global entry to be imported as.
    Global(GlobalType),
}

impl Deserialize for External {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let kind = VarUint7::deserialize(reader)?;
        match kind.into() {
            0x00 => Ok(External::Function(VarUint32::deserialize(reader)?.into())),
            0x01 => Ok(External::Table(TableType::deserialize(reader)?)),
            0x02 => Ok(External::Memory(MemoryType::deserialize(reader)?)),
            0x03 => Ok(External::Global(GlobalType::deserialize(reader)?)),
            _ => Err(Error::UnknownExternalKind(kind.into())),
        }
    }
}

impl Serialize for External {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        use self::External::*;

        match self {
            Function(index) => {
                VarUint7::from(0x00).serialize(writer)?;
                VarUint32::from(index).serialize(writer)?;
            },
            Table(tt) => {
                VarInt7::from(0x01).serialize(writer)?;
                tt.serialize(writer)?;
            },
            Memory(mt) => {
                VarInt7::from(0x02).serialize(writer)?;
                mt.serialize(writer)?;
            },
            Global(gt) => {
                VarInt7::from(0x03).serialize(writer)?;
                gt.serialize(writer)?;
            },
        }

        Ok(())
    }
}

/// Import entry.
#[derive(Debug, Clone)]
pub struct ImportEntry {
    module_str: String,
    field_str: String,
    external: External,
}

impl ImportEntry {
    /// New import entry.
    pub fn new(module_str: String, field_str: String, external: External) -> Self {
        ImportEntry {
            module_str: module_str,
            field_str: field_str,
            external: external,
        }
    }

    /// Module reference of the import entry.
    pub fn module(&self) -> &str { &self.module_str }

    /// Module reference of the import entry (mutable).
    pub fn module_mut(&mut self) -> &mut str {
        &mut self.module_str
    }

    /// Field reference of the import entry.
    pub fn field(&self) -> &str { &self.field_str }

    /// Field reference of the import entry (mutable)
    pub fn field_mut(&mut self) -> &mut str {
        &mut self.field_str
    }

    /// Local binidng of the import entry.
    pub fn external(&self) -> &External { &self.external }

    /// Local binidng of the import entry (mutable)
    pub fn external_mut(&mut self) -> &mut External { &mut self.external }
}

impl Deserialize for ImportEntry {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let module_str = String::deserialize(reader)?;
        let field_str = String::deserialize(reader)?;
        let external = External::deserialize(reader)?;

        Ok(ImportEntry {
            module_str: module_str,
            field_str: field_str,
            external: external,
        })
    }
}

impl Serialize for ImportEntry {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        self.module_str.serialize(writer)?;
        self.field_str.serialize(writer)?;
        self.external.serialize(writer)
    }
}
<commit_msg>fix api for import entry<commit_after>use std::io;
use super::{
    Deserialize, Serialize, Error, VarUint7, VarInt7, VarUint32, VarUint1,
    ValueType, TableElementType
};

/// Global definition struct
#[derive(Debug, Clone)]
pub struct GlobalType {
    content_type: ValueType,
    is_mutable: bool,
}

impl GlobalType {
    /// New global type
    pub fn new(content_type: ValueType, is_mutable: bool) -> Self {
        GlobalType {
            content_type: content_type,
            is_mutable: is_mutable,
        }
    }

    /// Type of the global entry
    pub fn content_type(&self) -> ValueType { self.content_type }

    /// Is global entry is declared as mutable
    pub fn is_mutable(&self) -> bool { self.is_mutable }
}

impl Deserialize for GlobalType {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let content_type = ValueType::deserialize(reader)?;
        let is_mutable = VarUint1::deserialize(reader)?;
        Ok(GlobalType {
            content_type: content_type,
            is_mutable: is_mutable.into(),
        })
    }
}

impl Serialize for GlobalType {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        self.content_type.serialize(writer)?;
        VarUint1::from(self.is_mutable).serialize(writer)?;
        Ok(())
    }
}

/// Table entry
#[derive(Debug, Clone)]
pub struct TableType {
    elem_type: TableElementType,
    limits: ResizableLimits,
}

impl TableType {
    /// New table definition
    pub fn new(min: u32, max: Option<u32>) -> Self {
        TableType {
            elem_type: TableElementType::AnyFunc,
            limits: ResizableLimits::new(min, max),
        }
    }

    /// Table memory specification
    pub fn limits(&self) -> &ResizableLimits { &self.limits }

    /// Table element type
    pub fn elem_type(&self) -> TableElementType { self.elem_type }
}

impl Deserialize for TableType {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let elem_type = TableElementType::deserialize(reader)?;
        let limits = ResizableLimits::deserialize(reader)?;
        Ok(TableType {
            elem_type: elem_type,
            limits: limits,
        })
    }
}

impl Serialize for TableType {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        self.elem_type.serialize(writer)?;
        self.limits.serialize(writer)
    }
}

/// Memory limits
#[derive(Debug, Clone)]
pub struct ResizableLimits {
    initial: u32,
    maximum: Option<u32>,
}

impl ResizableLimits {
    /// New memory limits definition
    pub fn new(min: u32, max: Option<u32>) -> Self {
        ResizableLimits {
            initial: min,
            maximum: max,
        }
    }
    /// Initial size
    pub fn initial(&self) -> u32 { self.initial }
    /// Maximum size
    pub fn maximum(&self) -> Option<u32> { self.maximum }
}

impl Deserialize for ResizableLimits {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let has_max = VarUint1::deserialize(reader)?;
        let initial = VarUint32::deserialize(reader)?;
        let maximum = if has_max.into() {
            Some(VarUint32::deserialize(reader)?.into())
        } else {
            None
        };

        Ok(ResizableLimits {
            initial: initial.into(),
            maximum: maximum,
        })
    }
}

impl Serialize for ResizableLimits {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        let max = self.maximum;
        VarUint1::from(max.is_some()).serialize(writer)?;
        VarUint32::from(self.initial).serialize(writer)?;
        if let Some(val) = max {
            VarUint32::from(val).serialize(writer)?;
        }
        Ok(())
    }
}

/// Memory entry.
#[derive(Debug, Clone)]
pub struct MemoryType(ResizableLimits);

impl MemoryType {
    /// New memory definition
    pub fn new(min: u32, max: Option<u32>) -> Self {
        MemoryType(ResizableLimits::new(min, max))
    }
    /// Limits of the memory entry.
    pub fn limits(&self) -> &ResizableLimits {
        &self.0
    }
}

impl Deserialize for MemoryType {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        Ok(MemoryType(ResizableLimits::deserialize(reader)?))
    }
}

impl Serialize for MemoryType {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        self.0.serialize(writer)
    }
}

/// External to local binding.
#[derive(Debug, Clone)]
pub enum External {
    /// Binds to function with index.
    Function(u32),
    /// Describes local table definition to be imported as.
    Table(TableType),
    /// Describes local memory definition to be imported as.
    Memory(MemoryType),
    /// Describes local global entry to be imported as.
    Global(GlobalType),
}

impl Deserialize for External {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let kind = VarUint7::deserialize(reader)?;
        match kind.into() {
            0x00 => Ok(External::Function(VarUint32::deserialize(reader)?.into())),
            0x01 => Ok(External::Table(TableType::deserialize(reader)?)),
            0x02 => Ok(External::Memory(MemoryType::deserialize(reader)?)),
            0x03 => Ok(External::Global(GlobalType::deserialize(reader)?)),
            _ => Err(Error::UnknownExternalKind(kind.into())),
        }
    }
}

impl Serialize for External {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        use self::External::*;

        match self {
            Function(index) => {
                VarUint7::from(0x00).serialize(writer)?;
                VarUint32::from(index).serialize(writer)?;
            },
            Table(tt) => {
                VarInt7::from(0x01).serialize(writer)?;
                tt.serialize(writer)?;
            },
            Memory(mt) => {
                VarInt7::from(0x02).serialize(writer)?;
                mt.serialize(writer)?;
            },
            Global(gt) => {
                VarInt7::from(0x03).serialize(writer)?;
                gt.serialize(writer)?;
            },
        }

        Ok(())
    }
}

/// Import entry.
#[derive(Debug, Clone)]
pub struct ImportEntry {
    module_str: String,
    field_str: String,
    external: External,
}

impl ImportEntry {
    /// New import entry.
    pub fn new(module_str: String, field_str: String, external: External) -> Self {
        ImportEntry {
            module_str: module_str,
            field_str: field_str,
            external: external,
        }
    }

    /// Module reference of the import entry.
    pub fn module(&self) -> &str { &self.module_str }

    /// Module reference of the import entry (mutable).
    pub fn module_mut(&mut self) -> &mut String {
        &mut self.module_str
    }

    /// Field reference of the import entry.
    pub fn field(&self) -> &str { &self.field_str }

    /// Field reference of the import entry (mutable)
    pub fn field_mut(&mut self) -> &mut String {
        &mut self.field_str
    }

    /// Local binidng of the import entry.
    pub fn external(&self) -> &External { &self.external }

    /// Local binidng of the import entry (mutable)
    pub fn external_mut(&mut self) -> &mut External { &mut self.external }
}

impl Deserialize for ImportEntry {
    type Error = Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let module_str = String::deserialize(reader)?;
        let field_str = String::deserialize(reader)?;
        let external = External::deserialize(reader)?;

        Ok(ImportEntry {
            module_str: module_str,
            field_str: field_str,
            external: external,
        })
    }
}

impl Serialize for ImportEntry {
    type Error = Error;

    fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
        self.module_str.serialize(writer)?;
        self.field_str.serialize(writer)?;
        self.external.serialize(writer)
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::default::Default;
use time;

#[doc(hidden)]
pub struct Ratelimit {
    pub delay: i64,
    pub limit: Option<(i64, i32)>,
}

#[doc(hidden)]
pub struct MemberRatelimit {
    pub tickets: i32,
    pub last_time: i64,
    pub set_time: i64,
}

impl Default for MemberRatelimit {
    fn default() -> Self {
        MemberRatelimit {
            tickets: 0,
            last_time: 0,
            set_time: 0,
        }
    }
}

#[doc(hidden)]
pub struct Bucket {
    pub ratelimit: Ratelimit,
    pub users: HashMap<u64, MemberRatelimit>,
}

impl Bucket {
    pub fn take(&mut self, user_id: u64) -> i64 {
        let time =- time::get_time().sec;
        let user = self.users.entry(user_id)
            .or_insert_with(MemberRatelimit::default);

        if let Some((timespan, limit)) = self.ratelimit.limit {
            if (user.tickets + 1) > limit {
                if time < (user.set_time + timespan) {
                    return (user.set_time + timespan) - time;
                } else {
                    user.tickets = 0;
                    user.set_time = time;
                }
            }
        }

        if time < user.last_time + self.ratelimit.delay {
            (user.last_time + self.ratelimit.delay) - time
        } else {
            user.tickets += 1;
            user.last_time = time;

            0
        }
    }
}
<commit_msg>Fix framework command cooldowns<commit_after>use std::collections::HashMap;
use std::default::Default;
use time;

#[doc(hidden)]
pub struct Ratelimit {
    pub delay: i64,
    pub limit: Option<(i64, i32)>,
}

#[doc(hidden)]
pub struct MemberRatelimit {
    pub tickets: i32,
    pub last_time: i64,
    pub set_time: i64,
}

impl Default for MemberRatelimit {
    fn default() -> Self {
        MemberRatelimit {
            tickets: 0,
            last_time: 0,
            set_time: 0,
        }
    }
}

#[doc(hidden)]
pub struct Bucket {
    pub ratelimit: Ratelimit,
    pub users: HashMap<u64, MemberRatelimit>,
}

impl Bucket {
    pub fn take(&mut self, user_id: u64) -> i64 {
        let time = time::get_time().sec;
        let user = self.users.entry(user_id)
            .or_insert_with(MemberRatelimit::default);

        if let Some((timespan, limit)) = self.ratelimit.limit {
            if (user.tickets + 1) > limit {
                if time < (user.set_time + timespan) {
                    return (user.set_time + timespan) - time;
                } else {
                    user.tickets = 0;
                    user.set_time = time;
                }
            }
        }

        if time < user.last_time + self.ratelimit.delay {
            (user.last_time + self.ratelimit.delay) - time
        } else {
            user.tickets += 1;
            user.last_time = time;

            0
        }
    }
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::HashMap;
use std::fmt;

use english_cardinal_classifier;
use {Args, Context, Message, MessagePart, PluralCategory, Value};

/// Format a value taking pluralization rules into account.
#[derive(Debug)]
pub struct PluralFormat {
    /// The name of the variable whose value should be formatted.
    variable_name: String,
    classifier: fn(i64) -> PluralCategory,
    literals: HashMap<i64, Message>,
    offset: i64,
    zero: Option<Message>,
    one: Option<Message>,
    two: Option<Message>,
    few: Option<Message>,
    many: Option<Message>,
    other: Message,
}

impl PluralFormat {
    /// Construct a `PluralFormat`.
    pub fn new(variable_name: &str, other: Message) -> Self {
        PluralFormat {
            variable_name: variable_name.to_string(),
            classifier: english_cardinal_classifier,
            literals: HashMap::new(),
            offset: 0,
            zero: None,
            one: None,
            two: None,
            few: None,
            many: None,
            other: other,
        }
    }

    /// Set the `message` to be used for a literal value.
    pub fn literal(&mut self, literal: i64, message: Message) {
        self.literals.insert(literal, message);
    }

    /// Apply an `offset`.
    pub fn offset(&mut self, offset: i64) {
        self.offset = offset;
    }

    /// Set the `message` for `PluralCategory::Zero`.
    pub fn zero(&mut self, message: Message) {
        self.zero = Some(message);
    }

    /// Set the `message` for `PluralCategory::One`.
    pub fn one(&mut self, message: Message) {
        self.one = Some(message);
    }

    /// Set the `message` for `PluralCategory::Two`.
    pub fn two(&mut self, message: Message) {
        self.two = Some(message);
    }

    /// Set the `message` for `PluralCategory::Few`.
    pub fn few(&mut self, message: Message) {
        self.few = Some(message);
    }

    /// Set the `message` for `PluralCategory::Many`.
    pub fn many(&mut self, message: Message) {
        self.many = Some(message);
    }

    /// Given a value adjusted by the `offset`, determine which `Message` to use.
    fn lookup_message(&self, offset_value: i64) -> &Message {
        if let Some(literal) = self.literals.get(&offset_value) {
            literal
        } else {
            let category = (self.classifier)(offset_value);
            match category {
                PluralCategory::Zero => self.zero.as_ref().unwrap_or(&self.other),
                PluralCategory::One => self.one.as_ref().unwrap_or(&self.other),
                PluralCategory::Two => self.two.as_ref().unwrap_or(&self.other),
                PluralCategory::Few => self.few.as_ref().unwrap_or(&self.other),
                PluralCategory::Many => self.many.as_ref().unwrap_or(&self.other),
                PluralCategory::Other => &self.other,
            }
        }
    }

    /// Handle specialized behavior for `PlaceholderFormat` when formatting
    /// a `PluralFormat`.
    ///
    /// XXX: Can we fold this away and do something more general for
    /// `PlaceholderFormat`?
    fn format_plural_message<'f>(&'f self,
                                 context: &Context,
                                 stream: &mut fmt::Write,
                                 message: &'f Message,
                                 _offset_value: i64,
                                 args: &'f Args<'f>)
                                 -> fmt::Result {
        for part in &message.parts {
            // XXX: Need to deal with PlaceholderFormat here and give it
            // the `offset_value`.
            try!(part.apply_format(context, stream, args));
        }
        Ok(())
    }
}

impl MessagePart for PluralFormat {
    fn apply_format<'f>(&'f self,
                        context: &Context,
                        stream: &mut fmt::Write,
                        args: &'f Args<'f>)
                        -> fmt::Result {
        if let Some(arg) = args.get(&self.variable_name) {
            let value = match *arg.value() {
                Value::Number(n) => n,
                _ => panic!("Wrong variable type."),
            };
            let offset_value = value - self.offset;
            let message = self.lookup_message(offset_value);
            try!(self.format_plural_message(context, stream, message, offset_value, args));
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use icu::parse;
    use super::PluralFormat;
    use {arg, Context, MessagePart};

    #[test]
    fn it_works() {
        let context = Context::new(None);
        let mut fmt = PluralFormat::new("count", parse("Other").unwrap());
        fmt.one(parse("One").unwrap());

        let mut output = String::new();
        fmt.apply_format(&context, &mut output, &arg("count", 0)).unwrap();
        assert_eq!("Other", output);

        let mut output = String::new();
        fmt.apply_format(&context, &mut output, &arg("count", 1)).unwrap();
        assert_eq!("One", output);

        let mut output = String::new();
        fmt.apply_format(&context, &mut output, &arg("count", 3)).unwrap();
        assert_eq!("Other", output);
    }
}
<commit_msg>We can just directly call the normal write_message now from PluralFormat.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::HashMap;
use std::fmt;

use english_cardinal_classifier;
use {Args, Context, Message, MessagePart, PluralCategory, Value};

/// Format a value taking pluralization rules into account.
#[derive(Debug)]
pub struct PluralFormat {
    /// The name of the variable whose value should be formatted.
    variable_name: String,
    classifier: fn(i64) -> PluralCategory,
    literals: HashMap<i64, Message>,
    offset: i64,
    zero: Option<Message>,
    one: Option<Message>,
    two: Option<Message>,
    few: Option<Message>,
    many: Option<Message>,
    other: Message,
}

impl PluralFormat {
    /// Construct a `PluralFormat`.
    pub fn new(variable_name: &str, other: Message) -> Self {
        PluralFormat {
            variable_name: variable_name.to_string(),
            classifier: english_cardinal_classifier,
            literals: HashMap::new(),
            offset: 0,
            zero: None,
            one: None,
            two: None,
            few: None,
            many: None,
            other: other,
        }
    }

    /// Set the `message` to be used for a literal value.
    pub fn literal(&mut self, literal: i64, message: Message) {
        self.literals.insert(literal, message);
    }

    /// Apply an `offset`.
    pub fn offset(&mut self, offset: i64) {
        self.offset = offset;
    }

    /// Set the `message` for `PluralCategory::Zero`.
    pub fn zero(&mut self, message: Message) {
        self.zero = Some(message);
    }

    /// Set the `message` for `PluralCategory::One`.
    pub fn one(&mut self, message: Message) {
        self.one = Some(message);
    }

    /// Set the `message` for `PluralCategory::Two`.
    pub fn two(&mut self, message: Message) {
        self.two = Some(message);
    }

    /// Set the `message` for `PluralCategory::Few`.
    pub fn few(&mut self, message: Message) {
        self.few = Some(message);
    }

    /// Set the `message` for `PluralCategory::Many`.
    pub fn many(&mut self, message: Message) {
        self.many = Some(message);
    }

    /// Given a value adjusted by the `offset`, determine which `Message` to use.
    fn lookup_message(&self, offset_value: i64) -> &Message {
        if let Some(literal) = self.literals.get(&offset_value) {
            literal
        } else {
            let category = (self.classifier)(offset_value);
            match category {
                PluralCategory::Zero => self.zero.as_ref().unwrap_or(&self.other),
                PluralCategory::One => self.one.as_ref().unwrap_or(&self.other),
                PluralCategory::Two => self.two.as_ref().unwrap_or(&self.other),
                PluralCategory::Few => self.few.as_ref().unwrap_or(&self.other),
                PluralCategory::Many => self.many.as_ref().unwrap_or(&self.other),
                PluralCategory::Other => &self.other,
            }
        }
    }
}

impl MessagePart for PluralFormat {
    fn apply_format<'f>(&'f self,
                        context: &Context,
                        stream: &mut fmt::Write,
                        args: &'f Args<'f>)
                        -> fmt::Result {
        if let Some(arg) = args.get(&self.variable_name) {
            let value = match *arg.value() {
                Value::Number(n) => n,
                _ => panic!("Wrong variable type."),
            };
            let offset_value = value - self.offset;
            let message = self.lookup_message(offset_value);
            try!(message.write_message(context, stream, args));
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use icu::parse;
    use super::PluralFormat;
    use {arg, Context, MessagePart};

    #[test]
    fn it_works() {
        let context = Context::new(None);
        let mut fmt = PluralFormat::new("count", parse("Other").unwrap());
        fmt.one(parse("One").unwrap());

        let mut output = String::new();
        fmt.apply_format(&context, &mut output, &arg("count", 0)).unwrap();
        assert_eq!("Other", output);

        let mut output = String::new();
        fmt.apply_format(&context, &mut output, &arg("count", 1)).unwrap();
        assert_eq!("One", output);

        let mut output = String::new();
        fmt.apply_format(&context, &mut output, &arg("count", 3)).unwrap();
        assert_eq!("Other", output);
    }
}
<|endoftext|>


<commit_before>use decoders::Image;
use imageops::fcol;

pub fn whitebalance(img: &Image, inb: &[f32]) -> Vec<f32> {
  let mut out: Vec<f32> = vec![0.0; (img.width*img.height) as usize];

  // Set green multiplier as 1.0
  let unity: f32 = img.wb_coeffs[1];
  let mul = img.wb_coeffs.iter().map(|x| if x.is_nan() { 1.0 } else { x / unity }).collect::<Vec<f32>>();

  let mut pos = 0;
  for row in 0..img.height {
    for col in 0..img.width {
      let pixel = inb[pos];
      let color = fcol(img, row, col);
      out[pos] = pixel * mul[color];
      pos += 1;
    }
  }

  out
}
<commit_msg>whitebalance: clip highlights<commit_after>use decoders::Image;
use imageops::fcol;

pub fn whitebalance(img: &Image, inb: &[f32]) -> Vec<f32> {
  let mut out: Vec<f32> = vec![0.0; (img.width*img.height) as usize];

  // Set green multiplier as 1.0
  let unity: f32 = img.wb_coeffs[1];
  let mul = img.wb_coeffs.iter().map(|x| if x.is_nan() { 1.0 } else { x / unity }).collect::<Vec<f32>>();

  let mut pos = 0;
  for row in 0..img.height {
    for col in 0..img.width {
      let pixel = inb[pos];
      let color = fcol(img, row, col);
      out[pos] = (pixel * mul[color]).min(1.0);
      pos += 1;
    }
  }

  out
}
<|endoftext|>


<commit_before>//! Diagnostic data structures.

#[cfg(feature = "serialization")]
use serde::{Deserialize, Serialize};
use std::ops::Range;
use std::string::ToString;

/// A severity level for diagnostic messages.
///
/// These are ordered in the following way:
///
/// ```rust
/// use codespan_reporting::diagnostic::Severity;
///
/// assert!(Severity::Bug > Severity::Error);
/// assert!(Severity::Error > Severity::Warning);
/// assert!(Severity::Warning > Severity::Note);
/// assert!(Severity::Note > Severity::Help);
/// ```
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub enum Severity {
    /// An unexpected bug.
    Bug,
    /// An error.
    Error,
    /// A warning.
    Warning,
    /// A note.
    Note,
    /// A help message.
    Help,
}

impl Severity {
    /// We want bugs to be the maximum severity, errors next, etc...
    fn to_cmp_int(self) -> u8 {
        match self {
            Severity::Bug => 5,
            Severity::Error => 4,
            Severity::Warning => 3,
            Severity::Note => 2,
            Severity::Help => 1,
        }
    }
}

impl PartialOrd for Severity {
    fn partial_cmp(&self, other: &Severity) -> Option<std::cmp::Ordering> {
        u8::partial_cmp(&self.to_cmp_int(), &other.to_cmp_int())
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub enum LabelStyle {
    /// Labels that describe the primary cause of a diagnostic.
    Primary,
    /// Labels that provide additional context for a diagnostic.
    Secondary,
}

/// A label describing an underlined region of code associated with a diagnostic.
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct Label<FileId> {
    /// The style of the label.
    pub style: LabelStyle,
    /// The file that we are labelling.
    pub file_id: FileId,
    /// The range in bytes we are going to include in the final snippet.
    pub range: Range<usize>,
    /// An optional message to provide some additional information for the
    /// underlined code. These should not include line breaks.
    pub message: String,
}

impl<FileId> Label<FileId> {
    /// Create a new label.
    pub fn new(
        style: LabelStyle,
        file_id: FileId,
        range: impl Into<Range<usize>>,
    ) -> Label<FileId> {
        Label {
            style,
            file_id,
            range: range.into(),
            message: String::new(),
        }
    }

    /// Create a new label with a style of [`LabelStyle::Primary`].
    ///
    /// [`LabelStyle::Primary`]: LabelStyle::Primary
    pub fn primary(file_id: FileId, range: impl Into<Range<usize>>) -> Label<FileId> {
        Label::new(LabelStyle::Primary, file_id, range)
    }

    /// Create a new label with a style of [`LabelStyle::Secondary`].
    ///
    /// [`LabelStyle::Secondary`]: LabelStyle::Secondary
    pub fn secondary(file_id: FileId, range: impl Into<Range<usize>>) -> Label<FileId> {
        Label::new(LabelStyle::Secondary, file_id, range)
    }

    /// Add a message to the diagnostic.
    pub fn with_message(mut self, message: impl ToString) -> Label<FileId> {
        self.message = message.to_string();
        self
    }
}

/// Represents a diagnostic message that can provide information like errors and
/// warnings to the user.
///
/// The position of a Diagnostic is considered to be the position of the [`Label`] that has the earliest starting position and has the highest style which appears in all the labels of the diagnostic.
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct Diagnostic<FileId> {
    /// The overall severity of the diagnostic
    pub severity: Severity,
    /// An optional code that identifies this diagnostic.
    pub code: Option<String>,
    /// The main message associated with this diagnostic.
    ///
    /// These should not include line breaks, and in order support the 'short'
    /// diagnostic display mod, the message should be specific enough to make
    /// sense on its own, without additional context provided by labels and notes.
    pub message: String,
    /// Source labels that describe the cause of the diagnostic.
    /// The order of the labels inside the vector does not have any meaning.
    /// The labels are always arranged in the order they appear in the source code.
    pub labels: Vec<Label<FileId>>,
    /// Notes that are associated with the primary cause of the diagnostic.
    /// These can include line breaks for improved formatting.
    pub notes: Vec<String>,
}

impl<FileId> Diagnostic<FileId> {
    /// Create a new diagnostic.
    pub fn new(severity: Severity) -> Diagnostic<FileId> {
        Diagnostic {
            severity,
            code: None,
            message: String::new(),
            labels: Vec::new(),
            notes: Vec::new(),
        }
    }

    /// Create a new diagnostic with a severity of [`Severity::Bug`].
    ///
    /// [`Severity::Bug`]: Severity::Bug
    pub fn bug() -> Diagnostic<FileId> {
        Diagnostic::new(Severity::Bug)
    }

    /// Create a new diagnostic with a severity of [`Severity::Error`].
    ///
    /// [`Severity::Error`]: Severity::Error
    pub fn error() -> Diagnostic<FileId> {
        Diagnostic::new(Severity::Error)
    }

    /// Create a new diagnostic with a severity of [`Severity::Warning`].
    ///
    /// [`Severity::Warning`]: Severity::Warning
    pub fn warning() -> Diagnostic<FileId> {
        Diagnostic::new(Severity::Warning)
    }

    /// Create a new diagnostic with a severity of [`Severity::Note`].
    ///
    /// [`Severity::Note`]: Severity::Note
    pub fn note() -> Diagnostic<FileId> {
        Diagnostic::new(Severity::Note)
    }

    /// Create a new diagnostic with a severity of [`Severity::Help`].
    ///
    /// [`Severity::Help`]: Severity::Help
    pub fn help() -> Diagnostic<FileId> {
        Diagnostic::new(Severity::Help)
    }

    /// Set the error code of the diagnostic.
    pub fn with_code(mut self, code: impl Into<String>) -> Diagnostic<FileId> {
        self.code = Some(code.into());
        self
    }

    /// Set the message of the diagnostic.
    pub fn with_message(mut self, message: impl ToString) -> Diagnostic<FileId> {
        self.message = message.to_string();
        self
    }

    /// Add some labels to the diagnostic.
    pub fn with_labels(mut self, mut labels: Vec<Label<FileId>>) -> Diagnostic<FileId> {
        self.labels.append(&mut labels);
        self
    }

    /// Add some notes to the diagnostic.
    pub fn with_notes(mut self, mut notes: Vec<String>) -> Diagnostic<FileId> {
        self.notes.append(&mut notes);
        self
    }
}
<commit_msg>use ToString in with_code too<commit_after>//! Diagnostic data structures.

#[cfg(feature = "serialization")]
use serde::{Deserialize, Serialize};
use std::ops::Range;
use std::string::ToString;

/// A severity level for diagnostic messages.
///
/// These are ordered in the following way:
///
/// ```rust
/// use codespan_reporting::diagnostic::Severity;
///
/// assert!(Severity::Bug > Severity::Error);
/// assert!(Severity::Error > Severity::Warning);
/// assert!(Severity::Warning > Severity::Note);
/// assert!(Severity::Note > Severity::Help);
/// ```
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub enum Severity {
    /// An unexpected bug.
    Bug,
    /// An error.
    Error,
    /// A warning.
    Warning,
    /// A note.
    Note,
    /// A help message.
    Help,
}

impl Severity {
    /// We want bugs to be the maximum severity, errors next, etc...
    fn to_cmp_int(self) -> u8 {
        match self {
            Severity::Bug => 5,
            Severity::Error => 4,
            Severity::Warning => 3,
            Severity::Note => 2,
            Severity::Help => 1,
        }
    }
}

impl PartialOrd for Severity {
    fn partial_cmp(&self, other: &Severity) -> Option<std::cmp::Ordering> {
        u8::partial_cmp(&self.to_cmp_int(), &other.to_cmp_int())
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub enum LabelStyle {
    /// Labels that describe the primary cause of a diagnostic.
    Primary,
    /// Labels that provide additional context for a diagnostic.
    Secondary,
}

/// A label describing an underlined region of code associated with a diagnostic.
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct Label<FileId> {
    /// The style of the label.
    pub style: LabelStyle,
    /// The file that we are labelling.
    pub file_id: FileId,
    /// The range in bytes we are going to include in the final snippet.
    pub range: Range<usize>,
    /// An optional message to provide some additional information for the
    /// underlined code. These should not include line breaks.
    pub message: String,
}

impl<FileId> Label<FileId> {
    /// Create a new label.
    pub fn new(
        style: LabelStyle,
        file_id: FileId,
        range: impl Into<Range<usize>>,
    ) -> Label<FileId> {
        Label {
            style,
            file_id,
            range: range.into(),
            message: String::new(),
        }
    }

    /// Create a new label with a style of [`LabelStyle::Primary`].
    ///
    /// [`LabelStyle::Primary`]: LabelStyle::Primary
    pub fn primary(file_id: FileId, range: impl Into<Range<usize>>) -> Label<FileId> {
        Label::new(LabelStyle::Primary, file_id, range)
    }

    /// Create a new label with a style of [`LabelStyle::Secondary`].
    ///
    /// [`LabelStyle::Secondary`]: LabelStyle::Secondary
    pub fn secondary(file_id: FileId, range: impl Into<Range<usize>>) -> Label<FileId> {
        Label::new(LabelStyle::Secondary, file_id, range)
    }

    /// Add a message to the diagnostic.
    pub fn with_message(mut self, message: impl ToString) -> Label<FileId> {
        self.message = message.to_string();
        self
    }
}

/// Represents a diagnostic message that can provide information like errors and
/// warnings to the user.
///
/// The position of a Diagnostic is considered to be the position of the [`Label`] that has the earliest starting position and has the highest style which appears in all the labels of the diagnostic.
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct Diagnostic<FileId> {
    /// The overall severity of the diagnostic
    pub severity: Severity,
    /// An optional code that identifies this diagnostic.
    pub code: Option<String>,
    /// The main message associated with this diagnostic.
    ///
    /// These should not include line breaks, and in order support the 'short'
    /// diagnostic display mod, the message should be specific enough to make
    /// sense on its own, without additional context provided by labels and notes.
    pub message: String,
    /// Source labels that describe the cause of the diagnostic.
    /// The order of the labels inside the vector does not have any meaning.
    /// The labels are always arranged in the order they appear in the source code.
    pub labels: Vec<Label<FileId>>,
    /// Notes that are associated with the primary cause of the diagnostic.
    /// These can include line breaks for improved formatting.
    pub notes: Vec<String>,
}

impl<FileId> Diagnostic<FileId> {
    /// Create a new diagnostic.
    pub fn new(severity: Severity) -> Diagnostic<FileId> {
        Diagnostic {
            severity,
            code: None,
            message: String::new(),
            labels: Vec::new(),
            notes: Vec::new(),
        }
    }

    /// Create a new diagnostic with a severity of [`Severity::Bug`].
    ///
    /// [`Severity::Bug`]: Severity::Bug
    pub fn bug() -> Diagnostic<FileId> {
        Diagnostic::new(Severity::Bug)
    }

    /// Create a new diagnostic with a severity of [`Severity::Error`].
    ///
    /// [`Severity::Error`]: Severity::Error
    pub fn error() -> Diagnostic<FileId> {
        Diagnostic::new(Severity::Error)
    }

    /// Create a new diagnostic with a severity of [`Severity::Warning`].
    ///
    /// [`Severity::Warning`]: Severity::Warning
    pub fn warning() -> Diagnostic<FileId> {
        Diagnostic::new(Severity::Warning)
    }

    /// Create a new diagnostic with a severity of [`Severity::Note`].
    ///
    /// [`Severity::Note`]: Severity::Note
    pub fn note() -> Diagnostic<FileId> {
        Diagnostic::new(Severity::Note)
    }

    /// Create a new diagnostic with a severity of [`Severity::Help`].
    ///
    /// [`Severity::Help`]: Severity::Help
    pub fn help() -> Diagnostic<FileId> {
        Diagnostic::new(Severity::Help)
    }

    /// Set the error code of the diagnostic.
    pub fn with_code(mut self, code: impl ToString) -> Diagnostic<FileId> {
        self.code = Some(code.to_string());
        self
    }

    /// Set the message of the diagnostic.
    pub fn with_message(mut self, message: impl ToString) -> Diagnostic<FileId> {
        self.message = message.to_string();
        self
    }

    /// Add some labels to the diagnostic.
    pub fn with_labels(mut self, mut labels: Vec<Label<FileId>>) -> Diagnostic<FileId> {
        self.labels.append(&mut labels);
        self
    }

    /// Add some notes to the diagnostic.
    pub fn with_notes(mut self, mut notes: Vec<String>) -> Diagnostic<FileId> {
        self.notes.append(&mut notes);
        self
    }
}
<|endoftext|>