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

mod tags;
mod html;

use hir::{Name, Semantics};
use ra_ide_db::{
    defs::{classify_name, NameDefinition},
    RootDatabase,
};
use ra_prof::profile;
use ra_syntax::{
    ast, AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxKind::*, SyntaxToken,
    TextRange, WalkEvent, T,
};
use rustc_hash::FxHashMap;

use crate::{references::classify_name_ref, FileId};

pub use tags::{Highlight, HighlightModifier, HighlightModifiers, HighlightTag};

pub(crate) use html::highlight_as_html;

#[derive(Debug)]
pub struct HighlightedRange {
    pub range: TextRange,
    pub highlight: Highlight,
    pub binding_hash: Option<u64>,
}

fn is_control_keyword(kind: SyntaxKind) -> bool {
    match kind {
        T![for]
        | T![loop]
        | T![while]
        | T![continue]
        | T![break]
        | T![if]
        | T![else]
        | T![match]
        | T![return] => true,
        _ => false,
    }
}

pub(crate) fn highlight(
    db: &RootDatabase,
    file_id: FileId,
    range_to_highlight: Option<TextRange>,
) -> Vec<HighlightedRange> {
    let _p = profile("highlight");
    let sema = Semantics::new(db);

    // Determine the root based on the given range.
    let (root, range_to_highlight) = {
        let source_file = sema.parse(file_id);
        match range_to_highlight {
            Some(range) => {
                let node = match source_file.syntax().covering_element(range) {
                    NodeOrToken::Node(it) => it,
                    NodeOrToken::Token(it) => it.parent(),
                };
                (node, range)
            }
            None => (source_file.syntax().clone(), source_file.syntax().text_range()),
        }
    };

    let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default();
    let mut res = Vec::new();

    let mut current_macro_call: Option<ast::MacroCall> = None;

    for event in root.preorder_with_tokens() {
        let event_range = match &event {
            WalkEvent::Enter(it) => it.text_range(),
            WalkEvent::Leave(it) => it.text_range(),
        };

        if event_range.intersection(&range_to_highlight).is_none() {
            continue;
        }

        match event.clone().map(|it| it.into_node().and_then(ast::MacroCall::cast)) {
            WalkEvent::Enter(Some(mc)) => {
                current_macro_call = Some(mc.clone());
                if let Some(range) = highlight_macro(&mc) {
                    res.push(HighlightedRange {
                        range,
                        highlight: HighlightTag::Macro.into(),
                        binding_hash: None,
                    });
                }
                continue;
            }
            WalkEvent::Leave(Some(mc)) => {
                assert!(current_macro_call == Some(mc));
                current_macro_call = None;
                continue;
            }
            _ => (),
        }

        let node = match event {
            WalkEvent::Enter(it) => it,
            WalkEvent::Leave(_) => continue,
        };

        if current_macro_call.is_some() {
            if let Some(token) = node.into_token() {
                if let Some((highlight, binding_hash)) =
                    highlight_token_tree(&sema, &mut bindings_shadow_count, token.clone())
                {
                    res.push(HighlightedRange {
                        range: token.text_range(),
                        highlight,
                        binding_hash,
                    });
                }
            }
            continue;
        }

        if let Some((highlight, binding_hash)) =
            highlight_node(&sema, &mut bindings_shadow_count, node.clone())
        {
            res.push(HighlightedRange { range: node.text_range(), highlight, binding_hash });
        }
    }

    res
}

fn highlight_macro(macro_call: &ast::MacroCall) -> Option<TextRange> {
    let path = macro_call.path()?;
    let name_ref = path.segment()?.name_ref()?;

    let range_start = name_ref.syntax().text_range().start();
    let mut range_end = name_ref.syntax().text_range().end();
    for sibling in path.syntax().siblings_with_tokens(Direction::Next) {
        match sibling.kind() {
            T![!] | IDENT => range_end = sibling.text_range().end(),
            _ => (),
        }
    }

    Some(TextRange::from_to(range_start, range_end))
}

fn highlight_token_tree(
    sema: &Semantics<RootDatabase>,
    bindings_shadow_count: &mut FxHashMap<Name, u32>,
    token: SyntaxToken,
) -> Option<(Highlight, Option<u64>)> {
    if token.parent().kind() != TOKEN_TREE {
        return None;
    }
    let token = sema.descend_into_macros(token.clone());
    let expanded = {
        let parent = token.parent();
        // We only care Name and Name_ref
        match (token.kind(), parent.kind()) {
            (IDENT, NAME) | (IDENT, NAME_REF) => parent.into(),
            _ => token.into(),
        }
    };

    highlight_node(sema, bindings_shadow_count, expanded)
}

fn highlight_node(
    sema: &Semantics<RootDatabase>,
    bindings_shadow_count: &mut FxHashMap<Name, u32>,
    node: SyntaxElement,
) -> Option<(Highlight, Option<u64>)> {
    let db = sema.db;
    let mut binding_hash = None;
    let highlight: Highlight = match node.kind() {
        FN_DEF => {
            bindings_shadow_count.clear();
            return None;
        }
        COMMENT => HighlightTag::Comment.into(),
        STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => HighlightTag::LiteralString.into(),
        ATTR => HighlightTag::Attribute.into(),
        // Special-case field init shorthand
        NAME_REF if node.parent().and_then(ast::RecordField::cast).is_some() => {
            HighlightTag::Field.into()
        }
        NAME_REF if node.ancestors().any(|it| it.kind() == ATTR) => return None,
        NAME_REF => {
            let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap();
            let name_kind = classify_name_ref(sema, &name_ref);
            match name_kind {
                Some(name_kind) => {
                    if let NameDefinition::Local(local) = &name_kind {
                        if let Some(name) = local.name(db) {
                            let shadow_count =
                                bindings_shadow_count.entry(name.clone()).or_default();
                            binding_hash = Some(calc_binding_hash(&name, *shadow_count))
                        }
                    };

                    highlight_name(db, name_kind)
                }
                _ => return None,
            }
        }
        NAME => {
            let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap();
            let name_kind = classify_name(sema, &name);

            if let Some(NameDefinition::Local(local)) = &name_kind {
                if let Some(name) = local.name(db) {
                    let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
                    *shadow_count += 1;
                    binding_hash = Some(calc_binding_hash(&name, *shadow_count))
                }
            };

            match name_kind {
                Some(name_kind) => highlight_name(db, name_kind),
                None => name.syntax().parent().map_or(HighlightTag::Function.into(), |x| {
                    match x.kind() {
                        STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => {
                            HighlightTag::Type.into()
                        }
                        TYPE_PARAM => HighlightTag::TypeParam.into(),
                        RECORD_FIELD_DEF => HighlightTag::Field.into(),
                        _ => HighlightTag::Function.into(),
                    }
                }),
            }
        }
        INT_NUMBER | FLOAT_NUMBER => HighlightTag::LiteralNumeric.into(),
        BYTE => HighlightTag::LiteralByte.into(),
        CHAR => HighlightTag::LiteralChar.into(),
        LIFETIME => HighlightTag::TypeLifetime.into(),
        T![unsafe] => HighlightTag::Keyword | HighlightModifier::Unsafe,
        k if is_control_keyword(k) => HighlightTag::Keyword | HighlightModifier::Control,
        k if k.is_keyword() => HighlightTag::Keyword.into(),

        _ => return None,
    };

    return Some((highlight, binding_hash));

    fn calc_binding_hash(name: &Name, shadow_count: u32) -> u64 {
        fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 {
            use std::{collections::hash_map::DefaultHasher, hash::Hasher};

            let mut hasher = DefaultHasher::new();
            x.hash(&mut hasher);
            hasher.finish()
        }

        hash((name, shadow_count))
    }
}

fn highlight_name(db: &RootDatabase, def: NameDefinition) -> Highlight {
    match def {
        NameDefinition::Macro(_) => HighlightTag::Macro,
        NameDefinition::StructField(_) => HighlightTag::Field,
        NameDefinition::ModuleDef(hir::ModuleDef::Module(_)) => HighlightTag::Module,
        NameDefinition::ModuleDef(hir::ModuleDef::Function(_)) => HighlightTag::Function,
        NameDefinition::ModuleDef(hir::ModuleDef::Adt(_)) => HighlightTag::Type,
        NameDefinition::ModuleDef(hir::ModuleDef::EnumVariant(_)) => HighlightTag::Constant,
        NameDefinition::ModuleDef(hir::ModuleDef::Const(_)) => HighlightTag::Constant,
        NameDefinition::ModuleDef(hir::ModuleDef::Static(_)) => HighlightTag::Constant,
        NameDefinition::ModuleDef(hir::ModuleDef::Trait(_)) => HighlightTag::Type,
        NameDefinition::ModuleDef(hir::ModuleDef::TypeAlias(_)) => HighlightTag::Type,
        NameDefinition::ModuleDef(hir::ModuleDef::BuiltinType(_)) => {
            return HighlightTag::Type | HighlightModifier::Builtin
        }
        NameDefinition::SelfType(_) => HighlightTag::TypeSelf,
        NameDefinition::TypeParam(_) => HighlightTag::TypeParam,
        NameDefinition::Local(local) => {
            let mut h = Highlight::new(HighlightTag::Variable);
            if local.is_mut(db) || local.ty(db).is_mutable_reference() {
                h |= HighlightModifier::Mutable;
            }
            return h;
        }
    }
    .into()
}

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

    use test_utils::{assert_eq_text, project_dir, read_text};

    use crate::{
        mock_analysis::{single_file, MockAnalysis},
        FileRange, TextRange,
    };

    #[test]
    fn test_highlighting() {
        let (analysis, file_id) = single_file(
            r#"
#[derive(Clone, Debug)]
struct Foo {
    pub x: i32,
    pub y: i32,
}

fn foo<T>() -> T {
    unimplemented!();
    foo::<i32>();
}

macro_rules! def_fn {
    ($($tt:tt)*) => {$($tt)*}
}

def_fn!{
    fn bar() -> u32 {
        100
    }
}

// comment
fn main() {
    println!("Hello, {}!", 92);

    let mut vec = Vec::new();
    if true {
        let x = 92;
        vec.push(Foo { x, y: 1 });
    }
    unsafe { vec.set_len(0); }

    let mut x = 42;
    let y = &mut x;
    let z = &y;

    y;
}

enum E<X> {
    V(X)
}

impl<X> E<X> {
    fn new<T>() -> E<T> {}
}
"#
            .trim(),
        );
        let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlighting.html");
        let actual_html = &analysis.highlight_as_html(file_id, false).unwrap();
        let expected_html = &read_text(&dst_file);
        fs::write(dst_file, &actual_html).unwrap();
        assert_eq_text!(expected_html, actual_html);
    }

    #[test]
    fn test_rainbow_highlighting() {
        let (analysis, file_id) = single_file(
            r#"
fn main() {
    let hello = "hello";
    let x = hello.to_string();
    let y = hello.to_string();

    let x = "other color please!";
    let y = x.to_string();
}

fn bar() {
    let mut hello = "hello";
}
"#
            .trim(),
        );
        let dst_file = project_dir().join("crates/ra_ide/src/snapshots/rainbow_highlighting.html");
        let actual_html = &analysis.highlight_as_html(file_id, true).unwrap();
        let expected_html = &read_text(&dst_file);
        fs::write(dst_file, &actual_html).unwrap();
        assert_eq_text!(expected_html, actual_html);
    }

    #[test]
    fn accidentally_quadratic() {
        let file = project_dir().join("crates/ra_syntax/test_data/accidentally_quadratic");
        let src = fs::read_to_string(file).unwrap();

        let mut mock = MockAnalysis::new();
        let file_id = mock.add_file("/main.rs", &src);
        let host = mock.analysis_host();

        // let t = std::time::Instant::now();
        let _ = host.analysis().highlight(file_id).unwrap();
        // eprintln!("elapsed: {:?}", t.elapsed());
    }

    #[test]
    fn test_ranges() {
        let (analysis, file_id) = single_file(
            r#"
            #[derive(Clone, Debug)]
            struct Foo {
                pub x: i32,
                pub y: i32,
            }"#,
        );

        // The "x"
        let highlights = &analysis
            .highlight_range(FileRange {
                file_id,
                range: TextRange::offset_len(82.into(), 1.into()),
            })
            .unwrap();

        assert_eq!(&highlights[0].highlight.to_string(), "field");
    }
}
<commit_msg>More cleanup<commit_after>//! Implements syntax highlighting.

