<commit_before>//! Assorted functions shared by several assists.
pub(crate) mod insert_use;
pub(crate) mod import_assets;

use std::ops;

use hir::{Crate, Enum, HasSource, Module, ScopeDef, Semantics, Trait};
use ide_db::RootDatabase;
use itertools::Itertools;
use syntax::{
    ast::edit::AstNodeEdit,
    ast::NameOwner,
    ast::{self, edit, make, ArgListOwner},
    AstNode, Direction,
    SyntaxKind::*,
    SyntaxNode, TextSize, T,
};

use crate::{
    assist_config::SnippetCap,
    ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams},
};

pub use insert_use::MergeBehaviour;
pub(crate) use insert_use::{insert_use, ImportScope};

pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path {
    let mut segments = Vec::new();
    let mut is_abs = false;
    match path.kind {
        hir::PathKind::Plain => {}
        hir::PathKind::Super(0) => segments.push(make::path_segment_self()),
        hir::PathKind::Super(n) => segments.extend((0..n).map(|_| make::path_segment_super())),
        hir::PathKind::DollarCrate(_) | hir::PathKind::Crate => {
            segments.push(make::path_segment_crate())
        }
        hir::PathKind::Abs => is_abs = true,
    }

    segments.extend(
        path.segments
            .iter()
            .map(|segment| make::path_segment(make::name_ref(&segment.to_string()))),
    );
    make::path_from_segments(segments, is_abs)
}

pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr {
    extract_trivial_expression(&block)
        .filter(|expr| !expr.syntax().text().contains_char('\n'))
        .unwrap_or_else(|| block.into())
}

pub fn extract_trivial_expression(block: &ast::BlockExpr) -> Option<ast::Expr> {
    let has_anything_else = |thing: &SyntaxNode| -> bool {
        let mut non_trivial_children =
            block.syntax().children_with_tokens().filter(|it| match it.kind() {
                WHITESPACE | T!['{'] | T!['}'] => false,
                _ => it.as_node() != Some(thing),
            });
        non_trivial_children.next().is_some()
    };

    if let Some(expr) = block.expr() {
        if has_anything_else(expr.syntax()) {
            return None;
        }
        return Some(expr);
    }
    // Unwrap `{ continue; }`
    let (stmt,) = block.statements().next_tuple()?;
    if let ast::Stmt::ExprStmt(expr_stmt) = stmt {
        if has_anything_else(expr_stmt.syntax()) {
            return None;
        }
        let expr = expr_stmt.expr()?;
        match expr.syntax().kind() {
            CONTINUE_EXPR | BREAK_EXPR | RETURN_EXPR => return Some(expr),
            _ => (),
        }
    }
    None
}

#[derive(Copy, Clone, PartialEq)]
pub enum DefaultMethods {
    Only,
    No,
}

pub fn filter_assoc_items(
    db: &RootDatabase,
    items: &[hir::AssocItem],
    default_methods: DefaultMethods,
) -> Vec<ast::AssocItem> {
    fn has_def_name(item: &ast::AssocItem) -> bool {
        match item {
            ast::AssocItem::Fn(def) => def.name(),
            ast::AssocItem::TypeAlias(def) => def.name(),
            ast::AssocItem::Const(def) => def.name(),
            ast::AssocItem::MacroCall(_) => None,
        }
        .is_some()
    };

    items
        .iter()
        .map(|i| match i {
            hir::AssocItem::Function(i) => ast::AssocItem::Fn(i.source(db).value),
            hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(i.source(db).value),
            hir::AssocItem::Const(i) => ast::AssocItem::Const(i.source(db).value),
        })
        .filter(has_def_name)
        .filter(|it| match it {
            ast::AssocItem::Fn(def) => matches!(
                (default_methods, def.body()),
                (DefaultMethods::Only, Some(_)) | (DefaultMethods::No, None)
            ),
            _ => default_methods == DefaultMethods::No,
        })
        .collect::<Vec<_>>()
}

pub fn add_trait_assoc_items_to_impl(
    sema: &hir::Semantics<ide_db::RootDatabase>,
    items: Vec<ast::AssocItem>,
    trait_: hir::Trait,
    impl_def: ast::Impl,
    target_scope: hir::SemanticsScope,
) -> (ast::Impl, ast::AssocItem) {
    let impl_item_list = impl_def.assoc_item_list().unwrap_or_else(make::assoc_item_list);

    let n_existing_items = impl_item_list.assoc_items().count();
    let source_scope = sema.scope_for_def(trait_);
    let ast_transform = QualifyPaths::new(&target_scope, &source_scope)
        .or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_def.clone()));

    let items = items
        .into_iter()
        .map(|it| ast_transform::apply(&*ast_transform, it))
        .map(|it| match it {
            ast::AssocItem::Fn(def) => ast::AssocItem::Fn(add_body(def)),
            ast::AssocItem::TypeAlias(def) => ast::AssocItem::TypeAlias(def.remove_bounds()),
            _ => it,
        })
        .map(|it| edit::remove_attrs_and_docs(&it));

    let new_impl_item_list = impl_item_list.append_items(items);
    let new_impl_def = impl_def.with_assoc_item_list(new_impl_item_list);
    let first_new_item =
        new_impl_def.assoc_item_list().unwrap().assoc_items().nth(n_existing_items).unwrap();
    return (new_impl_def, first_new_item);

    fn add_body(fn_def: ast::Fn) -> ast::Fn {
        match fn_def.body() {
            Some(_) => fn_def,
            None => {
                let body =
                    make::block_expr(None, Some(make::expr_todo())).indent(edit::IndentLevel(1));
                fn_def.with_body(body)
            }
        }
    }
}

#[derive(Clone, Copy, Debug)]
pub(crate) enum Cursor<'a> {
    Replace(&'a SyntaxNode),
    Before(&'a SyntaxNode),
}

impl<'a> Cursor<'a> {
    fn node(self) -> &'a SyntaxNode {
        match self {
            Cursor::Replace(node) | Cursor::Before(node) => node,
        }
    }
}

pub(crate) fn render_snippet(_cap: SnippetCap, node: &SyntaxNode, cursor: Cursor) -> String {
    assert!(cursor.node().ancestors().any(|it| it == *node));
    let range = cursor.node().text_range() - node.text_range().start();
    let range: ops::Range<usize> = range.into();

    let mut placeholder = cursor.node().to_string();
    escape(&mut placeholder);
    let tab_stop = match cursor {
        Cursor::Replace(placeholder) => format!("${{0:{}}}", placeholder),
        Cursor::Before(placeholder) => format!("$0{}", placeholder),
    };

    let mut buf = node.to_string();
    buf.replace_range(range, &tab_stop);
    return buf;

    fn escape(buf: &mut String) {
        stdx::replace(buf, '{', r"\{");
        stdx::replace(buf, '}', r"\}");
        stdx::replace(buf, '$', r"\$");
    }
}

pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize {
    node.children_with_tokens()
        .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
        .map(|it| it.text_range().start())
        .unwrap_or_else(|| node.text_range().start())
}

pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr {
    if let Some(expr) = invert_special_case(&expr) {
        return expr;
    }
    make::expr_prefix(T![!], expr)
}

fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
    match expr {
        ast::Expr::BinExpr(bin) => match bin.op_kind()? {
            ast::BinOp::NegatedEqualityTest => bin.replace_op(T![==]).map(|it| it.into()),
            ast::BinOp::EqualityTest => bin.replace_op(T![!=]).map(|it| it.into()),
            _ => None,
        },
        ast::Expr::MethodCallExpr(mce) => {
            let receiver = mce.receiver()?;
            let method = mce.name_ref()?;
            let arg_list = mce.arg_list()?;

            let method = match method.text().as_str() {
                "is_some" => "is_none",
                "is_none" => "is_some",
                "is_ok" => "is_err",
                "is_err" => "is_ok",
                _ => return None,
            };
            Some(make::expr_method_call(receiver, method, arg_list))
        }
        ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::PrefixOp::Not => pe.expr(),
        // FIXME:
        // ast::Expr::Literal(true | false )
        _ => None,
    }
}

/// Helps with finding well-know things inside the standard library. This is
/// somewhat similar to the known paths infra inside hir, but it different; We
/// want to make sure that IDE specific paths don't become interesting inside
/// the compiler itself as well.
pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Option<Crate>);

#[allow(non_snake_case)]
impl FamousDefs<'_, '_> {
    pub const FIXTURE: &'static str = r#"//- /libcore.rs crate:core
pub mod convert {
    pub trait From<T> {
        fn from(t: T) -> Self;
    }
}

pub mod default {
    pub trait Default: Sized {
       fn default() -> Self;
    }
}

pub mod iter {
    pub use self::traits::{collect::IntoIterator, iterator::Iterator};
    mod traits {
        pub(crate) mod iterator {
            use crate::option::Option;
            pub trait Iterator {
                type Item;
                fn next(&mut self) -> Option<Self::Item>;
                fn by_ref(&mut self) -> &mut Self {
                    self
                }
                fn take(self, n: usize) -> crate::iter::Take<Self> {
                    crate::iter::Take { inner: self }
                }
            }

            impl<I: Iterator> Iterator for &mut I {
                type Item = I::Item;
                fn next(&mut self) -> Option<I::Item> {
                    (**self).next()
                }
            }
        }
        pub(crate) mod collect {
            pub trait IntoIterator {
                type Item;
            }
        }
    }

    pub use self::sources::*;
    pub(crate) mod sources {
        use super::Iterator;
        use crate::option::Option::{self, *};
        pub struct Repeat<A> {
            element: A,
        }

        pub fn repeat<T>(elt: T) -> Repeat<T> {
            Repeat { element: elt }
        }

        impl<A> Iterator for Repeat<A> {
            type Item = A;

            fn next(&mut self) -> Option<A> {
                None
            }
        }
    }