mod tags;
mod html;

use hir::{Name, Semantics};
use ra_ide_db::{
    defs::{classify_name, NameDefinition},
    RootDatabase,
};
use ra_prof::profile;
use ra_syntax::{
    ast, AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxKind::*, TextRange, WalkEvent, T,
};
use rustc_hash::FxHashMap;

use crate::{references::classify_name_ref, FileId};

pub(crate) use html::highlight_as_html;
pub use tags::{Highlight, HighlightModifier, HighlightModifiers, HighlightTag};

#[derive(Debug)]
pub struct HighlightedRange {
    pub range: TextRange,
    pub highlight: Highlight,
    pub binding_hash: Option<u64>,
}

pub(crate) fn highlight(
    db: &RootDatabase,
    file_id: FileId,
    range_to_highlight: Option<TextRange>,
) -> Vec<HighlightedRange> {
    let _p = profile("highlight");
    let sema = Semantics::new(db);

    // Determine the root based on the given range.
    let (root, range_to_highlight) = {
        let source_file = sema.parse(file_id);
        match range_to_highlight {
            Some(range) => {
                let node = match source_file.syntax().covering_element(range) {
                    NodeOrToken::Node(it) => it,
                    NodeOrToken::Token(it) => it.parent(),
                };
                (node, range)
            }
            None => (source_file.syntax().clone(), source_file.syntax().text_range()),
        }
    };

    let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default();
    let mut res = Vec::new();

    let mut current_macro_call: Option<ast::MacroCall> = None;

    // Walk all nodes, keeping track of whether we are inside a macro or not.
    // If in macro, expand it first and highlight the expanded code.
    for event in root.preorder_with_tokens() {
        let event_range = match &event {
            WalkEvent::Enter(it) => it.text_range(),
            WalkEvent::Leave(it) => it.text_range(),
        };

        // Element outside of the viewport, no need to highlight
        if range_to_highlight.intersection(&event_range).is_none() {
            continue;
        }

        // Track "inside macro" state
        match event.clone().map(|it| it.into_node().and_then(ast::MacroCall::cast)) {
            WalkEvent::Enter(Some(mc)) => {
                current_macro_call = Some(mc.clone());
                if let Some(range) = macro_call_range(&mc) {
                    res.push(HighlightedRange {
                        range,
                        highlight: HighlightTag::Macro.into(),
                        binding_hash: None,
                    });
                }
                continue;
            }
            WalkEvent::Leave(Some(mc)) => {
                assert!(current_macro_call == Some(mc));
                current_macro_call = None;
                continue;
            }
            _ => (),
        }

        let element = match event {
            WalkEvent::Enter(it) => it,
            WalkEvent::Leave(_) => continue,
        };
        let range = element.text_range();

        let element_to_highlight = if current_macro_call.is_some() {
            // Inside a macro -- expand it first
            let token = match element.into_token() {
                Some(it) if it.parent().kind() == TOKEN_TREE => it,
                _ => continue,
            };
            let token = sema.descend_into_macros(token.clone());
            let parent = token.parent();
            // We only care Name and Name_ref
            match (token.kind(), parent.kind()) {
                (IDENT, NAME) | (IDENT, NAME_REF) => parent.into(),
                _ => token.into(),
            }
        } else {
            element
        };

        if let Some((highlight, binding_hash)) =
            highlight_element(&sema, &mut bindings_shadow_count, element_to_highlight)
        {
            res.push(HighlightedRange { range, highlight, binding_hash });
        }
    }

    res
}

fn macro_call_range(macro_call: &ast::MacroCall) -> Option<TextRange> {
    let path = macro_call.path()?;
    let name_ref = path.segment()?.name_ref()?;

    let range_start = name_ref.syntax().text_range().start();
    let mut range_end = name_ref.syntax().text_range().end();
    for sibling in path.syntax().siblings_with_tokens(Direction::Next) {
        match sibling.kind() {
            T![!] | IDENT => range_end = sibling.text_range().end(),
            _ => (),
        }
    }

    Some(TextRange::from_to(range_start, range_end))
}

fn highlight_element(
    sema: &Semantics<RootDatabase>,
    bindings_shadow_count: &mut FxHashMap<Name, u32>,
    element: SyntaxElement,
) -> Option<(Highlight, Option<u64>)> {
    let db = sema.db;
    let mut binding_hash = None;
    let highlight: Highlight = match element.kind() {
        FN_DEF => {
            bindings_shadow_count.clear();
            return None;
        }

        // Highlight definitions depending on the "type" of the definition.
        NAME => {
            let name = element.into_node().and_then(ast::Name::cast).unwrap();
            let name_kind = classify_name(sema, &name);

            if let Some(NameDefinition::Local(local)) = &name_kind {
                if let Some(name) = local.name(db) {
                    let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
                    *shadow_count += 1;
                    binding_hash = Some(calc_binding_hash(&name, *shadow_count))
                }
            };

            match name_kind {
                Some(name_kind) => highlight_name(db, name_kind),
                None => highlight_name_by_syntax(name),
            }
        }

        // Highlight references like the definitions they resolve to

        // Special-case field init shorthand
        NAME_REF if element.parent().and_then(ast::RecordField::cast).is_some() => {
            HighlightTag::Field.into()
        }
        NAME_REF if element.ancestors().any(|it| it.kind() == ATTR) => return None,
        NAME_REF => {
            let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap();
            let name_kind = classify_name_ref(sema, &name_ref)?;

            if let NameDefinition::Local(local) = &name_kind {
                if let Some(name) = local.name(db) {
                    let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
                    binding_hash = Some(calc_binding_hash(&name, *shadow_count))
                }
            };

            highlight_name(db, name_kind)
        }

        // Simple token-based highlighting
        COMMENT => HighlightTag::Comment.into(),
        STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => HighlightTag::LiteralString.into(),
        ATTR => HighlightTag::Attribute.into(),
        INT_NUMBER | FLOAT_NUMBER => HighlightTag::LiteralNumeric.into(),
        BYTE => HighlightTag::LiteralByte.into(),
        CHAR => HighlightTag::LiteralChar.into(),
        LIFETIME => HighlightTag::TypeLifetime.into(),

        k if k.is_keyword() => {
            let h = Highlight::new(HighlightTag::Keyword);
            match k {
                T![break]
                | T![continue]
                | T![else]
                | T![for]
                | T![if]
                | T![loop]
                | T![match]
                | T![return]
                | T![while] => h | HighlightModifier::Control,
                T![unsafe] => h | HighlightModifier::Unsafe,
                _ => h,
            }
        }

        _ => return None,
    };

    return Some((highlight, binding_hash));

    fn calc_binding_hash(name: &Name, shadow_count: u32) -> u64 {
        fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 {
            use std::{collections::hash_map::DefaultHasher, hash::Hasher};

            let mut hasher = DefaultHasher::new();
            x.hash(&mut hasher);
            hasher.finish()
        }

        hash((name, shadow_count))
    }
}

fn highlight_name(db: &RootDatabase, def: NameDefinition) -> Highlight {
    match def {
        NameDefinition::Macro(_) => HighlightTag::Macro,
        NameDefinition::StructField(_) => HighlightTag::Field,
        NameDefinition::ModuleDef(def) => match def {
            hir::ModuleDef::Module(_) => HighlightTag::Module,
            hir::ModuleDef::Function(_) => HighlightTag::Function,
            hir::ModuleDef::Adt(_) => HighlightTag::Type,
            hir::ModuleDef::EnumVariant(_) => HighlightTag::Constant,
            hir::ModuleDef::Const(_) => HighlightTag::Constant,
            hir::ModuleDef::Static(_) => HighlightTag::Constant,
            hir::ModuleDef::Trait(_) => HighlightTag::Type,
            hir::ModuleDef::TypeAlias(_) => HighlightTag::Type,
            hir::ModuleDef::BuiltinType(_) => {
                return HighlightTag::Type | HighlightModifier::Builtin
            }
        },
        NameDefinition::SelfType(_) => HighlightTag::TypeSelf,
        NameDefinition::TypeParam(_) => HighlightTag::TypeParam,
        NameDefinition::Local(local) => {
            let mut h = Highlight::new(HighlightTag::Variable);
            if local.is_mut(db) || local.ty(db).is_mutable_reference() {
                h |= HighlightModifier::Mutable;
            }
            return h;
        }
    }
    .into()
}

fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
    let default = HighlightTag::Function.into();

    let parent = match name.syntax().parent() {
        Some(it) => it,
        _ => return default,
    };

    match parent.kind() {
        STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => HighlightTag::Type.into(),
        TYPE_PARAM => HighlightTag::TypeParam.into(),
        RECORD_FIELD_DEF => HighlightTag::Field.into(),
        _ => default,
    }
}

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

    use test_utils::{assert_eq_text, project_dir, read_text};

    use crate::{
        mock_analysis::{single_file, MockAnalysis},
        FileRange, TextRange,
    };

    #[test]
    fn test_highlighting() {
        let (analysis, file_id) = single_file(
            r#"
#[derive(Clone, Debug)]
struct Foo {
    pub x: i32,
    pub y: i32,
}

fn foo<T>() -> T {
    unimplemented!();
    foo::<i32>();
}

macro_rules! def_fn {
    ($($tt:tt)*) => {$($tt)*}
}

def_fn!{
    fn bar() -> u32 {
        100
    }
}

// comment
fn main() {
    println!("Hello, {}!", 92);

    let mut vec = Vec::new();
    if true {
        let x = 92;
        vec.push(Foo { x, y: 1 });
    }
    unsafe { vec.set_len(0); }

    let mut x = 42;
    let y = &mut x;
    let z = &y;

    y;
}

enum E<X> {
    V(X)
}

impl<X> E<X> {
    fn new<T>() -> E<T> {}
}
"#
            .trim(),
        );
        let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlighting.html");
        let actual_html = &analysis.highlight_as_html(file_id, false).unwrap();
        let expected_html = &read_text(&dst_file);
        fs::write(dst_file, &actual_html).unwrap();
        assert_eq_text!(expected_html, actual_html);
    }

    #[test]
    fn test_rainbow_highlighting() {
        let (analysis, file_id) = single_file(
            r#"
fn main() {
    let hello = "hello";
    let x = hello.to_string();
    let y = hello.to_string();

    let x = "other color please!";
    let y = x.to_string();
}

fn bar() {
    let mut hello = "hello";
}
"#
            .trim(),
        );
        let dst_file = project_dir().join("crates/ra_ide/src/snapshots/rainbow_highlighting.html");
        let actual_html = &analysis.highlight_as_html(file_id, true).unwrap();
        let expected_html = &read_text(&dst_file);
        fs::write(dst_file, &actual_html).unwrap();
        assert_eq_text!(expected_html, actual_html);
    }

    #[test]
    fn accidentally_quadratic() {
        let file = project_dir().join("crates/ra_syntax/test_data/accidentally_quadratic");
        let src = fs::read_to_string(file).unwrap();

        let mut mock = MockAnalysis::new();
        let file_id = mock.add_file("/main.rs", &src);
        let host = mock.analysis_host();

        // let t = std::time::Instant::now();
        let _ = host.analysis().highlight(file_id).unwrap();
        // eprintln!("elapsed: {:?}", t.elapsed());
    }

    #[test]
    fn test_ranges() {
        let (analysis, file_id) = single_file(
            r#"
            #[derive(Clone, Debug)]
            struct Foo {
                pub x: i32,
                pub y: i32,
            }"#,
        );

        // The "x"
        let highlights = &analysis
            .highlight_range(FileRange {
                file_id,
                range: TextRange::offset_len(82.into(), 1.into()),
            })
            .unwrap();

        assert_eq!(&highlights[0].highlight.to_string(), "field");
    }
}
<|endoftext|>


<commit_before>
fn main () {
  // dummy
  println!("cargo:rustc-flags=-l sodium");
}<commit_msg>Whitespace changes<commit_after>fn main () {
    println!("cargo:rustc-flags=-l sodium");
}
<|endoftext|>


<commit_before>// Copyright 2019 The Exonum Team
//
// 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.

//! Exonum blockchain explorer API.

use actix::Arbiter;
use actix_web::{http, ws, AsyncResponder, Error as ActixError, FromRequest, Query};
use chrono::{DateTime, Utc};
use exonum_merkledb::{ObjectHash, Snapshot};
use futures::{Future, IntoFuture};
use hex::FromHex;

use std::{
    ops::{Bound, Range},
    sync::{Arc, Mutex},
};

use crate::{
    api::{
        backends::actix::{
            self as actix_backend, FutureResponse, HttpRequest, RawHandler, RequestHandler,
        },
        node::SharedNodeState,
        websocket::{Server, Session, SubscriptionType, TransactionFilter},
        ApiBackend, ApiContext, ApiScope, Error as ApiError,
    },
    blockchain::Block,
    crypto::Hash,
    explorer::{self, median_precommits_time, BlockchainExplorer, TransactionInfo},
    helpers::Height,
    messages::{Precommit, SignedMessage, Verified},
    node::ApiSender,
    runtime::CallInfo,
};

/// The maximum number of blocks to return per blocks request, in this way
/// the parameter limits the maximum execution time for such requests.
pub const MAX_BLOCKS_PER_REQUEST: usize = 1000;

/// Information on blocks coupled with the corresponding range in the blockchain.
#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct BlocksRange {
    /// Exclusive range of blocks.
    pub range: Range<Height>,
    /// Blocks in the range.
    pub blocks: Vec<BlockInfo>,
}

/// Information about a transaction included in the block.
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct TxInfo {
    /// Transaction hash.
    pub tx_hash: Hash,
    /// Information to call.
    pub call_info: CallInfo,
}

/// Information about a block in the blockchain.
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct BlockInfo {
    /// Block header as recorded in the blockchain.
    #[serde(flatten)]
    pub block: Block,

    /// Precommits authorizing the block.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub precommits: Option<Vec<Verified<Precommit>>>,

    /// Info of transactions in the block.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub txs: Option<Vec<TxInfo>>,

    /// Median time from the block precommits.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub time: Option<DateTime<Utc>>,
}

/// Blocks in range parameters.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Default)]
pub struct BlocksQuery {
    /// The number of blocks to return. Should not be greater than `MAX_BLOCKS_PER_REQUEST`.
    pub count: usize,
    /// The maximum height of the returned blocks.
    ///
    /// The blocks are returned in reverse order,
    /// starting from the latest and at least up to the `latest - count + 1`.
    /// The default value is the height of the latest block in the blockchain.
    pub latest: Option<Height>,
    /// The minimum height of the returned blocks. The default value is `Height(0)` (the genesis
    /// block).
    ///
    /// Note that `earliest` has the least priority compared to `latest` and `count`;
    /// it can only truncate the list of otherwise returned blocks if some of them have a lesser
    /// height.
    pub earliest: Option<Height>,
    /// If true, then only non-empty blocks are returned. The default value is false.
    #[serde(default)]
    pub skip_empty_blocks: bool,
    /// If true, then the returned `BlocksRange`'s `times` field will contain median time from the
    /// corresponding blocks precommits.
    #[serde(default)]
    pub add_blocks_time: bool,
    /// If true, then the returned `BlocksRange.precommits` will contain precommits for the
    /// corresponding returned blocks.
    #[serde(default)]
    pub add_precommits: bool,
}

/// Block query parameters.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
pub struct BlockQuery {
    /// The height of the desired block.
    pub height: Height,
}

impl BlockQuery {
    /// Creates a new block query with the given height.
    pub fn new(height: Height) -> Self {
        Self { height }
    }
}

/// Raw Transaction in hex representation.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct TransactionHex {
    /// The hex value of the transaction to be broadcasted.
    pub tx_body: String,
}

/// Transaction response.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
pub struct TransactionResponse {
    /// The hex value of the transaction to be broadcasted.
    pub tx_hash: Hash,
}

/// Transaction query parameters.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
pub struct TransactionQuery {
    /// The hash of the transaction to be searched.
    pub hash: Hash,
}

impl TransactionQuery {
    /// Creates a new transaction query with the given height.
    pub fn new(hash: Hash) -> Self {
        Self { hash }
    }
}

impl AsRef<str> for TransactionHex {
    fn as_ref(&self) -> &str {
        self.tx_body.as_ref()
    }
}

impl AsRef<[u8]> for TransactionHex {
    fn as_ref(&self) -> &[u8] {
        self.tx_body.as_ref()
    }
}

/// Exonum blockchain explorer API.
#[derive(Debug, Clone)]
pub struct ExplorerApi {
    context: ApiContext,
}

impl ExplorerApi {
    /// Create a new `ExplorerApi` instance.
    pub fn new(context: ApiContext) -> Self {
        Self { context }
    }

    /// Return the explored range and the corresponding headers. The range specifies the smallest
    /// and largest heights traversed to collect the number of blocks specified in
    /// the [`BlocksQuery`] struct.
    ///
    /// [`BlocksQuery`]: struct.BlocksQuery.html
    pub fn blocks(snapshot: &dyn Snapshot, query: BlocksQuery) -> Result<BlocksRange, ApiError> {
        let explorer = BlockchainExplorer::new(snapshot);
        if query.count > MAX_BLOCKS_PER_REQUEST {
            return Err(ApiError::BadRequest(format!(
                "Max block count per request exceeded ({})",
                MAX_BLOCKS_PER_REQUEST
            )));
        }

        let (upper, upper_bound) = if let Some(upper) = query.latest {
            if upper > explorer.height() {
                return Err(ApiError::NotFound(format!(
                    "Requested latest height {} is greater than the current blockchain height {}",
                    upper,
                    explorer.height()
                )));
            }
            (upper, Bound::Included(upper))
        } else {
            (explorer.height(), Bound::Unbounded)
        };
        let lower_bound = if let Some(lower) = query.earliest {
            Bound::Included(lower)
        } else {
            Bound::Unbounded
        };

        let blocks: Vec<_> = explorer
            .blocks((lower_bound, upper_bound))
            .rev()
            .filter(|block| !query.skip_empty_blocks || !block.is_empty())
            .take(query.count)
            .map(|block| BlockInfo {
                txs: None,

                time: if query.add_blocks_time {
                    Some(median_precommits_time(&block.precommits()))
                } else {
                    None
                },

                precommits: if query.add_precommits {
                    Some(block.precommits().to_vec())
                } else {
                    None
                },

                block: block.into_header(),
            })
            .collect();

        let height = if blocks.len() < query.count {
            query.earliest.unwrap_or(Height(0))
        } else {
            blocks.last().map_or(Height(0), |info| info.block.height())
        };

        Ok(BlocksRange {
            range: height..upper.next(),
            blocks,
        })
    }