    pub use self::adapters::*;
    pub(crate) mod adapters {
        use super::Iterator;
        use crate::option::Option::{self, *};
        pub struct Take<I> { pub(crate) inner: I }
        impl<I> Iterator for Take<I> where I: Iterator {
            type Item = <I as Iterator>::Item;
            fn next(&mut self) -> Option<<I as Iterator>::Item> {
                None
            }
        }
    }
}

pub mod option {
    pub enum Option<T> { None, Some(T)}
}

pub mod prelude {
    pub use crate::{convert::From, iter::{IntoIterator, Iterator}, option::Option::{self, *}, default::Default};
}
#[prelude_import]
pub use prelude::*;
"#;

    pub fn core(&self) -> Option<Crate> {
        self.find_crate("core")
    }

    pub(crate) fn core_convert_From(&self) -> Option<Trait> {
        self.find_trait("core:convert:From")
    }

    pub(crate) fn core_option_Option(&self) -> Option<Enum> {
        self.find_enum("core:option:Option")
    }

    pub fn core_default_Default(&self) -> Option<Trait> {
        self.find_trait("core:default:Default")
    }

    pub fn core_iter_Iterator(&self) -> Option<Trait> {
        self.find_trait("core:iter:traits:iterator:Iterator")
    }

    pub fn core_iter(&self) -> Option<Module> {
        self.find_module("core:iter")
    }

    fn find_trait(&self, path: &str) -> Option<Trait> {
        match self.find_def(path)? {
            hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it),
            _ => None,
        }
    }

    fn find_enum(&self, path: &str) -> Option<Enum> {
        match self.find_def(path)? {
            hir::ScopeDef::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(it))) => Some(it),
            _ => None,
        }
    }

    fn find_module(&self, path: &str) -> Option<Module> {
        match self.find_def(path)? {
            hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(it)) => Some(it),
            _ => None,
        }
    }

    fn find_crate(&self, name: &str) -> Option<Crate> {
        let krate = self.1?;
        let db = self.0.db;
        let res =
            krate.dependencies(db).into_iter().find(|dep| dep.name.to_string() == name)?.krate;
        Some(res)
    }

    fn find_def(&self, path: &str) -> Option<ScopeDef> {
        let db = self.0.db;
        let mut path = path.split(':');
        let trait_ = path.next_back()?;
        let std_crate = path.next()?;
        let std_crate = self.find_crate(std_crate)?;
        let mut module = std_crate.root_module(db);
        for segment in path {
            module = module.children(db).find_map(|child| {
                let name = child.name(db)?;
                if name.to_string() == segment {
                    Some(child)
                } else {
                    None
                }
            })?;
        }
        let def =
            module.scope(db, None).into_iter().find(|(name, _def)| name.to_string() == trait_)?.1;
        Some(def)
    }
}

pub(crate) fn next_prev() -> impl Iterator<Item = Direction> {
    [Direction::Next, Direction::Prev].iter().copied()
}
<commit_msg>add suggestion ..Default::default() for remaining struct fields in a constructor #6492<commit_after>//! Assorted functions shared by several assists.
pub(crate) mod insert_use;
pub(crate) mod import_assets;

use std::ops;

use hir::{Crate, Enum, HasSource, Module, ScopeDef, Semantics, Trait};
use ide_db::RootDatabase;
use itertools::Itertools;
use syntax::{
    ast::edit::AstNodeEdit,
    ast::NameOwner,
    ast::{self, edit, make, ArgListOwner},
    AstNode, Direction,
    SyntaxKind::*,
    SyntaxNode, TextSize, T,
};

use crate::{
    assist_config::SnippetCap,
    ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams},
};

pub use insert_use::MergeBehaviour;
pub(crate) use insert_use::{insert_use, ImportScope};

pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path {
    let mut segments = Vec::new();
    let mut is_abs = false;
    match path.kind {
        hir::PathKind::Plain => {}
        hir::PathKind::Super(0) => segments.push(make::path_segment_self()),
        hir::PathKind::Super(n) => segments.extend((0..n).map(|_| make::path_segment_super())),
        hir::PathKind::DollarCrate(_) | hir::PathKind::Crate => {
            segments.push(make::path_segment_crate())
        }
        hir::PathKind::Abs => is_abs = true,
    }

    segments.extend(
        path.segments
            .iter()
            .map(|segment| make::path_segment(make::name_ref(&segment.to_string()))),
    );
    make::path_from_segments(segments, is_abs)
}

pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr {
    extract_trivial_expression(&block)
        .filter(|expr| !expr.syntax().text().contains_char('\n'))
        .unwrap_or_else(|| block.into())
}

pub fn extract_trivial_expression(block: &ast::BlockExpr) -> Option<ast::Expr> {
    let has_anything_else = |thing: &SyntaxNode| -> bool {
        let mut non_trivial_children =
            block.syntax().children_with_tokens().filter(|it| match it.kind() {
                WHITESPACE | T!['{'] | T!['}'] => false,
                _ => it.as_node() != Some(thing),
            });
        non_trivial_children.next().is_some()
    };

    if let Some(expr) = block.expr() {
        if has_anything_else(expr.syntax()) {
            return None;
        }
        return Some(expr);
    }
    // Unwrap `{ continue; }`
    let (stmt,) = block.statements().next_tuple()?;
    if let ast::Stmt::ExprStmt(expr_stmt) = stmt {
        if has_anything_else(expr_stmt.syntax()) {
            return None;
        }
        let expr = expr_stmt.expr()?;
        match expr.syntax().kind() {
            CONTINUE_EXPR | BREAK_EXPR | RETURN_EXPR => return Some(expr),
            _ => (),
        }
    }
    None
}

#[derive(Copy, Clone, PartialEq)]
pub enum DefaultMethods {
    Only,
    No,
}

pub fn filter_assoc_items(
    db: &RootDatabase,
    items: &[hir::AssocItem],
    default_methods: DefaultMethods,
) -> Vec<ast::AssocItem> {
    fn has_def_name(item: &ast::AssocItem) -> bool {
        match item {
            ast::AssocItem::Fn(def) => def.name(),
            ast::AssocItem::TypeAlias(def) => def.name(),
            ast::AssocItem::Const(def) => def.name(),
            ast::AssocItem::MacroCall(_) => None,
        }
        .is_some()
    };

    items
        .iter()
        .map(|i| match i {
            hir::AssocItem::Function(i) => ast::AssocItem::Fn(i.source(db).value),
            hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(i.source(db).value),
            hir::AssocItem::Const(i) => ast::AssocItem::Const(i.source(db).value),
        })
        .filter(has_def_name)
        .filter(|it| match it {
            ast::AssocItem::Fn(def) => matches!(
                (default_methods, def.body()),
                (DefaultMethods::Only, Some(_)) | (DefaultMethods::No, None)
            ),
            _ => default_methods == DefaultMethods::No,
        })
        .collect::<Vec<_>>()
}

pub fn add_trait_assoc_items_to_impl(
    sema: &hir::Semantics<ide_db::RootDatabase>,
    items: Vec<ast::AssocItem>,
    trait_: hir::Trait,
    impl_def: ast::Impl,
    target_scope: hir::SemanticsScope,
) -> (ast::Impl, ast::AssocItem) {
    let impl_item_list = impl_def.assoc_item_list().unwrap_or_else(make::assoc_item_list);

    let n_existing_items = impl_item_list.assoc_items().count();
    let source_scope = sema.scope_for_def(trait_);
    let ast_transform = QualifyPaths::new(&target_scope, &source_scope)
        .or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_def.clone()));

    let items = items
        .into_iter()
        .map(|it| ast_transform::apply(&*ast_transform, it))
        .map(|it| match it {
            ast::AssocItem::Fn(def) => ast::AssocItem::Fn(add_body(def)),
            ast::AssocItem::TypeAlias(def) => ast::AssocItem::TypeAlias(def.remove_bounds()),
            _ => it,
        })
        .map(|it| edit::remove_attrs_and_docs(&it));

    let new_impl_item_list = impl_item_list.append_items(items);
    let new_impl_def = impl_def.with_assoc_item_list(new_impl_item_list);
    let first_new_item =
        new_impl_def.assoc_item_list().unwrap().assoc_items().nth(n_existing_items).unwrap();
    return (new_impl_def, first_new_item);

    fn add_body(fn_def: ast::Fn) -> ast::Fn {
        match fn_def.body() {
            Some(_) => fn_def,
            None => {
                let body =
                    make::block_expr(None, Some(make::expr_todo())).indent(edit::IndentLevel(1));
                fn_def.with_body(body)
            }
        }
    }
}

#[derive(Clone, Copy, Debug)]
pub(crate) enum Cursor<'a> {
    Replace(&'a SyntaxNode),
    Before(&'a SyntaxNode),
}

impl<'a> Cursor<'a> {
    fn node(self) -> &'a SyntaxNode {
        match self {
            Cursor::Replace(node) | Cursor::Before(node) => node,
        }
    }
}

pub(crate) fn render_snippet(_cap: SnippetCap, node: &SyntaxNode, cursor: Cursor) -> String {
    assert!(cursor.node().ancestors().any(|it| it == *node));
    let range = cursor.node().text_range() - node.text_range().start();
    let range: ops::Range<usize> = range.into();

    let mut placeholder = cursor.node().to_string();
    escape(&mut placeholder);
    let tab_stop = match cursor {
        Cursor::Replace(placeholder) => format!("${{0:{}}}", placeholder),
        Cursor::Before(placeholder) => format!("$0{}", placeholder),
    };

    let mut buf = node.to_string();
    buf.replace_range(range, &tab_stop);
    return buf;

    fn escape(buf: &mut String) {
        stdx::replace(buf, '{', r"\{");
        stdx::replace(buf, '}', r"\}");
        stdx::replace(buf, '$', r"\$");
    }
}

pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize {
    node.children_with_tokens()
        .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
        .map(|it| it.text_range().start())
        .unwrap_or_else(|| node.text_range().start())
}

pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr {
    if let Some(expr) = invert_special_case(&expr) {
        return expr;
    }
    make::expr_prefix(T![!], expr)
}

fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
    match expr {
        ast::Expr::BinExpr(bin) => match bin.op_kind()? {
            ast::BinOp::NegatedEqualityTest => bin.replace_op(T![==]).map(|it| it.into()),
            ast::BinOp::EqualityTest => bin.replace_op(T![!=]).map(|it| it.into()),
            _ => None,
        },
        ast::Expr::MethodCallExpr(mce) => {
            let receiver = mce.receiver()?;
            let method = mce.name_ref()?;
            let arg_list = mce.arg_list()?;

            let method = match method.text().as_str() {
                "is_some" => "is_none",
                "is_none" => "is_some",
                "is_ok" => "is_err",
                "is_err" => "is_ok",
                _ => return None,
            };
            Some(make::expr_method_call(receiver, method, arg_list))
        }
        ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::PrefixOp::Not => pe.expr(),
        // FIXME:
        // ast::Expr::Literal(true | false )
        _ => None,
    }
}

/// Helps with finding well-know things inside the standard library. This is
/// somewhat similar to the known paths infra inside hir, but it different; We
/// want to make sure that IDE specific paths don't become interesting inside
/// the compiler itself as well.
pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Option<Crate>);

#[allow(non_snake_case)]
impl FamousDefs<'_, '_> {
    pub const FIXTURE: &'static str = r#"//- /libcore.rs crate:core
pub mod convert {
    pub trait From<T> {
        fn from(t: T) -> Self;
    }
}

pub mod default {
    pub trait Default {
       fn default() -> Self;
    }
}

pub mod iter {
    pub use self::traits::{collect::IntoIterator, iterator::Iterator};
    mod traits {
        pub(crate) mod iterator {
            use crate::option::Option;
            pub trait Iterator {
                type Item;
                fn next(&mut self) -> Option<Self::Item>;
                fn by_ref(&mut self) -> &mut Self {
                    self
                }
                fn take(self, n: usize) -> crate::iter::Take<Self> {
                    crate::iter::Take { inner: self }
                }
            }

            impl<I: Iterator> Iterator for &mut I {
                type Item = I::Item;
                fn next(&mut self) -> Option<I::Item> {
                    (**self).next()
                }
            }
        }
        pub(crate) mod collect {
            pub trait IntoIterator {
                type Item;
            }
        }
    }

    pub use self::sources::*;
    pub(crate) mod sources {
        use super::Iterator;
        use crate::option::Option::{self, *};
        pub struct Repeat<A> {
            element: A,
        }

        pub fn repeat<T>(elt: T) -> Repeat<T> {
            Repeat { element: elt }
        }

        impl<A> Iterator for Repeat<A> {
            type Item = A;

            fn next(&mut self) -> Option<A> {
                None
            }
        }
    }

    pub use self::adapters::*;
    pub(crate) mod adapters {
        use super::Iterator;
        use crate::option::Option::{self, *};
        pub struct Take<I> { pub(crate) inner: I }
        impl<I> Iterator for Take<I> where I: Iterator {
            type Item = <I as Iterator>::Item;
            fn next(&mut self) -> Option<<I as Iterator>::Item> {
                None
            }
        }
    }
}

pub mod option {
    pub enum Option<T> { None, Some(T)}
}

pub mod prelude {
    pub use crate::{convert::From, iter::{IntoIterator, Iterator}, option::Option::{self, *}, default::Default};
}
#[prelude_import]
pub use prelude::*;
"#;

    pub fn core(&self) -> Option<Crate> {
        self.find_crate("core")
    }

    pub(crate) fn core_convert_From(&self) -> Option<Trait> {
        self.find_trait("core:convert:From")
    }

    pub(crate) fn core_option_Option(&self) -> Option<Enum> {
        self.find_enum("core:option:Option")
    }

    pub fn core_default_Default(&self) -> Option<Trait> {
        self.find_trait("core:default:Default")
    }

    pub fn core_iter_Iterator(&self) -> Option<Trait> {
        self.find_trait("core:iter:traits:iterator:Iterator")
    }

    pub fn core_iter(&self) -> Option<Module> {
        self.find_module("core:iter")
    }

    fn find_trait(&self, path: &str) -> Option<Trait> {
        match self.find_def(path)? {
            hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it),
            _ => None,
        }
    }

    fn find_enum(&self, path: &str) -> Option<Enum> {
        match self.find_def(path)? {
            hir::ScopeDef::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(it))) => Some(it),
            _ => None,
        }
    }

    fn find_module(&self, path: &str) -> Option<Module> {
        match self.find_def(path)? {
            hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(it)) => Some(it),
            _ => None,
        }
    }

    fn find_crate(&self, name: &str) -> Option<Crate> {
        let krate = self.1?;
        let db = self.0.db;
        let res =
            krate.dependencies(db).into_iter().find(|dep| dep.name.to_string() == name)?.krate;
        Some(res)
    }

    fn find_def(&self, path: &str) -> Option<ScopeDef> {
        let db = self.0.db;
        let mut path = path.split(':');
        let trait_ = path.next_back()?;
        let std_crate = path.next()?;
        let std_crate = self.find_crate(std_crate)?;
        let mut module = std_crate.root_module(db);
        for segment in path {
            module = module.children(db).find_map(|child| {
                let name = child.name(db)?;
                if name.to_string() == segment {
                    Some(child)
                } else {
                    None
                }
            })?;
        }
        let def =
            module.scope(db, None).into_iter().find(|(name, _def)| name.to_string() == trait_)?.1;
        Some(def)
    }
}

pub(crate) fn next_prev() -> impl Iterator<Item = Direction> {
    [Direction::Next, Direction::Prev].iter().copied()
}
<|endoftext|>


<commit_before>extern crate puppetfile;
extern crate http;
extern crate serialize;
extern crate semver;

use std::io::File;
use std::os;
use std::str;
use std::sync::Future;
use semver::version::{Version, ParseError};
use puppetfile::Puppetfile;

fn main() {
    let args = os::args();
    let file_raw_bytes = File::open(&Path::new(args[1].as_slice())).read_to_end().unwrap();
    let puppetfile_contents = str::from_utf8(file_raw_bytes.as_slice()).unwrap();
    let puppetfile = Puppetfile::parse(puppetfile_contents).unwrap();

    let modules = puppetfile.modules.clone();
    let mut version_ftrs: Vec<Future<(String, Result<Version, ParseError>)>> = modules.move_iter().filter(
        |m| m.user_name_pair().is_some()
    ).map(|m| {
        let forge_url = puppetfile.forge.clone();
        Future::spawn(proc() {
            (m.name.clone(), m.forge_version(forge_url))
        })
    }).collect();

    let versions: Vec<(String, Version)> = version_ftrs.mut_iter().map(
        |ftr| ftr.get()
    ).filter_map(
        |tpl| match tpl {
            (name, Ok(version)) => Some((name, version)),
            (_, Err(_)) => None
        }
    ).collect();

    let mut modules_to_check = puppetfile.modules.iter().filter(
        |m| m.user_name_pair().is_some() && m.version().is_some()
    );

    for module in modules_to_check {
        for &(ref name, ref version) in versions.iter() {
            if module.name == *name && module.version().is_some() &&
                    module.version().unwrap() != *version {
                println!("{}: {} != {}", module.name, module.version().unwrap(), version)
            }
        }
    }
}
<commit_msg>default to path Puppetfile if none is given as argument<commit_after>extern crate puppetfile;
extern crate http;
extern crate serialize;
extern crate semver;

use std::io::File;
use std::os;
use std::str;
use std::sync::Future;
use semver::version::{Version, ParseError};
use puppetfile::Puppetfile;

fn main() {
    let args = os::args();
    let path = if args.len() == 1 {
        Path::new("Puppetfile")
    } else {
        Path::new(args[1].as_slice())
    };
    let file_raw_bytes = match File::open(&path).read_to_end() {
        Ok(bytes)  => bytes,
        Err(error) => fail!("{}", error)
    };
    let puppetfile_contents = str::from_utf8(file_raw_bytes.as_slice()).unwrap();
    let puppetfile = Puppetfile::parse(puppetfile_contents).unwrap();

    let modules = puppetfile.modules.clone();
    let mut version_ftrs: Vec<Future<(String, Result<Version, ParseError>)>> = modules.move_iter().filter(
        |m| m.user_name_pair().is_some()
    ).map(|m| {
        let forge_url = puppetfile.forge.clone();
        Future::spawn(proc() {
            (m.name.clone(), m.forge_version(forge_url))
        })
    }).collect();

    let versions: Vec<(String, Version)> = version_ftrs.mut_iter().map(
        |ftr| ftr.get()
    ).filter_map(
        |tpl| match tpl {
            (name, Ok(version)) => Some((name, version)),
            (_, Err(_)) => None
        }
    ).collect();

    let mut modules_to_check = puppetfile.modules.iter().filter(
        |m| m.user_name_pair().is_some() && m.version().is_some()
    );

    for module in modules_to_check {
        for &(ref name, ref version) in versions.iter() {
            if module.name == *name && module.version().is_some() &&
                    module.version().unwrap() != *version {
                println!("{}: {} != {}", module.name, module.version().unwrap(), version)
            }
        }
    }
}
<|endoftext|>


<commit_before>//! `cargo rm`
#![warn(
    missing_docs,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unsafe_code,
    unstable_features,
    unused_import_braces,
    unused_qualifications
)]

#[macro_use]
extern crate error_chain;

use cargo_edit::{manifest_from_pkgid, Manifest};
use std::borrow::Cow;
use std::io::Write;
use std::path::PathBuf;
use std::process;
use structopt::StructOpt;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

mod errors {
    error_chain! {
        links {
            CargoEditLib(::cargo_edit::Error, ::cargo_edit::ErrorKind);
        }
        foreign_links {
            Io(::std::io::Error);
        }
    }
}
use crate::errors::*;

#[derive(Debug, StructOpt)]
#[structopt(bin_name = "cargo")]
enum Command {
    /// Remove a dependency from a Cargo.toml manifest file.
    #[structopt(name = "rm")]
    Rm(Args),
}

#[derive(Debug, StructOpt)]
struct Args {
    /// Crates to be removed.
    #[structopt(name = "crates", required = true)]
    crates: Vec<String>,

    /// Remove crate as development dependency.
    #[structopt(long = "dev", short = "D", conflicts_with = "build")]
    dev: bool,

    /// Remove crate as build dependency.
    #[structopt(long = "build", short = "B", conflicts_with = "dev")]
    build: bool,