    /// Return the content for a block at a specific height.
    pub fn block(snapshot: &dyn Snapshot, query: BlockQuery) -> Result<BlockInfo, ApiError> {
        BlockchainExplorer::new(snapshot)
            .block(query.height)
            .map(From::from)
            .ok_or_else(|| {
                ApiError::NotFound(format!("Block for height: {} not found", query.height))
            })
    }

    /// Search for a transaction, either committed or uncommitted, by the hash.
    pub fn transaction_info(
        snapshot: &dyn Snapshot,
        query: TransactionQuery,
    ) -> Result<TransactionInfo, ApiError> {
        BlockchainExplorer::new(snapshot)
            .transaction(&query.hash)
            .ok_or_else(|| {
                let description = serde_json::to_string(&json!({ "type": "unknown" })).unwrap();
                ApiError::NotFound(description)
            })
    }

    /// Add transaction into the pool of unconfirmed transactions, and broadcast transaction to other nodes.
    // TODO move this method to the public system API [ECR-3222]
    pub fn add_transaction(
        sender: &ApiSender,
        query: TransactionHex,
    ) -> Result<TransactionResponse, ApiError> {
        let msg = SignedMessage::from_hex(query.tx_body)?;
        let tx_hash = msg.object_hash();
        // FIXME Don't ignore message error.
        let _ = sender
            .broadcast_transaction(msg.into_verified()?)
            .map_err(ApiError::from);
        Ok(TransactionResponse { tx_hash })
    }

    /// Subscribes to events.
    pub fn handle_ws<Q>(
        name: &'static str,
        backend: &mut actix_backend::ApiBuilder,
        context: ApiContext,
        shared_node_state: SharedNodeState,
        extract_query: Q,
    ) where
        Q: Fn(&HttpRequest) -> Result<SubscriptionType, ActixError> + Send + Sync + 'static,
    {
        let server = Arc::new(Mutex::new(None));

        let index = move |request: HttpRequest| -> FutureResponse {
            let server = server.clone();
            let context = context.clone();
            let mut address = server.lock().expect("Expected mutex lock");
            if address.is_none() {
                *address = Some(Arbiter::start(|_| Server::new(context)));

                shared_node_state.set_broadcast_server_address(address.to_owned().unwrap());
            }
            let address = address.to_owned().unwrap();

            extract_query(&request)
                .into_future()
                .from_err()
                .and_then(move |query: SubscriptionType| {
                    ws::start(&request, Session::new(address, vec![query])).into_future()
                })
                .responder()
        };

        backend.raw_handler(RequestHandler {
            name: name.to_owned(),
            method: http::Method::GET,
            inner: Arc::from(index) as Arc<RawHandler>,
        });
    }

    /// Add explorer API endpoints to the corresponding scope.
    pub fn wire(
        self,
        api_scope: &mut ApiScope,
        shared_node_state: SharedNodeState,
    ) -> &mut ApiScope {
        // Default subscription for blocks.
        Self::handle_ws(
            "v1/blocks/subscribe",
            api_scope.web_backend(),
            self.context.clone(),
            shared_node_state.clone(),
            |_| Ok(SubscriptionType::Blocks),
        );
        // Default subscription for transactions.
        Self::handle_ws(
            "v1/transactions/subscribe",
            api_scope.web_backend(),
            self.context.clone(),
            shared_node_state.clone(),
            |request| {
                if request.query().is_empty() {
                    return Ok(SubscriptionType::Transactions { filter: None });
                }

                Query::from_request(request, &Default::default())
                    .map(|query: Query<TransactionFilter>| {
                        Ok(SubscriptionType::Transactions {
                            filter: Some(query.into_inner()),
                        })
                    })
                    .unwrap_or(Ok(SubscriptionType::None))
            },
        );
        // Default websocket connection.
        Self::handle_ws(
            "v1/ws",
            api_scope.web_backend(),
            self.context.clone(),
            shared_node_state,
            |_| Ok(SubscriptionType::None),
        );
        api_scope
            .endpoint("v1/blocks", {
                let context = self.context.clone();
                move |query| Self::blocks(context.snapshot().as_ref(), query)
            })
            .endpoint("v1/block", {
                let context = self.context.clone();
                move |query| Self::block(context.snapshot().as_ref(), query)
            })
            .endpoint("v1/transactions", {
                let context = self.context.clone();
                move |query| Self::transaction_info(context.snapshot().as_ref(), query)
            })
            .endpoint_mut("v1/transactions", {
                let context = self.context.clone();
                move |query| Self::add_transaction(context.sender(), query)
            })
    }
}

impl<'a> From<explorer::BlockInfo<'a>> for BlockInfo {
    fn from(inner: explorer::BlockInfo<'a>) -> Self {
        Self {
            block: inner.header().clone(),
            precommits: Some(inner.precommits().to_vec()),
            txs: Some(
                inner
                    .transaction_hashes()
                    .iter()
                    .enumerate()
                    .map(|(idx, &tx_hash)| TxInfo {
                        tx_hash,
                        call_info: inner
                            .transaction(idx)
                            .unwrap()
                            .content()
                            .payload()
                            .call_info
                            .clone(),
                    })
                    .collect(),
            ),
            time: Some(median_precommits_time(&inner.precommits())),
        }
    }
}
<commit_msg>Make add_transaction handler async (#1489)<commit_after>// Copyright 2019 The Exonum Team
//
// 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.

//! Exonum blockchain explorer API.

use actix::Arbiter;
use actix_web::{http, ws, AsyncResponder, Error as ActixError, FromRequest, Query};
use chrono::{DateTime, Utc};
use exonum_merkledb::{ObjectHash, Snapshot};
use futures::{Future, IntoFuture, Sink};
use hex::FromHex;

use std::{
    ops::{Bound, Range},
    sync::{Arc, Mutex},
};

use crate::{
    api::{
        backends::actix::{
            self as actix_backend, FutureResponse, HttpRequest, RawHandler, RequestHandler,
        },
        node::SharedNodeState,
        websocket::{Server, Session, SubscriptionType, TransactionFilter},
        ApiBackend, ApiContext, ApiScope, Error as ApiError, FutureResult,
    },
    blockchain::Block,
    crypto::Hash,
    explorer::{self, median_precommits_time, BlockchainExplorer, TransactionInfo},
    helpers::Height,
    messages::{Precommit, SignedMessage, Verified},
    node::{ApiSender, ExternalMessage},
    runtime::CallInfo,
};

/// The maximum number of blocks to return per blocks request, in this way
/// the parameter limits the maximum execution time for such requests.
pub const MAX_BLOCKS_PER_REQUEST: usize = 1000;

/// Information on blocks coupled with the corresponding range in the blockchain.
#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct BlocksRange {
    /// Exclusive range of blocks.
    pub range: Range<Height>,
    /// Blocks in the range.
    pub blocks: Vec<BlockInfo>,
}

/// Information about a transaction included in the block.
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct TxInfo {
    /// Transaction hash.
    pub tx_hash: Hash,
    /// Information to call.
    pub call_info: CallInfo,
}

/// Information about a block in the blockchain.
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct BlockInfo {
    /// Block header as recorded in the blockchain.
    #[serde(flatten)]
    pub block: Block,

    /// Precommits authorizing the block.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub precommits: Option<Vec<Verified<Precommit>>>,

    /// Info of transactions in the block.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub txs: Option<Vec<TxInfo>>,

    /// Median time from the block precommits.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub time: Option<DateTime<Utc>>,
}

/// Blocks in range parameters.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Default)]
pub struct BlocksQuery {
    /// The number of blocks to return. Should not be greater than `MAX_BLOCKS_PER_REQUEST`.
    pub count: usize,
    /// The maximum height of the returned blocks.
    ///
    /// The blocks are returned in reverse order,
    /// starting from the latest and at least up to the `latest - count + 1`.
    /// The default value is the height of the latest block in the blockchain.
    pub latest: Option<Height>,
    /// The minimum height of the returned blocks. The default value is `Height(0)` (the genesis
    /// block).
    ///
    /// Note that `earliest` has the least priority compared to `latest` and `count`;
    /// it can only truncate the list of otherwise returned blocks if some of them have a lesser
    /// height.
    pub earliest: Option<Height>,
    /// If true, then only non-empty blocks are returned. The default value is false.
    #[serde(default)]
    pub skip_empty_blocks: bool,
    /// If true, then the returned `BlocksRange`'s `times` field will contain median time from the
    /// corresponding blocks precommits.
    #[serde(default)]
    pub add_blocks_time: bool,
    /// If true, then the returned `BlocksRange.precommits` will contain precommits for the
    /// corresponding returned blocks.
    #[serde(default)]
    pub add_precommits: bool,
}

/// Block query parameters.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
pub struct BlockQuery {
    /// The height of the desired block.
    pub height: Height,
}

impl BlockQuery {
    /// Creates a new block query with the given height.
    pub fn new(height: Height) -> Self {
        Self { height }
    }
}

/// Raw Transaction in hex representation.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct TransactionHex {
    /// The hex value of the transaction to be broadcasted.
    pub tx_body: String,
}

/// Transaction response.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
pub struct TransactionResponse {
    /// The hex value of the transaction to be broadcasted.
    pub tx_hash: Hash,
}

/// Transaction query parameters.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
pub struct TransactionQuery {
    /// The hash of the transaction to be searched.
    pub hash: Hash,
}

impl TransactionQuery {
    /// Creates a new transaction query with the given height.
    pub fn new(hash: Hash) -> Self {
        Self { hash }
    }
}

impl AsRef<str> for TransactionHex {
    fn as_ref(&self) -> &str {
        self.tx_body.as_ref()
    }
}

impl AsRef<[u8]> for TransactionHex {
    fn as_ref(&self) -> &[u8] {
        self.tx_body.as_ref()
    }
}