    /// Path to the manifest to remove a dependency from.
    #[structopt(long = "manifest-path", value_name = "path", conflicts_with = "pkgid")]
    manifest_path: Option<PathBuf>,

    /// Package id of the crate to add this dependency to.
    #[structopt(
        long = "package",
        short = "p",
        value_name = "pkgid",
        conflicts_with = "path"
    )]
    pkgid: Option<String>,

    /// Do not print any output in case of success.
    #[structopt(long = "quiet", short = "q")]
    quiet: bool,
}

impl Args {
    /// Get depenency section
    pub fn get_section(&self) -> &'static str {
        if self.dev {
            "dev-dependencies"
        } else if self.build {
            "build-dependencies"
        } else {
            "dependencies"
        }
    }
}

fn print_msg(name: &str, section: &str) -> Result<()> {
    let colorchoice = if atty::is(atty::Stream::Stdout) {
        ColorChoice::Auto
    } else {
        ColorChoice::Never
    };
    let mut output = StandardStream::stdout(colorchoice);
    output.set_color(ColorSpec::new().set_fg(Some(Color::Green)).set_bold(true))?;
    write!(output, "{:>12}", "Removing")?;
    output.reset()?;
    writeln!(output, " {} from {}", name, section)?;
    Ok(())
}

fn handle_rm(args: &Args) -> Result<()> {
    let manifest_path = if let Some(ref pkgid) = args.pkgid {
        let pkg = manifest_from_pkgid(pkgid)?;
        Cow::Owned(Some(pkg.manifest_path))
    } else {
        Cow::Borrowed(&args.manifest_path)
    };
    let mut manifest = Manifest::open(&manifest_path)?;
    let deps = &args.crates;

    deps.iter()
        .map(|dep| {
            if !args.quiet {
                print_msg(&dep, args.get_section())?;
            }
            manifest
                .remove_from_table(args.get_section(), dep)
                .map_err(Into::into)
        })
        .collect::<Result<Vec<_>>>()
        .map_err(|err| {
            eprintln!("Could not edit `Cargo.toml`.\n\nERROR: {}", err);
            err
        })?;

    let mut file = Manifest::find_file(&manifest_path)?;
    manifest.write_to_file(&mut file)?;

    Ok(())
}

fn main() {
    let args: Command = Command::from_args();
    let Command::Rm(args) = args;

    if let Err(err) = handle_rm(&args) {
        eprintln!("Command failed due to unhandled error: {}\n", err);

        for e in err.iter().skip(1) {
            eprintln!("Caused by: {}", e);
        }

        if let Some(backtrace) = err.backtrace() {
            eprintln!("Backtrace: {:?}", backtrace);
        }

        process::exit(1);
    }
}
<commit_msg>Fix pkgid option descrion for `rm` command (#405)<commit_after>//! `cargo rm`
#![warn(
    missing_docs,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unsafe_code,
    unstable_features,
    unused_import_braces,
    unused_qualifications
)]

#[macro_use]
extern crate error_chain;

use cargo_edit::{manifest_from_pkgid, Manifest};
use std::borrow::Cow;
use std::io::Write;
use std::path::PathBuf;
use std::process;
use structopt::StructOpt;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

mod errors {
    error_chain! {
        links {
            CargoEditLib(::cargo_edit::Error, ::cargo_edit::ErrorKind);
        }
        foreign_links {
            Io(::std::io::Error);
        }
    }
}
use crate::errors::*;

#[derive(Debug, StructOpt)]
#[structopt(bin_name = "cargo")]
enum Command {
    /// Remove a dependency from a Cargo.toml manifest file.
    #[structopt(name = "rm")]
    Rm(Args),
}

#[derive(Debug, StructOpt)]
struct Args {
    /// Crates to be removed.
    #[structopt(name = "crates", required = true)]
    crates: Vec<String>,

    /// Remove crate as development dependency.
    #[structopt(long = "dev", short = "D", conflicts_with = "build")]
    dev: bool,

    /// Remove crate as build dependency.
    #[structopt(long = "build", short = "B", conflicts_with = "dev")]
    build: bool,

    /// Path to the manifest to remove a dependency from.
    #[structopt(long = "manifest-path", value_name = "path", conflicts_with = "pkgid")]
    manifest_path: Option<PathBuf>,

    /// Package id of the crate to remove this dependency from.
    #[structopt(
        long = "package",
        short = "p",
        value_name = "pkgid",
        conflicts_with = "path"
    )]
    pkgid: Option<String>,

    /// Do not print any output in case of success.
    #[structopt(long = "quiet", short = "q")]
    quiet: bool,
}

impl Args {
    /// Get depenency section
    pub fn get_section(&self) -> &'static str {
        if self.dev {
            "dev-dependencies"
        } else if self.build {
            "build-dependencies"
        } else {
            "dependencies"
        }
    }
}

fn print_msg(name: &str, section: &str) -> Result<()> {
    let colorchoice = if atty::is(atty::Stream::Stdout) {
        ColorChoice::Auto
    } else {
        ColorChoice::Never
    };
    let mut output = StandardStream::stdout(colorchoice);
    output.set_color(ColorSpec::new().set_fg(Some(Color::Green)).set_bold(true))?;
    write!(output, "{:>12}", "Removing")?;
    output.reset()?;
    writeln!(output, " {} from {}", name, section)?;
    Ok(())
}

fn handle_rm(args: &Args) -> Result<()> {
    let manifest_path = if let Some(ref pkgid) = args.pkgid {
        let pkg = manifest_from_pkgid(pkgid)?;
        Cow::Owned(Some(pkg.manifest_path))
    } else {
        Cow::Borrowed(&args.manifest_path)
    };
    let mut manifest = Manifest::open(&manifest_path)?;
    let deps = &args.crates;

    deps.iter()
        .map(|dep| {
            if !args.quiet {
                print_msg(&dep, args.get_section())?;
            }
            manifest
                .remove_from_table(args.get_section(), dep)
                .map_err(Into::into)
        })
        .collect::<Result<Vec<_>>>()
        .map_err(|err| {
            eprintln!("Could not edit `Cargo.toml`.\n\nERROR: {}", err);
            err
        })?;

    let mut file = Manifest::find_file(&manifest_path)?;
    manifest.write_to_file(&mut file)?;

    Ok(())
}