/// Exonum blockchain explorer API.
#[derive(Debug, Clone)]
pub struct ExplorerApi {
    context: ApiContext,
}

impl ExplorerApi {
    /// Create a new `ExplorerApi` instance.
    pub fn new(context: ApiContext) -> Self {
        Self { context }
    }

    /// Return the explored range and the corresponding headers. The range specifies the smallest
    /// and largest heights traversed to collect the number of blocks specified in
    /// the [`BlocksQuery`] struct.
    ///
    /// [`BlocksQuery`]: struct.BlocksQuery.html
    pub fn blocks(snapshot: &dyn Snapshot, query: BlocksQuery) -> Result<BlocksRange, ApiError> {
        let explorer = BlockchainExplorer::new(snapshot);
        if query.count > MAX_BLOCKS_PER_REQUEST {
            return Err(ApiError::BadRequest(format!(
                "Max block count per request exceeded ({})",
                MAX_BLOCKS_PER_REQUEST
            )));
        }

        let (upper, upper_bound) = if let Some(upper) = query.latest {
            if upper > explorer.height() {
                return Err(ApiError::NotFound(format!(
                    "Requested latest height {} is greater than the current blockchain height {}",
                    upper,
                    explorer.height()
                )));
            }
            (upper, Bound::Included(upper))
        } else {
            (explorer.height(), Bound::Unbounded)
        };
        let lower_bound = if let Some(lower) = query.earliest {
            Bound::Included(lower)
        } else {
            Bound::Unbounded
        };

        let blocks: Vec<_> = explorer
            .blocks((lower_bound, upper_bound))
            .rev()
            .filter(|block| !query.skip_empty_blocks || !block.is_empty())
            .take(query.count)
            .map(|block| BlockInfo {
                txs: None,

                time: if query.add_blocks_time {
                    Some(median_precommits_time(&block.precommits()))
                } else {
                    None
                },

                precommits: if query.add_precommits {
                    Some(block.precommits().to_vec())
                } else {
                    None
                },

                block: block.into_header(),
            })
            .collect();

        let height = if blocks.len() < query.count {
            query.earliest.unwrap_or(Height(0))
        } else {
            blocks.last().map_or(Height(0), |info| info.block.height())
        };

        Ok(BlocksRange {
            range: height..upper.next(),
            blocks,
        })
    }

    /// Return the content for a block at a specific height.
    pub fn block(snapshot: &dyn Snapshot, query: BlockQuery) -> Result<BlockInfo, ApiError> {
        BlockchainExplorer::new(snapshot)
            .block(query.height)
            .map(From::from)
            .ok_or_else(|| {
                ApiError::NotFound(format!("Block for height: {} not found", query.height))
            })
    }

    /// Search for a transaction, either committed or uncommitted, by the hash.
    pub fn transaction_info(
        snapshot: &dyn Snapshot,
        query: TransactionQuery,
    ) -> Result<TransactionInfo, ApiError> {
        BlockchainExplorer::new(snapshot)
            .transaction(&query.hash)
            .ok_or_else(|| {
                let description = serde_json::to_string(&json!({ "type": "unknown" })).unwrap();
                ApiError::NotFound(description)
            })
    }

    /// Add transaction into the pool of unconfirmed transactions, and broadcast transaction to other nodes.
    // TODO move this method to the public system API [ECR-3222]
    pub fn add_transaction(
        sender: &ApiSender,
        query: TransactionHex,
    ) -> FutureResult<TransactionResponse> {
        let verify_message = |hex: String| -> Result<_, failure::Error> {
            let msg = SignedMessage::from_hex(hex)?;
            let tx_hash = msg.object_hash();
            let verified = msg.into_verified()?;
            Ok((verified, tx_hash))
        };

        let sender = sender.clone();
        let send_transaction = move |(verified, tx_hash)| {
            sender
                .clone()
                .0
                .send(ExternalMessage::Transaction(verified))
                .map(move |_| TransactionResponse { tx_hash })
                .map_err(|e| ApiError::InternalError(e.into()))
        };

        Box::new(
            verify_message(query.tx_body)
                .into_future()
                .map_err(|e| ApiError::BadRequest(e.to_string()))
                .and_then(send_transaction),
        )
    }

    /// Subscribes to events.
    pub fn handle_ws<Q>(
        name: &'static str,
        backend: &mut actix_backend::ApiBuilder,
        context: ApiContext,
        shared_node_state: SharedNodeState,
        extract_query: Q,
    ) where
        Q: Fn(&HttpRequest) -> Result<SubscriptionType, ActixError> + Send + Sync + 'static,
    {
        let server = Arc::new(Mutex::new(None));

        let index = move |request: HttpRequest| -> FutureResponse {
            let server = server.clone();
            let context = context.clone();
            let mut address = server.lock().expect("Expected mutex lock");
            if address.is_none() {
                *address = Some(Arbiter::start(|_| Server::new(context)));

                shared_node_state.set_broadcast_server_address(address.to_owned().unwrap());
            }
            let address = address.to_owned().unwrap();

            extract_query(&request)
                .into_future()
                .from_err()
                .and_then(move |query: SubscriptionType| {
                    ws::start(&request, Session::new(address, vec![query])).into_future()
                })
                .responder()
        };

        backend.raw_handler(RequestHandler {
            name: name.to_owned(),
            method: http::Method::GET,
            inner: Arc::from(index) as Arc<RawHandler>,
        });
    }

    /// Add explorer API endpoints to the corresponding scope.
    pub fn wire(
        self,
        api_scope: &mut ApiScope,
        shared_node_state: SharedNodeState,
    ) -> &mut ApiScope {
        // Default subscription for blocks.
        Self::handle_ws(
            "v1/blocks/subscribe",
            api_scope.web_backend(),
            self.context.clone(),
            shared_node_state.clone(),
            |_| Ok(SubscriptionType::Blocks),
        );
        // Default subscription for transactions.
        Self::handle_ws(
            "v1/transactions/subscribe",
            api_scope.web_backend(),
            self.context.clone(),
            shared_node_state.clone(),
            |request| {
                if request.query().is_empty() {
                    return Ok(SubscriptionType::Transactions { filter: None });
                }

                Query::from_request(request, &Default::default())
                    .map(|query: Query<TransactionFilter>| {
                        Ok(SubscriptionType::Transactions {
                            filter: Some(query.into_inner()),
                        })
                    })
                    .unwrap_or(Ok(SubscriptionType::None))
            },
        );
        // Default websocket connection.
        Self::handle_ws(
            "v1/ws",
            api_scope.web_backend(),
            self.context.clone(),
            shared_node_state,
            |_| Ok(SubscriptionType::None),
        );
        api_scope
            .endpoint("v1/blocks", {
                let context = self.context.clone();
                move |query| Self::blocks(context.snapshot().as_ref(), query)
            })
            .endpoint("v1/block", {
                let context = self.context.clone();
                move |query| Self::block(context.snapshot().as_ref(), query)
            })
            .endpoint("v1/transactions", {
                let context = self.context.clone();
                move |query| Self::transaction_info(context.snapshot().as_ref(), query)
            })
            .endpoint_mut("v1/transactions", {
                let context = self.context.clone();
                move |query| Self::add_transaction(context.sender(), query)
            })
    }
}