fn main() {
    let args: Command = Command::from_args();
    let Command::Rm(args) = args;

    if let Err(err) = handle_rm(&args) {
        eprintln!("Command failed due to unhandled error: {}\n", err);

        for e in err.iter().skip(1) {
            eprintln!("Caused by: {}", e);
        }

        if let Some(backtrace) = err.backtrace() {
            eprintln!("Backtrace: {:?}", backtrace);
        }

        process::exit(1);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.
#![feature(path_ext)]
#![feature(rustc_private)]
#![cfg(not(test))]
#![feature(result_expect)]

#[macro_use]
extern crate log;
extern crate rustfmt;
extern crate toml;

use rustfmt::{WriteMode, run};
use rustfmt::config::Config;

use std::env;
use std::fs::{File, PathExt};
use std::io::{self, Read};
use std::path::PathBuf;
use std::str::FromStr;

// Try to find a project file in the current directory and its parents.
fn lookup_project_file() -> io::Result<PathBuf> {
    let mut current = try!(env::current_dir());
    loop {
        let config_file = current.join("rustfmt.toml");
        if config_file.exists() {
            return Ok(config_file);
        } else {
            current = match current.parent() {
                // if the current directory has no parent, we're done searching
                None => return Err(io::Error::new(io::ErrorKind::NotFound, "config not found")),
                Some(path) => path.to_path_buf(),
            };
        }
    }
}

// Try to find a project file. If it's found, read it.
fn lookup_and_read_project_file() -> io::Result<(PathBuf, String)> {
    let path = try!(lookup_project_file());
    let mut file = try!(File::open(&path));
    let mut toml = String::new();
    try!(file.read_to_string(&mut toml));
    Ok((path, toml))
}

fn main() {
    let (args, write_mode) = determine_params(std::env::args());

    let config = match lookup_and_read_project_file() {
        Ok((path, toml)) => {
            println!("Project config file: {}", path.display());
            Config::from_toml(&toml)
        }
        Err(_) => Default::default(),
    };

    run(args, write_mode, Box::new(config));
    std::process::exit(0);
}

fn usage<S: Into<String>>(reason: S) {
    print!("{}\n\r usage: rustfmt [-h Help] [--write-mode=[true/false]] <file_name>", reason.into());
    std::process::exit(1);
}

fn determine_params<I>(args: I) -> (Vec<String>, WriteMode)
    where I: Iterator<Item = String>
{
    let arg_prefix = "-";
    let write_mode_prefix = "--write-mode=";
    let help_mode = "-h";
    let long_help_mode = "--help";
    let mut write_mode = WriteMode::Replace;

    // The NewFile option currently isn't supported because it requires another
    // parameter, but it can be added later.
    let args:Vec<String> = args.filter(|arg| {
        if arg.starts_with(write_mode_prefix) {
            write_mode = FromStr::from_str(&arg[write_mode_prefix.len()..]).expect("Unrecognized write mode");
            false
        } else if arg.starts_with(help_mode) || arg.starts_with(long_help_mode) {
            usage("");
            false
        } else if arg.starts_with(arg_prefix) {
            usage("Invalid argument");
            false
        } else {
            true
        }
    }).collect();
    if args.len() < 2 {
        usage("Please provide a file to be formatted");
    }

    (args, write_mode)
}
<commit_msg>Only exit after running all destructors and flushing stdout<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.
#![feature(path_ext)]
#![feature(rustc_private)]
#![cfg(not(test))]

#[macro_use]
extern crate log;
extern crate rustfmt;
extern crate toml;

use rustfmt::{WriteMode, run};
use rustfmt::config::Config;

use std::env;
use std::fs::{File, PathExt};
use std::io::{self, Read};
use std::path::PathBuf;
use std::str::FromStr;

// Try to find a project file in the current directory and its parents.
fn lookup_project_file() -> io::Result<PathBuf> {
    let mut current = try!(env::current_dir());
    loop {
        let config_file = current.join("rustfmt.toml");
        if config_file.exists() {
            return Ok(config_file);
        } else {
            current = match current.parent() {
                // if the current directory has no parent, we're done searching
                None => return Err(io::Error::new(io::ErrorKind::NotFound, "config not found")),
                Some(path) => path.to_path_buf(),
            };
        }
    }
}

// Try to find a project file. If it's found, read it.
fn lookup_and_read_project_file() -> io::Result<(PathBuf, String)> {
    let path = try!(lookup_project_file());
    let mut file = try!(File::open(&path));
    let mut toml = String::new();
    try!(file.read_to_string(&mut toml));
    Ok((path, toml))
}

fn execute() -> i32 {
    let (args, write_mode) = match determine_params(std::env::args()) {
        Some((args, write_mode)) => (args, write_mode),
        None => return 1,
    };

    let config = match lookup_and_read_project_file() {
        Ok((path, toml)) => {
            println!("Project config file: {}", path.display());
            Config::from_toml(&toml)
        }
        Err(_) => Default::default(),
    };

    run(args, write_mode, Box::new(config));
    0
}

fn main() {
    use std::io::Write;
    let exit_code = execute();
    // Make sure standard output is flushed before we exit
    std::io::stdout().flush().unwrap();
    // Exit with given exit code.
    //
    // NOTE: This immediately terminates the process without doing any cleanup,
    // so make sure to finish all necessary cleanup before this is called.
    std::process::exit(exit_code);
}

fn print_usage<S: Into<String>>(reason: S) {
    println!("{}\n\r usage: rustfmt [-h Help] [--write-mode=[true/false]] <file_name>", reason.into());
}

fn determine_params<I>(args: I) -> Option<(Vec<String>, WriteMode)>
    where I: Iterator<Item = String>
{
    let arg_prefix = "-";
    let write_mode_prefix = "--write-mode=";
    let help_mode = "-h";
    let long_help_mode = "--help";
    let mut write_mode = WriteMode::Replace;
    let args: Vec<String> = args.collect();

    // The NewFile option currently isn't supported because it requires another
    // parameter, but it can be added later.
    if args.iter().any(|arg| {
        if arg.starts_with(write_mode_prefix) {
            write_mode = match FromStr::from_str(&arg[write_mode_prefix.len()..]) {
                Ok(mode) => mode,
                Err(_) => {
                    print_usage("Unrecognized write mode");
                    return true;
                }
            };
            false
        } else if arg.starts_with(help_mode) || arg.starts_with(long_help_mode) {
            print_usage("");
            true
        } else if arg.starts_with(arg_prefix) {
            print_usage("Invalid argument");
            true
        } else {
            false
        }
    }) {
        return None;
    }

    if args.len() < 2 {
        print_usage("Please provide a file to be formatted");
        return None;
    }

    Some((args, write_mode))
}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

//! Bstream module.
//! This is a blocking stream designed to block on read/write until

use std::result::Result;
use std::net::TcpStream;
use std::io::{Read, Write, Error};

use super::readbuffer::ReadBuffer;

/// Represents the result of attempting a read on the underlying file descriptor
pub type ReadResult = Result<Vec<u8>, Error>;

/// Represents the result attempting a write on the underlying fild descriptor
pub type WriteResult = Result<(), Error>;

/// States the current stream can be in
#[derive(PartialEq, Clone)]
enum ReadState {
    /// Currently reading the payload length
    PayloadLen,
    /// Currently reading the payload
    Payload
}

pub struct Bstream {
    /// Current state
    state: ReadState,
    /// Underlying std::net::TcpStream
    stream: TcpStream,
    /// Message buffer
    buffer: ReadBuffer
}

impl Bstream {

    /// Returns a new Bstream
    pub fn new(stream: TcpStream) -> Bstream {
        Bstream {
            state: ReadState::PayloadLen,
            stream: stream,
            buffer: ReadBuffer::new()
        }
    }

    /// Performs a blocking read and returns when a complete message
    /// has been returned, or an error has occured
    pub fn read(&mut self) -> ReadResult {
        loop {
            // Create a buffer for this specific read iteration
            let count = self.buffer.remaining();
            let mut buffer = Vec::<u8>::with_capacity(count as usize);
            unsafe { buffer.set_len(count as usize); }

            let result = self.stream.read(&mut buffer[..]);
            if result.is_err() {
                return Err(result.unwrap_err());
            }

            let num_read = result.unwrap();
            for x in 0..num_read {
                self.buffer.push(buffer[x]);
            }

            if self.buffer.remaining() == 0 {
                if self.state == ReadState::PayloadLen {
                    self.buffer.calc_payload_len();
                    let p_len = self.buffer.payload_len();
                    self.buffer.set_capacity(p_len);
                    self.state = ReadState::Payload;
                } else { // Payload completely read
                    self.buffer.reset();
                    self.state = ReadState::PayloadLen;
                    break;
                }
            }
        }

        let mut buffer = self.buffer.drain_queue();
        // This should always be .len() of 1
        // if it isn't - we're doing some bad stuff in here
        if buffer.len() != 1 {
            panic!("Error - Bstream.read() - Internal buffer was not equal to one...?")
        }

        match buffer.pop() {
            Some(buf) => Ok(buf),
            None => unimplemented!()
        }
    }

    /// Performs a blocking write operation and returns the complete buffer has
    /// been written, or an error has occured
    pub fn write(&mut self, buffer: &Vec<u8>) -> WriteResult {
        match self.stream.write_all(&buffer[..]) {
            Ok(()) => {
                let _ = self.stream.flush();
                Ok(())
            }
            Err(e) => Err(e)
        }
    }
}
<commit_msg>Added clone to Bstream<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

//! Bstream module.
//! This is a blocking stream designed to block on read/write until

use std::result::Result;
use std::net::TcpStream;
use std::io::{Read, Write, Error};

use super::readbuffer::ReadBuffer;

/// Represents the result of attempting a read on the underlying file descriptor
pub type ReadResult = Result<Vec<u8>, Error>;

/// Represents the result attempting a write on the underlying fild descriptor
pub type WriteResult = Result<(), Error>;

/// States the current stream can be in
#[derive(PartialEq, Clone)]
enum ReadState {
    /// Currently reading the payload length
    PayloadLen,
    /// Currently reading the payload
    Payload
}

pub struct Bstream {
    /// Current state
    state: ReadState,
    /// Underlying std::net::TcpStream
    stream: TcpStream,
    /// Message buffer
    buffer: ReadBuffer
}

impl Bstream {

    /// Returns a new Bstream
    pub fn new(stream: TcpStream) -> Bstream {
        Bstream {
            state: ReadState::PayloadLen,
            stream: stream,
            buffer: ReadBuffer::new()
        }
    }

    /// Performs a blocking read and returns when a complete message
    /// has been returned, or an error has occured
    pub fn read(&mut self) -> ReadResult {
        loop {
            // Create a buffer for this specific read iteration
            let count = self.buffer.remaining();
            let mut buffer = Vec::<u8>::with_capacity(count as usize);
            unsafe { buffer.set_len(count as usize); }

            let result = self.stream.read(&mut buffer[..]);
            if result.is_err() {
                return Err(result.unwrap_err());
            }

            let num_read = result.unwrap();
            for x in 0..num_read {
                self.buffer.push(buffer[x]);
            }

            if self.buffer.remaining() == 0 {
                if self.state == ReadState::PayloadLen {
                    self.buffer.calc_payload_len();
                    let p_len = self.buffer.payload_len();
                    self.buffer.set_capacity(p_len);
                    self.state = ReadState::Payload;
                } else { // Payload completely read
                    self.buffer.reset();
                    self.state = ReadState::PayloadLen;
                    break;
                }
            }
        }

        let mut buffer = self.buffer.drain_queue();
        // This should always be .len() of 1
        // if it isn't - we're doing some bad stuff in here
        if buffer.len() != 1 {
            panic!("Error - Bstream.read() - Internal buffer was not equal to one...?")
        }

        match buffer.pop() {
            Some(buf) => Ok(buf),
            None => unimplemented!()
        }
    }

    /// Performs a blocking write operation and returns the complete buffer has
    /// been written, or an error has occured
    pub fn write(&mut self, buffer: &Vec<u8>) -> WriteResult {
        match self.stream.write_all(&buffer[..]) {
            Ok(()) => {
                let _ = self.stream.flush();
                Ok(())
            }
            Err(e) => Err(e)
        }
    }
}

impl Clone for Bstream {
    fn clone(&self) -> Bstream {
        Bstream {
            state: self.state.clone(),
            stream: self.stream.try_clone().unwrap(),
            buffer: self.buffer.clone()
        }
    }
}
<|endoftext|>


<commit_before>use common::types::FnType;
use common::types::StructType;
use common::link::*;

use common::entity::FromEntity;
use common::entity::Entity;

use std::collections::HashMap;
use common::tree_id::*;

#[derive(Debug, Clone)]
pub struct Node {
    id: i32,
    path: TreeId,
    name: String,
    url: String,
    fn_type: FnType,
    links: Vec<Link>,
    nodes: Vec<Node>,
}

impl Node {
    fn push(&mut self, entity: &Entity) {
        match entity.struct_type {
            StructType::Link => {
                self.links.push(Link::from_entity(&entity));
            },
            StructType::Node => {
                self.nodes.push(Node::from_entity(&entity));
            }
        }
    }
}

impl FromEntity for Node {
    fn from_entity(entity: &Entity) -> Self {
        let clone = entity.clone();

        Node {
            id: clone.id,
            path: clone.tree_id,
            name: clone.name,
            url: clone.url,
            fn_type: clone.fn_type,
            links: Vec::new(),
            nodes: Vec::new()
        }
    }

    fn from_entities(entities: Vec<Entity>) -> Vec<Self> {
        let mut node_map: HashMap<String, Node> = HashMap::new();
        let mut node_dir: HashMap<i32, TreeId> = HashMap::new();
        let mut lower = usize::max_value();
        let mut pre_links: Vec<Entity> = Vec::new();

        for e in entities {
            let ref path = e.tree_id;
            if e.struct_type == StructType::Node {
                if level(path) < lower {
                    lower = level(path);
                }

                node_dir.insert(e.id, path.clone());
                node_map.insert(path.id(), Node::from_entity(&e));
            } else {
                pre_links.push(e.clone());
            }
        }

        for e in pre_links {
            let ref path = e.tree_id;
            let parent = match key(&path, level(&path) - 1) {
                Some(p) => p,
                None => panic!("{:?}", e),
            };

            if let Some(node) = node_map.get_mut(&parent) {
                node.push(&e);
            }
        }

        let mut roots = Vec::new();
        for (_, node) in node_map {
            push_node(&node_dir, &mut roots, lower, node);
        }

        roots
    }
}

fn push_node<'a>(dir: &HashMap<i32, TreeId>, roots: &mut Vec<Node>, search_level: usize, node: Node) {
    let path = match dir.get(&node.id) {
        Some(tree_id) => tree_id,
        None => panic!("{:?}", node)
    };

    if level(path) == search_level {
        roots.push(node.clone());
    } else {
        for root in roots {
            let parent_id = match key(path, search_level) {
                Some(id) => id,
                None => panic!("{:?}", path)
            };

            let root_key = match dir.get(&root.id) {
                Some(key) => key,
                None => panic!("{:?}", root)
            };

            if parent_id == root_key.id() {
                push_node(dir, &mut root.nodes, search_level + 1, node.clone());
                break;
            }
        }
    }
}
<commit_msg>node_map NEEDS to bo btreemap<commit_after>use common::types::FnType;
use common::types::StructType;
use common::link::*;

use common::entity::FromEntity;
use common::entity::Entity;

use std::collections::HashMap;
use std::collections::BTreeMap;
use common::tree_id::*;

#[derive(Debug, Clone)]
pub struct Node {
    id: i32,
    path: TreeId,
    name: String,
    url: String,
    fn_type: FnType,
    links: Vec<Link>,
    nodes: Vec<Node>,
}

impl Node {
    fn push(&mut self, entity: &Entity) {
        match entity.struct_type {
            StructType::Link => {
                self.links.push(Link::from_entity(&entity));
            },
            StructType::Node => {
                self.nodes.push(Node::from_entity(&entity));
            }
        }
    }
}

impl FromEntity for Node {
    fn from_entity(entity: &Entity) -> Self {
        let clone = entity.clone();

        Node {
            id: clone.id,
            path: clone.tree_id,
            name: clone.name,
            url: clone.url,
            fn_type: clone.fn_type,
            links: Vec::new(),
            nodes: Vec::new()
        }
    }

    fn from_entities(entities: Vec<Entity>) -> Vec<Self> {
        let mut node_map: BTreeMap<String, Node> = BTreeMap::new();
        let mut node_dir: HashMap<i32, TreeId> = HashMap::new();
        let mut lower = usize::max_value();
        let mut pre_links: Vec<Entity> = Vec::new();

        for e in entities {
            let ref path = e.tree_id;
            if e.struct_type == StructType::Node {
                if level(path) < lower {
                    lower = level(path);
                }

                node_dir.insert(e.id, path.clone());
                node_map.insert(path.id(), Node::from_entity(&e));
            } else {
                pre_links.push(e.clone());
            }
        }

        for e in pre_links {
            let ref path = e.tree_id;
            let parent = match key(&path, level(&path) - 1) {
                Some(p) => p,
                None => panic!("{:?}", e),
            };

            if let Some(node) = node_map.get_mut(&parent) {
                node.push(&e);
            }
        }

        let mut roots = Vec::new();
        for (_, node) in node_map {
            push_node(&node_dir, &mut roots, lower, node);
        }

        println!("{:?}\n", roots);
        roots
    }
}

fn push_node(dir: &HashMap<i32, TreeId>, roots: &mut Vec<Node>, search_level: usize, node: Node) {
    let path = match dir.get(&node.id) {
        Some(tree_id) => tree_id,
        None => panic!("{:?}", node)
    };

    if level(path) == search_level {
        roots.push(node);
    } else {
        for root in roots {
            let parent_id = match key(path, search_level) {
                Some(id) => id,
                None => panic!("{:?}", path)
            };

            let root_key = match dir.get(&root.id) {
                Some(key) => key,
                None => panic!("{:?}", root)
            };

            println!("{:?} - {:?}\n", parent_id, root_key.id());
            if parent_id == root_key.id() {
                push_node(dir, &mut root.nodes, search_level + 1, node);
                break;
            }
        }
    }
}
<|endoftext|>


<commit_before>use luminance::{Depth32F, Dim2, Flat, Framebuffer, Mode, RGBA32F, Tess, Texture, Uniform, Unit};
use luminance::pipeline::{Pipe, Pipeline, RenderCommand, ShadingCommand};
use luminance::tess::TessRender;
use std::ops::{Add, BitAnd, Mul, Sub};

pub use luminance::{Equation, Factor};

use color::ColorAlpha;
use resource::{Res, ResCache};
use shader::Program;

/// Simple texture that can be embedded into a compositing graph.
pub type TextureLayer<'a> = &'a ColorMap;

pub type ColorMap = Texture<Flat, Dim2, RGBA32F>;
pub type DepthMap = Texture<Flat, Dim2, Depth32F>;

/// Render layer used to host renders.
pub struct RenderLayer<'a> {
  render: Box<Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) + 'a>
}

impl<'a> RenderLayer<'a> {
  pub fn new<F>(render: F) -> Self where F: 'a + Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) {
    RenderLayer {
      render: Box::new(render)
    }
  }
}

/// Compositing node.
pub enum Node<'a> {
  /// A render node.
  ///
  /// Contains render layer.
  Render(RenderLayer<'a>),
  /// A texture node.
  ///
  /// Contains a single texture.
  Texture(TextureLayer<'a>),
  /// A single color.
  ///
  /// Keep in mind that such a node is great when you want to display a fullscreen colored quad but
  /// you shouldn’t use it for blending purpose. Adding color masking to your post-process is a
  /// better alternative and will avoid fillrate alteration.
  Color(ColorAlpha),
  /// Composite node.
  ///
  /// Composite nodes are used to blend two compositing nodes according to a given `Equation` and
  /// two blending `Factor`s for source and destination, respectively.
  Composite(Box<Node<'a>>, Box<Node<'a>>, ColorAlpha, Equation, Factor, Factor)
}

impl<'a> Node<'a> {
  /// Compose this node with another one.
  pub fn compose_with(self, other: Self, clear_color: ColorAlpha, eq: Equation, src_fct: Factor, dst_fct: Factor) -> Self {
    Node::Composite(Box::new(self), Box::new(other), clear_color, eq, src_fct, dst_fct)
  }
}

impl<'a> From<RenderLayer<'a>> for Node<'a> {
  fn from(layer: RenderLayer<'a>) -> Self {
    Node::Render(layer)
  }
}

impl<'a> From<TextureLayer<'a>> for Node<'a> {
  fn from(texture: TextureLayer<'a>) -> Self {
    Node::Texture(texture)
  }
}

impl<'a> From<ColorAlpha> for Node<'a> {
  fn from(color: ColorAlpha) -> Self {
    Node::Color(color)
  }
}

impl<'a> Add for Node<'a> {
  type Output = Self;

  fn add(self, rhs: Self) -> Self {
    self.compose_with(rhs, ColorAlpha::new(0., 0., 0., 0.), Equation::Additive, Factor::One, Factor::One)
  }
}

impl<'a> Sub for Node<'a> {
  type Output = Self;

  fn sub(self, rhs: Self) -> Self {
    self.compose_with(rhs, ColorAlpha::new(0., 0., 0., 0.), Equation::Subtract, Factor::One, Factor::One)
  }
}

impl<'a> Mul for Node<'a> {
  type Output = Self;

  fn mul(self, rhs: Self) -> Self {
    self.compose_with(rhs, ColorAlpha::new(1., 1., 1., 1.), Equation::Additive, Factor::Zero, Factor::SrcColor)
  }
}

impl<'a> BitAnd for Node<'a> {
  type Output = Self;

  fn bitand(self, rhs: Self) -> Self::Output {
    self.compose_with(rhs, ColorAlpha::new(0., 0., 0., 0.), Equation::Additive, Factor::SrcAlpha, Factor::SrcAlphaComplement)
  }
}

/// Compositor object; used to consume `Node`s and output to screen.
pub struct Compositor {
  // width
  w: u32,
  // height
  h: u32,
  // allocated framebuffers that might contain nodes’ output
  framebuffers: Vec<Framebuffer<Flat, Dim2, ColorMap, DepthMap>>,
  // free list of available framebuffers
  free_framebuffers: Vec<usize>,
  // program used to compose nodes
  program: Res<Program>,
  // attributeless fullscreen quad for compositing
  quad: Tess
}

const FORWARD_SOURCE: &'static Uniform<Unit> = &Uniform::new(0);

impl Compositor {
  pub fn new(w: u32, h: u32, cache: &mut ResCache) -> Self {
    Compositor {
      w: w,
      h: h,
      framebuffers: Vec::new(),
      free_framebuffers: Vec::new(),
      program: cache.get("spectra/compositing/forward.glsl", vec![FORWARD_SOURCE.sem("source")]).unwrap(),
      quad: Tess::attributeless(Mode::TriangleStrip, 4)
    }
  }

  /// Whenever a node must be composed, we need a framebuffer to render into. This function pulls a
  /// framebuffer to use (via self.framebuffers) by returing an index. It might allocate a new
  /// framebuffer if there isn’t enough framebuffers to be pulled.
  fn pull_framebuffer(&mut self) -> usize {
    self.free_framebuffers.pop().unwrap_or_else(|| {
      let framebuffer_index = self.framebuffers.len();

      let framebuffer = Framebuffer::new((self.w, self.h), 0).unwrap();
      self.framebuffers.push(framebuffer);

      framebuffer_index
    })
  }

  /// Whenever a node has finished being composed, we *might* need to dispose the framebuffer it has
  /// pulled. This funciton does that job.
  ///
  /// It never deallocates memory. It has an important property: once a framebuffer is pulled,
  /// calling that function will make it available for other nodes, improving memory usage for the
  /// next calls.
  #[inline]
  fn dispose_framebuffer(&mut self, framebuffer_index: usize) {
    self.free_framebuffers.push(framebuffer_index);
  }