impl<'a> From<explorer::BlockInfo<'a>> for BlockInfo {
    fn from(inner: explorer::BlockInfo<'a>) -> Self {
        Self {
            block: inner.header().clone(),
            precommits: Some(inner.precommits().to_vec()),
            txs: Some(
                inner
                    .transaction_hashes()
                    .iter()
                    .enumerate()
                    .map(|(idx, &tx_hash)| TxInfo {
                        tx_hash,
                        call_info: inner
                            .transaction(idx)
                            .unwrap()
                            .content()
                            .payload()
                            .call_info
                            .clone(),
                    })
                    .collect(),
            ),
            time: Some(median_precommits_time(&inner.precommits())),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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
//
//    https://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.

mod function_wrapper_cpp;
pub(crate) mod type_to_cpp;

use crate::{conversion::analysis::fun::FnAnalysisBody, types::QualifiedName, CppFilePair};
use autocxx_parser::IncludeCppConfig;
use itertools::Itertools;
use std::collections::HashSet;
use type_to_cpp::{original_name_map_from_apis, type_to_cpp, CppNameMap};

use super::{
    analysis::fun::{
        function_wrapper::{FunctionWrapper, FunctionWrapperPayload},
        FnAnalysis,
    },
    api::Api,
    ConvertError,
};

#[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Hash)]
struct Header {
    name: &'static str,
    system: bool,
}

impl Header {
    fn system(name: &'static str) -> Self {
        Header { name, system: true }
    }

    fn user(name: &'static str) -> Self {
        Header {
            name,
            system: false,
        }
    }

    fn include_stmt(&self) -> String {
        if self.system {
            format!("#include <{}>", self.name)
        } else {
            format!("#include \"{}\"", self.name)
        }
    }
}

struct AdditionalFunction {
    type_definition: Option<String>, // are output before main declarations
    declaration: Option<String>,
    definition: Option<String>,
    headers: Vec<Header>,
}

/// Generates additional C++ glue functions needed by autocxx.
/// In some ways it would be preferable to be able to pass snippets
/// of C++ through to `cxx` for inclusion in the C++ file which it
/// generates, and perhaps we'll explore that in future. But for now,
/// autocxx generates its own _additional_ C++ files which therefore
/// need to be built and included in linking procedures.
pub(crate) struct CppCodeGenerator<'a> {
    additional_functions: Vec<AdditionalFunction>,
    inclusions: String,
    original_name_map: CppNameMap,
    config: &'a IncludeCppConfig,
}

impl<'a> CppCodeGenerator<'a> {
    pub(crate) fn generate_cpp_code(
        inclusions: String,
        apis: &[Api<FnAnalysis>],
        config: &'a IncludeCppConfig,
    ) -> Result<Option<CppFilePair>, ConvertError> {
        let mut gen = CppCodeGenerator::new(inclusions, original_name_map_from_apis(apis), config);
        // The 'filter' on the following line is designed to ensure we don't accidentally
        // end up out of sync with needs_cpp_codegen
        gen.add_needs(apis.iter().filter(|api| api.needs_cpp_codegen()))?;
        Ok(gen.generate())
    }

    fn new(
        inclusions: String,
        original_name_map: CppNameMap,
        config: &'a IncludeCppConfig,
    ) -> Self {
        CppCodeGenerator {
            additional_functions: Vec::new(),
            inclusions,
            original_name_map,
            config,
        }
    }

    // It's important to keep this in sync with Api::needs_cpp_codegen.
    fn add_needs<'b>(
        &mut self,
        apis: impl Iterator<Item = &'a Api<FnAnalysis>>,
    ) -> Result<(), ConvertError> {
        for api in apis {
            match &api {
                Api::StringConstructor { .. } => self.generate_string_constructor(),
                Api::Function {
                    analysis:
                        FnAnalysisBody {
                            cpp_wrapper: Some(cpp_wrapper),
                            ..
                        },
                    ..
                } => self.generate_by_value_wrapper(cpp_wrapper)?,
                Api::ConcreteType { rs_definition, .. } => self.generate_typedef(
                    api.name(),
                    type_to_cpp(rs_definition, &self.original_name_map)?,
                ),
                Api::CType { typename, .. } => self.generate_ctype_typedef(typename),
                _ => panic!("Should have filtered on needs_cpp_codegen"),
            }
        }
        Ok(())
    }

    fn generate(&self) -> Option<CppFilePair> {
        if self.additional_functions.is_empty() {
            None
        } else {
            let headers: HashSet<Header> = self
                .additional_functions
                .iter()
                .map(|x| x.headers.iter().cloned())
                .flatten()
                .collect();
            let headers = headers.iter().map(|x| x.include_stmt()).join("\n");
            let type_definitions = self.concat_additional_items(|x| x.type_definition.as_ref());
            let declarations = self.concat_additional_items(|x| x.declaration.as_ref());
            let declarations = format!(
                "#ifndef __AUTOCXXGEN_H__\n#define __AUTOCXXGEN_H__\n\n{}\n{}\n{}\n{}#endif // __AUTOCXXGEN_H__\n",
                headers, self.inclusions, type_definitions, declarations
            );
            let definitions = self.concat_additional_items(|x| x.definition.as_ref());
            log::info!("Additional C++ decls:\n{}", declarations);
            let header_name = format!("autocxxgen_{}.h", self.config.get_mod_name());
            let definitions = format!("#include \"{}\"\n{}", header_name, definitions);
            log::info!("Additional C++ defs:\n{}", definitions);
            Some(CppFilePair {
                header: declarations.into_bytes(),
                implementation: definitions.into_bytes(),
                header_name,
            })
        }
    }

    fn concat_additional_items<F>(&self, field_access: F) -> String
    where
        F: FnMut(&AdditionalFunction) -> Option<&String>,
    {
        let mut s = self
            .additional_functions
            .iter()
            .map(field_access)
            .flatten()
            .join("\n");
        s.push('\n');
        s
    }

    fn generate_string_constructor(&mut self) {
        let makestring_name = self.config.get_makestring_name();
        let declaration = format!(
            "std::unique_ptr<std::string> {}(::rust::Str str)",
            makestring_name
        );
        let definition = Some(format!(
            "{} {{ return std::make_unique<std::string>(std::string(str)); }}",
            declaration
        ));
        let declaration = Some(format!("{};", declaration));
        self.additional_functions.push(AdditionalFunction {
            type_definition: None,
            declaration,
            definition,
            headers: vec![
                Header::system("memory"),
                Header::system("string"),
                Header::user("cxx.h"),
            ],
        })
    }

    fn generate_by_value_wrapper(&mut self, details: &FunctionWrapper) -> Result<(), ConvertError> {
        // Even if the original function call is in a namespace,
        // we generate this wrapper in the global namespace.
        // We could easily do this the other way round, and when
        // cxx::bridge comes to support nested namespace mods then
        // we wil wish to do that to avoid name conflicts. However,
        // at the moment this is simpler because it avoids us having
        // to generate namespace blocks in the generated C++.
        let is_a_method = details.is_a_method;
        let name = &details.wrapper_function_name;
        let get_arg_name = |counter: usize| -> String {
            if is_a_method && counter == 0 {
                // For method calls that we generate, the first
                // argument name needs to be such that we recognize
                // it as a method in the second invocation of
                // bridge_converter after it's flowed again through
                // bindgen.
                // TODO this may not be the case any longer. We
                // may be able to remove this.
                "autocxx_gen_this".to_string()
            } else {
                format!("arg{}", counter)
            }
        };
        let args: Result<Vec<_>, _> = details
            .argument_conversion
            .iter()
            .enumerate()
            .map(|(counter, ty)| {
                Ok(format!(
                    "{} {}",
                    ty.unconverted_type(&self.original_name_map)?,
                    get_arg_name(counter)
                ))
            })
            .collect();
        let args = args?.join(", ");
        let ret_type = details
            .return_conversion
            .as_ref()
            .map_or(Ok("void".to_string()), |x| {
                x.converted_type(&self.original_name_map)
            })?;
        let declaration = format!("{} {}({})", ret_type, name, args);
        let arg_list: Result<Vec<_>, _> = details
            .argument_conversion
            .iter()
            .enumerate()
            .map(|(counter, conv)| {
                conv.cpp_conversion(&get_arg_name(counter), &self.original_name_map)
            })
            .collect();
        let mut arg_list = arg_list?.into_iter();
        let receiver = if is_a_method { arg_list.next() } else { None };
        let arg_list = arg_list.join(", ");
        let mut underlying_function_call = match &details.payload {
            FunctionWrapperPayload::Constructor => arg_list,
            FunctionWrapperPayload::FunctionCall(ns, id) => match receiver {
                Some(receiver) => format!("{}.{}({})", receiver, id.to_string(), arg_list),
                None => {
                    let underlying_function_call = ns
                        .into_iter()
                        .cloned()
                        .chain(std::iter::once(id.to_string()))
                        .join("::");
                    format!("{}({})", underlying_function_call, arg_list)
                }
            },
            FunctionWrapperPayload::StaticMethodCall(ns, ty_id, fn_id) => {
                let underlying_function_call = ns
                    .into_iter()
                    .cloned()
                    .chain([ty_id.to_string(), fn_id.to_string()].iter().cloned())
                    .join("::");
                format!("{}({})", underlying_function_call, arg_list)
            }
        };
        if let Some(ret) = &details.return_conversion {
            underlying_function_call = format!(
                "return {}",
                ret.cpp_conversion(&underlying_function_call, &self.original_name_map)?
            );
        };
        let definition = Some(format!(
            "{} {{ {}; }}",
            declaration, underlying_function_call,
        ));
        let declaration = Some(format!("{};", declaration));
        self.additional_functions.push(AdditionalFunction {
            type_definition: None,
            declaration,
            definition,
            headers: vec![Header::system("memory")],
        });
        Ok(())
    }

    fn generate_ctype_typedef(&mut self, tn: &QualifiedName) {
        let cpp_name = tn.to_cpp_name();
        self.generate_typedef(tn, cpp_name)
    }

    fn generate_typedef(&mut self, tn: &QualifiedName, definition: String) {
        let our_name = tn.get_final_item();
        self.additional_functions.push(AdditionalFunction {
            type_definition: Some(format!("typedef {} {};", definition, our_name)),
            declaration: None,
            definition: None,
            headers: Vec::new(),
        })
    }
}
<commit_msg>Re-inline makestring<commit_after>// Copyright 2020 Google LLC
//
// 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
//
//    https://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.

mod function_wrapper_cpp;
pub(crate) mod type_to_cpp;

use crate::{conversion::analysis::fun::FnAnalysisBody, types::QualifiedName, CppFilePair};
use autocxx_parser::IncludeCppConfig;
use itertools::Itertools;
use std::collections::HashSet;
use type_to_cpp::{original_name_map_from_apis, type_to_cpp, CppNameMap};

use super::{
    analysis::fun::{
        function_wrapper::{FunctionWrapper, FunctionWrapperPayload},
        FnAnalysis,
    },
    api::Api,
    ConvertError,
};

#[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Hash)]
struct Header {
    name: &'static str,
    system: bool,
}

impl Header {
    fn system(name: &'static str) -> Self {
        Header { name, system: true }
    }

    fn user(name: &'static str) -> Self {
        Header {
            name,
            system: false,
        }
    }

    fn include_stmt(&self) -> String {
        if self.system {
            format!("#include <{}>", self.name)
        } else {
            format!("#include \"{}\"", self.name)
        }
    }
}

struct AdditionalFunction {
    type_definition: Option<String>, // are output before main declarations
    declaration: Option<String>,
    definition: Option<String>,
    headers: Vec<Header>,
}

/// Generates additional C++ glue functions needed by autocxx.
/// In some ways it would be preferable to be able to pass snippets
/// of C++ through to `cxx` for inclusion in the C++ file which it
/// generates, and perhaps we'll explore that in future. But for now,
/// autocxx generates its own _additional_ C++ files which therefore
/// need to be built and included in linking procedures.
pub(crate) struct CppCodeGenerator<'a> {
    additional_functions: Vec<AdditionalFunction>,
    inclusions: String,
    original_name_map: CppNameMap,
    config: &'a IncludeCppConfig,
}

impl<'a> CppCodeGenerator<'a> {
    pub(crate) fn generate_cpp_code(
        inclusions: String,
        apis: &[Api<FnAnalysis>],
        config: &'a IncludeCppConfig,
    ) -> Result<Option<CppFilePair>, ConvertError> {
        let mut gen = CppCodeGenerator::new(inclusions, original_name_map_from_apis(apis), config);
        // The 'filter' on the following line is designed to ensure we don't accidentally
        // end up out of sync with needs_cpp_codegen
        gen.add_needs(apis.iter().filter(|api| api.needs_cpp_codegen()))?;
        Ok(gen.generate())
    }

    fn new(
        inclusions: String,
        original_name_map: CppNameMap,
        config: &'a IncludeCppConfig,
    ) -> Self {
        CppCodeGenerator {
            additional_functions: Vec::new(),
            inclusions,
            original_name_map,
            config,
        }
    }

    // It's important to keep this in sync with Api::needs_cpp_codegen.
    fn add_needs<'b>(
        &mut self,
        apis: impl Iterator<Item = &'a Api<FnAnalysis>>,
    ) -> Result<(), ConvertError> {
        for api in apis {
            match &api {
                Api::StringConstructor { .. } => self.generate_string_constructor(),
                Api::Function {
                    analysis:
                        FnAnalysisBody {
                            cpp_wrapper: Some(cpp_wrapper),
                            ..
                        },
                    ..
                } => self.generate_by_value_wrapper(cpp_wrapper)?,
                Api::ConcreteType { rs_definition, .. } => self.generate_typedef(
                    api.name(),
                    type_to_cpp(rs_definition, &self.original_name_map)?,
                ),
                Api::CType { typename, .. } => self.generate_ctype_typedef(typename),
                _ => panic!("Should have filtered on needs_cpp_codegen"),
            }
        }
        Ok(())
    }

    fn generate(&self) -> Option<CppFilePair> {
        if self.additional_functions.is_empty() {
            None
        } else {
            let headers: HashSet<Header> = self
                .additional_functions
                .iter()
                .map(|x| x.headers.iter().cloned())
                .flatten()
                .collect();
            let headers = headers.iter().map(|x| x.include_stmt()).join("\n");
            let type_definitions = self.concat_additional_items(|x| x.type_definition.as_ref());
            let declarations = self.concat_additional_items(|x| x.declaration.as_ref());
            let declarations = format!(
                "#ifndef __AUTOCXXGEN_H__\n#define __AUTOCXXGEN_H__\n\n{}\n{}\n{}\n{}#endif // __AUTOCXXGEN_H__\n",
                headers, self.inclusions, type_definitions, declarations
            );
            let definitions = self.concat_additional_items(|x| x.definition.as_ref());
            log::info!("Additional C++ decls:\n{}", declarations);
            let header_name = format!("autocxxgen_{}.h", self.config.get_mod_name());
            let definitions = format!("#include \"{}\"\n{}", header_name, definitions);
            log::info!("Additional C++ defs:\n{}", definitions);
            Some(CppFilePair {
                header: declarations.into_bytes(),
                implementation: definitions.into_bytes(),
                header_name,
            })
        }
    }

    fn concat_additional_items<F>(&self, field_access: F) -> String
    where
        F: FnMut(&AdditionalFunction) -> Option<&String>,
    {
        let mut s = self
            .additional_functions
            .iter()
            .map(field_access)
            .flatten()
            .join("\n");
        s.push('\n');
        s
    }

    fn generate_string_constructor(&mut self) {
        let makestring_name = self.config.get_makestring_name();
        let declaration = Some(format!("inline std::unique_ptr<std::string> {}(::rust::Str str) {{ return std::make_unique<std::string>(std::string(str)); }}", makestring_name));
        self.additional_functions.push(AdditionalFunction {
            type_definition: None,
            declaration,
            definition: None,
            headers: vec![
                Header::system("memory"),
                Header::system("string"),
                Header::user("cxx.h"),
            ],
        })
    }

    fn generate_by_value_wrapper(&mut self, details: &FunctionWrapper) -> Result<(), ConvertError> {
        // Even if the original function call is in a namespace,
        // we generate this wrapper in the global namespace.
        // We could easily do this the other way round, and when
        // cxx::bridge comes to support nested namespace mods then
        // we wil wish to do that to avoid name conflicts. However,
        // at the moment this is simpler because it avoids us having
        // to generate namespace blocks in the generated C++.
        let is_a_method = details.is_a_method;
        let name = &details.wrapper_function_name;
        let get_arg_name = |counter: usize| -> String {
            if is_a_method && counter == 0 {
                // For method calls that we generate, the first
                // argument name needs to be such that we recognize
                // it as a method in the second invocation of
                // bridge_converter after it's flowed again through
                // bindgen.
                // TODO this may not be the case any longer. We
                // may be able to remove this.
                "autocxx_gen_this".to_string()
            } else {
                format!("arg{}", counter)
            }
        };
        let args: Result<Vec<_>, _> = details
            .argument_conversion
            .iter()
            .enumerate()
            .map(|(counter, ty)| {
                Ok(format!(
                    "{} {}",
                    ty.unconverted_type(&self.original_name_map)?,
                    get_arg_name(counter)
                ))
            })
            .collect();
        let args = args?.join(", ");
        let ret_type = details
            .return_conversion
            .as_ref()
            .map_or(Ok("void".to_string()), |x| {
                x.converted_type(&self.original_name_map)
            })?;
        let declaration = format!("{} {}({})", ret_type, name, args);
        let arg_list: Result<Vec<_>, _> = details
            .argument_conversion
            .iter()
            .enumerate()
            .map(|(counter, conv)| {
                conv.cpp_conversion(&get_arg_name(counter), &self.original_name_map)
            })
            .collect();
        let mut arg_list = arg_list?.into_iter();
        let receiver = if is_a_method { arg_list.next() } else { None };
        let arg_list = arg_list.join(", ");
        let mut underlying_function_call = match &details.payload {
            FunctionWrapperPayload::Constructor => arg_list,
            FunctionWrapperPayload::FunctionCall(ns, id) => match receiver {
                Some(receiver) => format!("{}.{}({})", receiver, id.to_string(), arg_list),
                None => {
                    let underlying_function_call = ns
                        .into_iter()
                        .cloned()
                        .chain(std::iter::once(id.to_string()))
                        .join("::");
                    format!("{}({})", underlying_function_call, arg_list)
                }
            },
            FunctionWrapperPayload::StaticMethodCall(ns, ty_id, fn_id) => {
                let underlying_function_call = ns
                    .into_iter()
                    .cloned()
                    .chain([ty_id.to_string(), fn_id.to_string()].iter().cloned())
                    .join("::");
                format!("{}({})", underlying_function_call, arg_list)
            }
        };
        if let Some(ret) = &details.return_conversion {
            underlying_function_call = format!(
                "return {}",
                ret.cpp_conversion(&underlying_function_call, &self.original_name_map)?
            );
        };
        let definition = Some(format!(
            "{} {{ {}; }}",
            declaration, underlying_function_call,
        ));
        let declaration = Some(format!("{};", declaration));
        self.additional_functions.push(AdditionalFunction {
            type_definition: None,
            declaration,
            definition,
            headers: vec![Header::system("memory")],
        });
        Ok(())
    }

    fn generate_ctype_typedef(&mut self, tn: &QualifiedName) {
        let cpp_name = tn.to_cpp_name();
        self.generate_typedef(tn, cpp_name)
    }

    fn generate_typedef(&mut self, tn: &QualifiedName, definition: String) {
        let our_name = tn.get_final_item();
        self.additional_functions.push(AdditionalFunction {
            type_definition: Some(format!("typedef {} {};", definition, our_name)),
            declaration: None,
            definition: None,
            headers: Vec::new(),
        })
    }
}
<|endoftext|>


<commit_before>use std::env;

use serenity::{
    model::{channel::Message, gateway::Ready},
    prelude::*,
};

struct Handler;

impl EventHandler for Handler {
    fn message(&self, context: Context, msg: Message) {
        if msg.content == "!messageme" {
            // If the `methods` feature is enabled, then model structs will
            // have a lot of useful methods implemented, to avoid using an
            // often otherwise bulky Context, or even much lower-level `rest`
            // method.
            //
            // In this case, you can direct message a User directly by simply
            // calling a method on its instance, with the content of the
            // message.
            let dm = msg.author.dm(&context, |m| {
                m.content("Hello!");

                m
            });

            if let Err(why) = dm {
                println!("Error when direct messaging user: {:?}", why);
            }
        }
    }

    fn ready(&self, _: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
    }
}