  /// Consume and display a compositing graph represented by its nodes.
  pub fn display(&mut self, root: Node) {
    let fb_index = self.treat_node(root);

    {
      let fb = &self.framebuffers[fb_index];

      let screen = Framebuffer::default((self.w, self.h));

      let black = [0., 0., 0., 1.];
      let program = self.program.borrow();
      let uniforms_tex = [FORWARD_SOURCE.alter(Unit::new(0))];
      let tess_render = TessRender::from(&self.quad);
      let tess = &[Pipe::empty().uniforms(&uniforms_tex).unwrap(tess_render.clone())];
      let render_cmd = &[Pipe::new(RenderCommand::new(None, false, tess))];
      let shd_cmd = &[Pipe::new(ShadingCommand::new(&program, render_cmd))];
      let texture_set = &[&*fb.color_slot];

      Pipeline::new(&screen, black, texture_set, &[], shd_cmd).run();
    }

    self.dispose_framebuffer(fb_index);
  }

  /// Treat a node hierarchy and return the index  of the framebuffer that contains the result.
  fn treat_node(&mut self, node: Node) -> usize {
    match node {
      Node::Render(layer) => self.render(layer),
      Node::Texture(texture) => self.texturize(texture),
      Node::Color(color) => self.colorize(color),
      Node::Composite(left, right, clear_color, eq, src_fct, dst_fct) => self.composite(*left, *right, clear_color, eq, src_fct, dst_fct),
    }
  }

  fn render(&mut self, layer: RenderLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    (layer.render)(&fb);

    fb_index
  }

  fn texturize(&mut self, texture: TextureLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let black = [0., 0., 0., 1.];
    let program = self.program.borrow();
    let uniforms_tex = [FORWARD_SOURCE.alter(Unit::new(0))];
    let tess_render = TessRender::from(&self.quad);
    let tess = &[Pipe::empty().uniforms(&uniforms_tex).unwrap(tess_render.clone())];
    let render_cmd = &[Pipe::new(RenderCommand::new(None, false, tess))];
    let shd_cmd = &[Pipe::new(ShadingCommand::new(&program, render_cmd))];
    let texture_set = &[&**texture];

    Pipeline::new(fb, black, texture_set, &[], shd_cmd).run();

    fb_index
  }

  fn colorize(&mut self, color: ColorAlpha) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let color = *color.as_ref();

    Pipeline::new(fb, color, &[], &[], &[]).run();

    fb_index
  }

  fn composite(&mut self, left: Node, right: Node, clear_color: ColorAlpha, eq: Equation, src_fct: Factor, dst_fct: Factor) -> usize {
    let left_index = self.treat_node(left);
    let right_index = self.treat_node(right);

    assert!(left_index < self.framebuffers.len());
    assert!(right_index < self.framebuffers.len());

    let fb_index = self.pull_framebuffer();

    {
      let fb = &self.framebuffers[fb_index];

      let left_fb = &self.framebuffers[left_index];
      let right_fb = &self.framebuffers[right_index];

      // compose
      let program = self.program.borrow();
      let uniforms_left = [FORWARD_SOURCE.alter(Unit::new(0))];
      let uniforms_right = [FORWARD_SOURCE.alter(Unit::new(1))];
      let tess_render = TessRender::from(&self.quad);
      let tess = &[
        Pipe::empty().uniforms(&uniforms_left).unwrap(tess_render.clone()),
        Pipe::empty().uniforms(&uniforms_right).unwrap(tess_render)
      ];
      let render_cmd = &[Pipe::new(RenderCommand::new((eq, src_fct, dst_fct), false, tess))];
      let shd_cmd = &[Pipe::new(ShadingCommand::new(&program, render_cmd))];
      let texture_set = &[
        &*left_fb.color_slot,
        &*right_fb.color_slot
      ];

      Pipeline::new(fb, *clear_color.as_ref(), texture_set, &[], shd_cmd).run();
    }

    // dispose both left and right framebuffers
    self.dispose_framebuffer(left_index);
    self.dispose_framebuffer(right_index);

    fb_index
  }
}
<commit_msg>Removed BitAnd operator for Node and replaced it by Node::over.<commit_after>use luminance::{Depth32F, Dim2, Flat, Framebuffer, Mode, RGBA32F, Tess, Texture, Uniform, Unit};
use luminance::pipeline::{Pipe, Pipeline, RenderCommand, ShadingCommand};
use luminance::tess::TessRender;
use std::ops::{Add, Mul, Sub};

pub use luminance::{Equation, Factor};

use color::ColorAlpha;
use resource::{Res, ResCache};
use shader::Program;

/// Simple texture that can be embedded into a compositing graph.
pub type TextureLayer<'a> = &'a ColorMap;

pub type ColorMap = Texture<Flat, Dim2, RGBA32F>;
pub type DepthMap = Texture<Flat, Dim2, Depth32F>;

/// Render layer used to host renders.
pub struct RenderLayer<'a> {
  render: Box<Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) + 'a>
}

impl<'a> RenderLayer<'a> {
  pub fn new<F>(render: F) -> Self where F: 'a + Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) {
    RenderLayer {
      render: Box::new(render)
    }
  }
}

/// Compositing node.
pub enum Node<'a> {
  /// A render node.
  ///
  /// Contains render layer.
  Render(RenderLayer<'a>),
  /// A texture node.
  ///
  /// Contains a single texture.
  Texture(TextureLayer<'a>),
  /// A single color.
  ///
  /// Keep in mind that such a node is great when you want to display a fullscreen colored quad but
  /// you shouldn’t use it for blending purpose. Adding color masking to your post-process is a
  /// better alternative and will avoid fillrate alteration.
  Color(ColorAlpha),
  /// Composite node.
  ///
  /// Composite nodes are used to blend two compositing nodes according to a given `Equation` and
  /// two blending `Factor`s for source and destination, respectively.
  Composite(Box<Node<'a>>, Box<Node<'a>>, ColorAlpha, Equation, Factor, Factor)
}

impl<'a> Node<'a> {
  /// Compose this node with another one.
  pub fn compose_with(self, rhs: Self, clear_color: ColorAlpha, eq: Equation, src_fct: Factor, dst_fct: Factor) -> Self {
    Node::Composite(Box::new(self), Box::new(rhs), clear_color, eq, src_fct, dst_fct)
  }

  /// Compose this node over the other. In effect, the resulting node will replace any pixels covered
  /// by the right node by the ones of the left node unless the alpha value is different than `1`.
  /// In that case, an additive blending based on the alpha value of the left node will be performed.
  ///
  /// If you set the alpha value to `0` at a pixel in the left node, then the resulting pixel will be
  /// the one from the right node.
  pub fn over(self, rhs: Self) -> Self {
    self.compose_with(rhs, ColorAlpha::new(0., 0., 0., 0.), Equation::Additive, Factor::SrcAlpha, Factor::SrcAlphaComplement)
  }
}

impl<'a> From<RenderLayer<'a>> for Node<'a> {
  fn from(layer: RenderLayer<'a>) -> Self {
    Node::Render(layer)
  }
}

impl<'a> From<TextureLayer<'a>> for Node<'a> {
  fn from(texture: TextureLayer<'a>) -> Self {
    Node::Texture(texture)
  }
}

impl<'a> From<ColorAlpha> for Node<'a> {
  fn from(color: ColorAlpha) -> Self {
    Node::Color(color)
  }
}

impl<'a> Add for Node<'a> {
  type Output = Self;

  fn add(self, rhs: Self) -> Self {
    self.compose_with(rhs, ColorAlpha::new(0., 0., 0., 0.), Equation::Additive, Factor::One, Factor::One)
  }
}

impl<'a> Sub for Node<'a> {
  type Output = Self;

  fn sub(self, rhs: Self) -> Self {
    self.compose_with(rhs, ColorAlpha::new(0., 0., 0., 0.), Equation::Subtract, Factor::One, Factor::One)
  }
}

impl<'a> Mul for Node<'a> {
  type Output = Self;

  fn mul(self, rhs: Self) -> Self {
    self.compose_with(rhs, ColorAlpha::new(1., 1., 1., 1.), Equation::Additive, Factor::Zero, Factor::SrcColor)
  }
}

/// Compositor object; used to consume `Node`s and output to screen.
pub struct Compositor {
  // width
  w: u32,
  // height
  h: u32,
  // allocated framebuffers that might contain nodes’ output
  framebuffers: Vec<Framebuffer<Flat, Dim2, ColorMap, DepthMap>>,
  // free list of available framebuffers
  free_framebuffers: Vec<usize>,
  // program used to compose nodes
  program: Res<Program>,
  // attributeless fullscreen quad for compositing
  quad: Tess
}

const FORWARD_SOURCE: &'static Uniform<Unit> = &Uniform::new(0);

impl Compositor {
  pub fn new(w: u32, h: u32, cache: &mut ResCache) -> Self {
    Compositor {
      w: w,
      h: h,
      framebuffers: Vec::new(),
      free_framebuffers: Vec::new(),
      program: cache.get("spectra/compositing/forward.glsl", vec![FORWARD_SOURCE.sem("source")]).unwrap(),
      quad: Tess::attributeless(Mode::TriangleStrip, 4)
    }
  }

  /// Whenever a node must be composed, we need a framebuffer to render into. This function pulls a
  /// framebuffer to use (via self.framebuffers) by returing an index. It might allocate a new
  /// framebuffer if there isn’t enough framebuffers to be pulled.
  fn pull_framebuffer(&mut self) -> usize {
    self.free_framebuffers.pop().unwrap_or_else(|| {
      let framebuffer_index = self.framebuffers.len();

      let framebuffer = Framebuffer::new((self.w, self.h), 0).unwrap();
      self.framebuffers.push(framebuffer);

      framebuffer_index
    })
  }

  /// Whenever a node has finished being composed, we *might* need to dispose the framebuffer it has
  /// pulled. This funciton does that job.
  ///
  /// It never deallocates memory. It has an important property: once a framebuffer is pulled,
  /// calling that function will make it available for other nodes, improving memory usage for the
  /// next calls.
  #[inline]
  fn dispose_framebuffer(&mut self, framebuffer_index: usize) {
    self.free_framebuffers.push(framebuffer_index);
  }