fn main() {
    // Configure the client with your Discord bot token in the environment.
    let token = env::var("DISCORD_TOKEN")
        .expect("Expected a token in the environment");
    let mut client = Client::new(&token, Handler).expect("Err creating client");

    if let Err(why) = client.start() {
        println!("Client error: {:?}", why);
    }
}
<commit_msg>Update the mentioned feature `methods` to `utils`. (#560)<commit_after>use std::env;

use serenity::{
    model::{channel::Message, gateway::Ready},
    prelude::*,
};

struct Handler;

impl EventHandler for Handler {
    fn message(&self, context: Context, msg: Message) {
        if msg.content == "!messageme" {
            // If the `utils`-feature is enabled, then model structs will
            // have a lot of useful methods implemented, to avoid using an
            // often otherwise bulky Context, or even much lower-level `rest`
            // method.
            //
            // In this case, you can direct message a User directly by simply
            // calling a method on its instance, with the content of the
            // message.
            let dm = msg.author.dm(&context, |m| {
                m.content("Hello!");

                m
            });

            if let Err(why) = dm {
                println!("Error when direct messaging user: {:?}", why);
            }
        }
    }

    fn ready(&self, _: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
    }
}

fn main() {
    // Configure the client with your Discord bot token in the environment.
    let token = env::var("DISCORD_TOKEN")
        .expect("Expected a token in the environment");
    let mut client = Client::new(&token, Handler).expect("Err creating client");

    if let Err(why) = client.start() {
        println!("Client error: {:?}", why);
    }
}
<|endoftext|>


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

use std::process::Command;

fn assert_that_version_control_has_no_unstaged_changes() {
    let output = Command::new("git")
        .arg("status")
        .arg("--porcelain")
        .output()
        .unwrap();
    assert!(
        output.stdout.is_empty(),
        format!(
            "Git repository should be in a clean state, but found:\n{}",
            std::str::from_utf8(&output.stdout).unwrap_or("<binary>")
        )
    );
    assert!(output.status.success());
}

#[test]
fn test_that_generated_file_are_up_to_date_in_git() {
    // Better not run the `stdlib` tool when the repository is not in a clean state.
    assert_that_version_control_has_no_unstaged_changes();

    assert!(Command::new("cargo")
        .current_dir("../..")
        .arg("run")
        .arg("--release")
        .arg("-p")
        .arg("stdlib")
        .status()
        .unwrap()
        .success());

    // Running the stdlib tool should not create unstaged changes.
    assert_that_version_control_has_no_unstaged_changes();
}
<commit_msg>remove git test from Rust<commit_after><|endoftext|>


<commit_before>use luminance::{Dim2, Flat, Framebuffer, Mode, Pipe, Pipeline, RGBA32F, RawTexture, RenderCommand,
                ShadingCommand, Tess, TessRender, Texture, Unit, Uniform};

use resource::Res;
use scene::Scene;
use shader::Program;

pub type Texture2D<A> = Texture<Flat, Dim2, A>;

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

pub struct Forward {
  program: Res<Program>,
  quad: Tess,
  w: u32,
  h: u32
}

impl Forward {
  pub fn new(w: u32, h: u32, scene: &mut Scene) -> Self {
    let program = scene.get("spectra/compositors/forward.glsl", vec![FORWARD_SOURCE.sem("source")]).unwrap();

    Forward {
      program: program,
      quad: Tess::attributeless(Mode::TriangleStrip, 4),
      w: w,
      h: h
    }
  }

  pub fn to_screen(&self, source: &Texture2D<RGBA32F>) {
    let back_fb = Framebuffer::default((self.w, self.h));
    let textures: &[&RawTexture] = &[source];
    let tess_render = TessRender::one_whole(&self.quad);

    Pipeline::new(&back_fb, [0., 0., 0., 0.], textures, &[], vec![
      Pipe::empty()
        .uniforms(&[FORWARD_SOURCE.alter(Unit::new(0))])
        .unwrap(ShadingCommand::new(&self.program.borrow(), vec![
          Pipe::new(RenderCommand::new(None, true, vec![
            Pipe::new(tess_render)]))
          ]))
    ]).run();
  }

  pub fn black_screen(&self) {
    let back_fb = Framebuffer::default((self.w, self.h));
    Pipeline::new(&back_fb, [0., 0., 0., 0.], &[], &[], vec![]).run();
  }
}
<commit_msg>Simplified the Forward compositor.<commit_after>use luminance::{Dim2, Flat, Framebuffer, Mode, Pipe, Pipeline, RGBA32F, RawTexture, RenderCommand,
                ShadingCommand, Tess, TessRender, Texture, Unit, Uniform};

use resource::Res;
use scene::Scene;
use shader::Program;

pub type Texture2D<A> = Texture<Flat, Dim2, A>;

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

pub struct Forward {
  framebuffer: Framebuffer<Flat, Dim2, (), ()>,
  program: Res<Program>,
  quad: Tess
}

impl Forward {
  pub fn new(w: u32, h: u32, scene: &mut Scene) -> Self {
    let program = scene.get("spectra/compositors/forward.glsl", vec![FORWARD_SOURCE.sem("source")]).unwrap();

    Forward {
      framebuffer: Framebuffer::default((w, h)),
      program: program,
      quad: Tess::attributeless(Mode::TriangleStrip, 4),
    }
  }

  pub fn to_screen(&self, source: &Texture2D<RGBA32F>) {
    let textures: &[&RawTexture] = &[source];
    let tess_render = TessRender::one_whole(&self.quad);

    Pipeline::new(&self.framebuffer, [0., 0., 0., 0.], textures, &[], vec![
      Pipe::empty()
        .uniforms(&[FORWARD_SOURCE.alter(Unit::new(0))])
        .unwrap(ShadingCommand::new(&self.program.borrow(), vec![
          Pipe::new(RenderCommand::new(None, true, vec![
            Pipe::new(tess_render)]))
          ]))
    ]).run();
  }

  pub fn black_screen(&self) {
    Pipeline::new(&self.framebuffer, [0., 0., 0., 0.], &[], &[], vec![]).run();
  }
}
<|endoftext|>


<commit_before>//! The Content-Type entity header, defined in RFC 2616, Section 14.17.
use headers::serialization_utils::{push_parameters, WriterUtil};
use std::io::IoResult;
use std::fmt;

#[deriving(Clone, PartialEq, Eq)]
pub struct MediaType {
    pub type_: String,
    pub subtype: String,
    pub parameters: Vec<(String, String)>,
}

pub fn MediaType(type_: String, subtype: String, parameters: Vec<(String, String)>) -> MediaType {
    MediaType {
        type_: type_,
        subtype: subtype,
        parameters: parameters,
    }
}

impl fmt::Show for MediaType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Idea:
        //let s = String::new();
        //s.push_token(self.type_);
        //s.push_char('/');
        //s.push_token(self.subtype);
        //s.push_parameters(self.parameters);
        //s
        let s = format!("{}/{}", self.type_, self.subtype);
        f.write(push_parameters(s, self.parameters.as_slice()).as_bytes())
    }
}

impl super::HeaderConvertible for MediaType {
    fn from_stream<R: Reader>(reader: &mut super::HeaderValueByteIterator<R>) -> Option<MediaType> {
        let type_ = match reader.read_token() {
            Some(v) => v,
            None => return None,
        };
        if reader.next() != Some('/' as u8) {
            return None;
        }
        let subtype = match reader.read_token() {
            Some(v) => v,
            None => return None,
        };
        match reader.read_parameters() {
            // At the time of writing, ``Some(parameters) if reader.verify_consumed()`` was not
            // permitted: "cannot bind by-move into a pattern guard"
            Some(parameters) => {
                reader.some_if_consumed(MediaType {
                    type_: type_,
                    subtype: subtype,
                    parameters: parameters,
                })
            },
            None => None,
        }
    }

    fn to_stream<W: Writer>(&self, writer: &mut W) -> IoResult<()> {
        try!(writer.write_token(&self.type_));
        try!(writer.write(['/' as u8]));
        try!(writer.write_token(&self.subtype));
        writer.write_parameters(self.parameters.as_slice())
    }

    fn http_value(&self) -> String {
        self.to_str()
    }
}

#[test]
fn test_content_type() {
    use headers::test_utils::{assert_conversion_correct, assert_interpretation_correct,
                              assert_invalid};
    assert_conversion_correct("type/subtype", MediaType(String::from_str("type"), String::from_str("subtype"), Vec::new()));
    assert_conversion_correct("type/subtype;key=value",
                              MediaType(String::from_str("type"), String::from_str("subtype"), vec!((String::from_str("key"), String::from_str("value")))));
    assert_conversion_correct("type/subtype;key=value;q=0.1",
            MediaType(String::from_str("type"), String::from_str("subtype"), vec!((String::from_str("key"), String::from_str("value")), (String::from_str("q"), String::from_str("0.1")))));
    assert_interpretation_correct("type/subtype ; key = value ; q = 0.1",
            MediaType(String::from_str("type"), String::from_str("subtype"), vec!((String::from_str("key"), String::from_str("value")), (String::from_str("q"), String::from_str("0.1")))));

    assert_invalid::<MediaType>("");
    assert_invalid::<MediaType>("/");
    assert_invalid::<MediaType>("type/subtype,foo=bar");
    assert_invalid::<MediaType>("type /subtype");
    assert_invalid::<MediaType>("type/ subtype");
    assert_invalid::<MediaType>("type/subtype;foo=bar,foo=bar");
}
<commit_msg>MediaType(...) -> MediaType::new(...)<commit_after>//! The Content-Type entity header, defined in RFC 2616, Section 14.17.
use headers::serialization_utils::{push_parameters, WriterUtil};
use std::io::IoResult;
use std::fmt;

#[deriving(Clone, PartialEq, Eq)]
pub struct MediaType {
    pub type_: String,
    pub subtype: String,
    pub parameters: Vec<(String, String)>,
}

impl MediaType {
    pub fn new(type_: String, subtype: String, parameters: Vec<(String, String)>) -> MediaType {
        MediaType {
            type_: type_,
            subtype: subtype,
            parameters: parameters,
        }
    }
}

impl fmt::Show for MediaType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Idea:
        //let s = String::new();
        //s.push_token(self.type_);
        //s.push_char('/');
        //s.push_token(self.subtype);
        //s.push_parameters(self.parameters);
        //s
        let s = format!("{}/{}", self.type_, self.subtype);
        f.write(push_parameters(s, self.parameters.as_slice()).as_bytes())
    }
}

impl super::HeaderConvertible for MediaType {
    fn from_stream<R: Reader>(reader: &mut super::HeaderValueByteIterator<R>) -> Option<MediaType> {
        let type_ = match reader.read_token() {
            Some(v) => v,
            None => return None,
        };
        if reader.next() != Some('/' as u8) {
            return None;
        }
        let subtype = match reader.read_token() {
            Some(v) => v,
            None => return None,
        };
        match reader.read_parameters() {
            // At the time of writing, ``Some(parameters) if reader.verify_consumed()`` was not
            // permitted: "cannot bind by-move into a pattern guard"
            Some(parameters) => {
                reader.some_if_consumed(MediaType {
                    type_: type_,
                    subtype: subtype,
                    parameters: parameters,
                })
            },
            None => None,
        }
    }

    fn to_stream<W: Writer>(&self, writer: &mut W) -> IoResult<()> {
        try!(writer.write_token(&self.type_));
        try!(writer.write(['/' as u8]));
        try!(writer.write_token(&self.subtype));
        writer.write_parameters(self.parameters.as_slice())
    }

    fn http_value(&self) -> String {
        self.to_str()
    }
}

#[test]
fn test_content_type() {
    use headers::test_utils::{assert_conversion_correct, assert_interpretation_correct,
                              assert_invalid};
    assert_conversion_correct("type/subtype", MediaType::new(String::from_str("type"), String::from_str("subtype"), Vec::new()));
    assert_conversion_correct("type/subtype;key=value",
                              MediaType::new(String::from_str("type"), String::from_str("subtype"), vec!((String::from_str("key"), String::from_str("value")))));
    assert_conversion_correct("type/subtype;key=value;q=0.1",
            MediaType::new(String::from_str("type"), String::from_str("subtype"), vec!((String::from_str("key"), String::from_str("value")), (String::from_str("q"), String::from_str("0.1")))));
    assert_interpretation_correct("type/subtype ; key = value ; q = 0.1",
            MediaType::new(String::from_str("type"), String::from_str("subtype"), vec!((String::from_str("key"), String::from_str("value")), (String::from_str("q"), String::from_str("0.1")))));

    assert_invalid::<MediaType>("");
    assert_invalid::<MediaType>("/");
    assert_invalid::<MediaType>("type/subtype,foo=bar");
    assert_invalid::<MediaType>("type /subtype");
    assert_invalid::<MediaType>("type/ subtype");
    assert_invalid::<MediaType>("type/subtype;foo=bar,foo=bar");
}
<|endoftext|>