  /// Consume and display a compositing graph represented by its nodes.
  pub fn display(&mut self, root: Node) {
    let fb_index = self.treat_node(root);

    {
      let fb = &self.framebuffers[fb_index];

      let screen = Framebuffer::default((self.w, self.h));

      let black = [0., 0., 0., 1.];
      let program = self.program.borrow();
      let uniforms_tex = [FORWARD_SOURCE.alter(Unit::new(0))];
      let tess_render = TessRender::from(&self.quad);
      let tess = &[Pipe::empty().uniforms(&uniforms_tex).unwrap(tess_render.clone())];
      let render_cmd = &[Pipe::new(RenderCommand::new(None, false, tess))];
      let shd_cmd = &[Pipe::new(ShadingCommand::new(&program, render_cmd))];
      let texture_set = &[&*fb.color_slot];

      Pipeline::new(&screen, black, texture_set, &[], shd_cmd).run();
    }

    self.dispose_framebuffer(fb_index);
  }

  /// Treat a node hierarchy and return the index  of the framebuffer that contains the result.
  fn treat_node(&mut self, node: Node) -> usize {
    match node {
      Node::Render(layer) => self.render(layer),
      Node::Texture(texture) => self.texturize(texture),
      Node::Color(color) => self.colorize(color),
      Node::Composite(left, right, clear_color, eq, src_fct, dst_fct) => self.composite(*left, *right, clear_color, eq, src_fct, dst_fct),
    }
  }

  fn render(&mut self, layer: RenderLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    (layer.render)(&fb);

    fb_index
  }

  fn texturize(&mut self, texture: TextureLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let black = [0., 0., 0., 1.];
    let program = self.program.borrow();
    let uniforms_tex = [FORWARD_SOURCE.alter(Unit::new(0))];
    let tess_render = TessRender::from(&self.quad);
    let tess = &[Pipe::empty().uniforms(&uniforms_tex).unwrap(tess_render.clone())];
    let render_cmd = &[Pipe::new(RenderCommand::new(None, false, tess))];
    let shd_cmd = &[Pipe::new(ShadingCommand::new(&program, render_cmd))];
    let texture_set = &[&**texture];

    Pipeline::new(fb, black, texture_set, &[], shd_cmd).run();

    fb_index
  }

  fn colorize(&mut self, color: ColorAlpha) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let color = *color.as_ref();

    Pipeline::new(fb, color, &[], &[], &[]).run();

    fb_index
  }

  fn composite(&mut self, left: Node, right: Node, clear_color: ColorAlpha, eq: Equation, src_fct: Factor, dst_fct: Factor) -> usize {
    let left_index = self.treat_node(left);
    let right_index = self.treat_node(right);

    assert!(left_index < self.framebuffers.len());
    assert!(right_index < self.framebuffers.len());

    let fb_index = self.pull_framebuffer();

    {
      let fb = &self.framebuffers[fb_index];

      let left_fb = &self.framebuffers[left_index];
      let right_fb = &self.framebuffers[right_index];

      // compose
      let program = self.program.borrow();
      let uniforms_left = [FORWARD_SOURCE.alter(Unit::new(0))];
      let uniforms_right = [FORWARD_SOURCE.alter(Unit::new(1))];
      let tess_render = TessRender::from(&self.quad);
      let tess = &[
        Pipe::empty().uniforms(&uniforms_left).unwrap(tess_render.clone()),
        Pipe::empty().uniforms(&uniforms_right).unwrap(tess_render)
      ];
      let render_cmd = &[Pipe::new(RenderCommand::new((eq, src_fct, dst_fct), false, tess))];
      let shd_cmd = &[Pipe::new(ShadingCommand::new(&program, render_cmd))];
      let texture_set = &[
        &*left_fb.color_slot,
        &*right_fb.color_slot
      ];

      Pipeline::new(fb, *clear_color.as_ref(), texture_set, &[], shd_cmd).run();
    }

    // dispose both left and right framebuffers
    self.dispose_framebuffer(left_index);
    self.dispose_framebuffer(right_index);

    fb_index
  }
}
<|endoftext|>


<commit_before>//! Possible ZIP compression methods.

use std::fmt;

/// Compression methods for the contents of a ZIP file.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum CompressionMethod
{
    /// The file is stored (no compression)
    Stored,
    /// Deflate in pure rust
    #[cfg(feature = "deflate")]
    Deflated,
    /// File is compressed using BZIP2 algorithm
    #[cfg(feature = "bzip2")]
    Bzip2,
    /// Unsupported compression method
    Unsupported(u16),
}

impl CompressionMethod {
    /// Converts an u16 to its corresponding CompressionMethod
    pub fn from_u16(val: u16) -> CompressionMethod {
        match val {
            0 => CompressionMethod::Stored,
            #[cfg(feature = "deflate")]
            8 => CompressionMethod::Deflated,
            #[cfg(feature = "bzip2")]
            12 => CompressionMethod::Bzip2,
            v => CompressionMethod::Unsupported(v),
        }
    }

    /// Converts a CompressionMethod to a u16
    pub fn to_u16(self) -> u16 {
        match self {
            CompressionMethod::Stored => 0,
            #[cfg(feature = "deflate")]
            CompressionMethod::Deflated => 8,
            #[cfg(feature = "bzip2")]
            CompressionMethod::Bzip2 => 12,
            CompressionMethod::Unsupported(v) => v,
        }
    }
}

impl fmt::Display for CompressionMethod {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Just duplicate what the Debug format looks like, i.e, the enum key:
        write!(f, "{:?}", self)
    }
}

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

    #[test]
    fn from_eq_to() {
        for v in 0..(::std::u16::MAX as u32 + 1)
        {
            let from = CompressionMethod::from_u16(v as u16);
            let to = from.to_u16() as u32;
            assert_eq!(v, to);
        }
    }

    #[cfg(all(not(feature = "bzip2"), feature = "deflate"))]
    fn methods() -> Vec<CompressionMethod> {
        vec![CompressionMethod::Stored, CompressionMethod::Deflated]
    }

    #[cfg(all(not(feature = "deflate"), feature = "bzip2"))]
    fn methods() -> Vec<CompressionMethod> {
        vec![CompressionMethod::Stored, CompressionMethod::Bzip2]
    }

    #[cfg(all(feature = "bzip2", feature = "deflate"))]
    fn methods() -> Vec<CompressionMethod> {
        vec![CompressionMethod::Stored, CompressionMethod::Deflated, CompressionMethod::Bzip2]
    }

    #[cfg(all(not(feature = "bzip2"), not(feature = "deflate")))]
    fn methods() -> Vec<CompressionMethod> {
        vec![CompressionMethod::Stored]
    }

    #[test]
    fn to_eq_from() {
        fn check_match(method: CompressionMethod) {
            let to = method.to_u16();
            let from = CompressionMethod::from_u16(to);
            let back = from.to_u16();
            assert_eq!(to, back);
        }

        for method in methods() {
            check_match(method);
        }
    }

    #[test]
    fn to_display_fmt() {
        fn check_match(method: CompressionMethod) {
            let debug_str = format!("{:?}", method);
            let display_str = format!("{}", method);
            assert_eq!(debug_str, display_str);
        }

        for method in methods() {
            check_match(method);
        }
    }
}
<commit_msg>Simplify test code of compression<commit_after>//! Possible ZIP compression methods.

use std::fmt;

/// Compression methods for the contents of a ZIP file.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum CompressionMethod
{
    /// The file is stored (no compression)
    Stored,
    /// Deflate in pure rust
    #[cfg(feature = "deflate")]
    Deflated,
    /// File is compressed using BZIP2 algorithm
    #[cfg(feature = "bzip2")]
    Bzip2,
    /// Unsupported compression method
    Unsupported(u16),
}

impl CompressionMethod {
    /// Converts an u16 to its corresponding CompressionMethod
    pub fn from_u16(val: u16) -> CompressionMethod {
        match val {
            0 => CompressionMethod::Stored,
            #[cfg(feature = "deflate")]
            8 => CompressionMethod::Deflated,
            #[cfg(feature = "bzip2")]
            12 => CompressionMethod::Bzip2,
            v => CompressionMethod::Unsupported(v),
        }
    }

    /// Converts a CompressionMethod to a u16
    pub fn to_u16(self) -> u16 {
        match self {
            CompressionMethod::Stored => 0,
            #[cfg(feature = "deflate")]
            CompressionMethod::Deflated => 8,
            #[cfg(feature = "bzip2")]
            CompressionMethod::Bzip2 => 12,
            CompressionMethod::Unsupported(v) => v,
        }
    }
}

impl fmt::Display for CompressionMethod {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Just duplicate what the Debug format looks like, i.e, the enum key:
        write!(f, "{:?}", self)
    }
}

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

    #[test]
    fn from_eq_to() {
        for v in 0..(::std::u16::MAX as u32 + 1)
        {
            let from = CompressionMethod::from_u16(v as u16);
            let to = from.to_u16() as u32;
            assert_eq!(v, to);
        }
    }

    fn methods() -> Vec<CompressionMethod> {
        let mut methods = Vec::new();
        methods.push(CompressionMethod::Stored);
        #[cfg(feature="deflate")] methods.push(CompressionMethod::Deflated);
        #[cfg(feature="bzip2")] methods.push(CompressionMethod::Bzip2);
        methods
    }

    #[test]
    fn to_eq_from() {
        fn check_match(method: CompressionMethod) {
            let to = method.to_u16();
            let from = CompressionMethod::from_u16(to);
            let back = from.to_u16();
            assert_eq!(to, back);
        }

        for method in methods() {
            check_match(method);
        }
    }

    #[test]
    fn to_display_fmt() {
        fn check_match(method: CompressionMethod) {
            let debug_str = format!("{:?}", method);
            let display_str = format!("{}", method);
            assert_eq!(debug_str, display_str);
        }

        for method in methods() {
            check_match(method);
        }
    }
}
<|endoftext|>