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

use rustc_hash::FxHashSet;

use ra_syntax::{
    ast::{self, AstNode, AstToken, VisibilityOwner},
    Direction, NodeOrToken, SourceFile,
    SyntaxKind::{self, *},
    SyntaxNode, TextRange,
};

#[derive(Debug, PartialEq, Eq)]
pub enum FoldKind {
    Comment,
    Imports,
    Mods,
    Block,
    ArgList,
}

#[derive(Debug)]
pub struct Fold {
    pub range: TextRange,
    pub kind: FoldKind,
}

pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
    let mut res = vec![];
    let mut visited_comments = FxHashSet::default();
    let mut visited_imports = FxHashSet::default();
    let mut visited_mods = FxHashSet::default();

    for element in file.syntax().descendants_with_tokens() {
        // Fold items that span multiple lines
        if let Some(kind) = fold_kind(element.kind()) {
            let is_multiline = match &element {
                NodeOrToken::Node(node) => node.text().contains_char('\n'),
                NodeOrToken::Token(token) => token.text().contains('\n'),
            };
            if is_multiline {
                res.push(Fold { range: element.text_range(), kind });
                continue;
            }
        }

        match element {
            NodeOrToken::Token(token) => {
                // Fold groups of comments
                if let Some(comment) = ast::Comment::cast(token) {
                    if !visited_comments.contains(&comment) {
                        if let Some(range) =
                            contiguous_range_for_comment(comment, &mut visited_comments)
                        {
                            res.push(Fold { range, kind: FoldKind::Comment })
                        }
                    }
                }
            }
            NodeOrToken::Node(node) => {
                // Fold groups of imports
                if node.kind() == USE && !visited_imports.contains(&node) {
                    if let Some(range) = contiguous_range_for_group(&node, &mut visited_imports) {
                        res.push(Fold { range, kind: FoldKind::Imports })
                    }
                }

                // Fold groups of mods
                if node.kind() == MODULE && !has_visibility(&node) && !visited_mods.contains(&node)
                {
                    if let Some(range) =
                        contiguous_range_for_group_unless(&node, has_visibility, &mut visited_mods)
                    {
                        res.push(Fold { range, kind: FoldKind::Mods })
                    }
                }
            }
        }
    }

    res
}

fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
    match kind {
        COMMENT => Some(FoldKind::Comment),
        USE => Some(FoldKind::Imports),
        ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList),
        RECORD_FIELD_LIST
        | RECORD_PAT_FIELD_LIST
        | RECORD_EXPR_FIELD_LIST
        | ITEM_LIST
        | EXTERN_ITEM_LIST
        | USE_TREE_LIST
        | BLOCK_EXPR
        | MATCH_ARM_LIST
        | VARIANT_LIST
        | TOKEN_TREE => Some(FoldKind::Block),
        _ => None,
    }
}

fn has_visibility(node: &SyntaxNode) -> bool {
    ast::Module::cast(node.clone()).and_then(|m| m.visibility()).is_some()
}

fn contiguous_range_for_group(
    first: &SyntaxNode,
    visited: &mut FxHashSet<SyntaxNode>,
) -> Option<TextRange> {
    contiguous_range_for_group_unless(first, |_| false, visited)
}

fn contiguous_range_for_group_unless(
    first: &SyntaxNode,
    unless: impl Fn(&SyntaxNode) -> bool,
    visited: &mut FxHashSet<SyntaxNode>,
) -> Option<TextRange> {
    visited.insert(first.clone());

    let mut last = first.clone();
    for element in first.siblings_with_tokens(Direction::Next) {
        let node = match element {
            NodeOrToken::Token(token) => {
                if let Some(ws) = ast::Whitespace::cast(token) {
                    if !ws.spans_multiple_lines() {
                        // Ignore whitespace without blank lines
                        continue;
                    }
                }
                // There is a blank line or another token, which means that the
                // group ends here
                break;
            }
            NodeOrToken::Node(node) => node,
        };

        // Stop if we find a node that doesn't belong to the group
        if node.kind() != first.kind() || unless(&node) {
            break;
        }

        visited.insert(node.clone());
        last = node;
    }

    if first != &last {
        Some(TextRange::new(first.text_range().start(), last.text_range().end()))
    } else {
        // The group consists of only one element, therefore it cannot be folded
        None
    }
}

fn contiguous_range_for_comment(
    first: ast::Comment,
    visited: &mut FxHashSet<ast::Comment>,
) -> Option<TextRange> {
    visited.insert(first.clone());

    // Only fold comments of the same flavor
    let group_kind = first.kind();
    if !group_kind.shape.is_line() {
        return None;
    }

    let mut last = first.clone();
    for element in first.syntax().siblings_with_tokens(Direction::Next) {
        match element {
            NodeOrToken::Token(token) => {
                if let Some(ws) = ast::Whitespace::cast(token.clone()) {
                    if !ws.spans_multiple_lines() {
                        // Ignore whitespace without blank lines
                        continue;
                    }
                }
                if let Some(c) = ast::Comment::cast(token) {
                    if c.kind() == group_kind {
                        visited.insert(c.clone());
                        last = c;
                        continue;
                    }
                }
                // The comment group ends because either:
                // * An element of a different kind was reached
                // * A comment of a different flavor was reached
                break;
            }
            NodeOrToken::Node(_) => break,
        };
    }

    if first != last {
        Some(TextRange::new(first.syntax().text_range().start(), last.syntax().text_range().end()))
    } else {
        // The group consists of only one element, therefore it cannot be folded
        None
    }
}

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

    use super::*;

    fn check(ra_fixture: &str) {
        let (ranges, text) = extract_tags(ra_fixture, "fold");

        let parse = SourceFile::parse(&text);
        let folds = folding_ranges(&parse.tree());
        assert_eq!(
            folds.len(),
            ranges.len(),
            "The amount of folds is different than the expected amount"
        );

        for (fold, (range, attr)) in folds.iter().zip(ranges.into_iter()) {
            assert_eq!(fold.range.start(), range.start());
            assert_eq!(fold.range.end(), range.end());

            let kind = match fold.kind {
                FoldKind::Comment => "comment",
                FoldKind::Imports => "imports",
                FoldKind::Mods => "mods",
                FoldKind::Block => "block",
                FoldKind::ArgList => "arglist",
            };
            assert_eq!(kind, &attr.unwrap());
        }
    }

    #[test]
    fn test_fold_comments() {
        check(
            r#"
<fold comment>// Hello
// this is a multiline
// comment
//</fold>

// But this is not

fn main() <fold block>{
    <fold comment>// We should
    // also
    // fold
    // this one.</fold>
    <fold comment>//! But this one is different
    //! because it has another flavor</fold>
    <fold comment>/* As does this
    multiline comment */</fold>
}</fold>"#,
        );
    }

    #[test]
    fn test_fold_imports() {
        check(
            r#"
<fold imports>use std::<fold block>{
    str,
    vec,
    io as iop
}</fold>;</fold>

fn main() <fold block>{
}</fold>"#,
        );
    }

    #[test]
    fn test_fold_mods() {
        check(
            r#"

pub mod foo;
<fold mods>mod after_pub;
mod after_pub_next;</fold>

<fold mods>mod before_pub;
mod before_pub_next;</fold>
pub mod bar;

mod not_folding_single;
pub mod foobar;
pub not_folding_single_next;

<fold mods>#[cfg(test)]
mod with_attribute;
mod with_attribute_next;</fold>

fn main() <fold block>{
}</fold>"#,
        );
    }

    #[test]
    fn test_fold_import_groups() {
        check(
            r#"
<fold imports>use std::str;
use std::vec;
use std::io as iop;</fold>

<fold imports>use std::mem;
use std::f64;</fold>

use std::collections::HashMap;
// Some random comment
use std::collections::VecDeque;

fn main() <fold block>{
}</fold>"#,
        );
    }

    #[test]
    fn test_fold_import_and_groups() {
        check(
            r#"
<fold imports>use std::str;
use std::vec;
use std::io as iop;</fold>

<fold imports>use std::mem;
use std::f64;</fold>

<fold imports>use std::collections::<fold block>{
    HashMap,
    VecDeque,
}</fold>;</fold>
// Some random comment

fn main() <fold block>{
}</fold>"#,
        );
    }

    #[test]
    fn test_folds_macros() {
        check(
            r#"
macro_rules! foo <fold block>{
    ($($tt:tt)*) => { $($tt)* }
}</fold>
"#,
        );
    }

    #[test]
    fn test_fold_match_arms() {
        check(
            r#"
fn main() <fold block>{
    match 0 <fold block>{
        0 => 0,
        _ => 1,
    }</fold>
}</fold>
"#,
        );
    }

    #[test]
    fn fold_big_calls() {
        check(
            r#"
fn main() <fold block>{
    frobnicate<fold arglist>(
        1,
        2,
        3,
    )</fold>
}</fold>
"#,
        )
    }

    #[test]
    fn fold_record_literals() {
        check(
            r#"
const _: S = S <fold block>{

}</fold>;
"#,
        )
    }

    #[test]
    fn fold_multiline_params() {
        check(
            r#"
fn foo<fold arglist>(
    x: i32,
    y: String,
)</fold> {}
"#,
        )
    }
}
<commit_msg>Fold trait declarations<commit_after>//! FIXME: write short doc here

use rustc_hash::FxHashSet;

use ra_syntax::{
    ast::{self, AstNode, AstToken, VisibilityOwner},
    Direction, NodeOrToken, SourceFile,
    SyntaxKind::{self, *},
    SyntaxNode, TextRange,
};

#[derive(Debug, PartialEq, Eq)]
pub enum FoldKind {
    Comment,
    Imports,
    Mods,
    Block,
    ArgList,
}

#[derive(Debug)]
pub struct Fold {
    pub range: TextRange,
    pub kind: FoldKind,
}

pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
    let mut res = vec![];
    let mut visited_comments = FxHashSet::default();
    let mut visited_imports = FxHashSet::default();
    let mut visited_mods = FxHashSet::default();

    for element in file.syntax().descendants_with_tokens() {
        // Fold items that span multiple lines
        if let Some(kind) = fold_kind(element.kind()) {
            let is_multiline = match &element {
                NodeOrToken::Node(node) => node.text().contains_char('\n'),
                NodeOrToken::Token(token) => token.text().contains('\n'),
            };
            if is_multiline {
                res.push(Fold { range: element.text_range(), kind });
                continue;
            }
        }

        match element {
            NodeOrToken::Token(token) => {
                // Fold groups of comments
                if let Some(comment) = ast::Comment::cast(token) {
                    if !visited_comments.contains(&comment) {
                        if let Some(range) =
                            contiguous_range_for_comment(comment, &mut visited_comments)
                        {
                            res.push(Fold { range, kind: FoldKind::Comment })
                        }
                    }
                }
            }
            NodeOrToken::Node(node) => {
                // Fold groups of imports
                if node.kind() == USE && !visited_imports.contains(&node) {
                    if let Some(range) = contiguous_range_for_group(&node, &mut visited_imports) {
                        res.push(Fold { range, kind: FoldKind::Imports })
                    }
                }

                // Fold groups of mods
                if node.kind() == MODULE && !has_visibility(&node) && !visited_mods.contains(&node)
                {
                    if let Some(range) =
                        contiguous_range_for_group_unless(&node, has_visibility, &mut visited_mods)
                    {
                        res.push(Fold { range, kind: FoldKind::Mods })
                    }
                }
            }
        }
    }

    res
}

fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
    match kind {
        COMMENT => Some(FoldKind::Comment),
        USE => Some(FoldKind::Imports),
        ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList),
        ASSOC_ITEM_LIST
        | RECORD_FIELD_LIST
        | RECORD_PAT_FIELD_LIST
        | RECORD_EXPR_FIELD_LIST
        | ITEM_LIST
        | EXTERN_ITEM_LIST
        | USE_TREE_LIST
        | BLOCK_EXPR
        | MATCH_ARM_LIST
        | VARIANT_LIST
        | TOKEN_TREE => Some(FoldKind::Block),
        _ => None,
    }
}

fn has_visibility(node: &SyntaxNode) -> bool {
    ast::Module::cast(node.clone()).and_then(|m| m.visibility()).is_some()
}

fn contiguous_range_for_group(
    first: &SyntaxNode,
    visited: &mut FxHashSet<SyntaxNode>,
) -> Option<TextRange> {
    contiguous_range_for_group_unless(first, |_| false, visited)
}

fn contiguous_range_for_group_unless(
    first: &SyntaxNode,
    unless: impl Fn(&SyntaxNode) -> bool,
    visited: &mut FxHashSet<SyntaxNode>,
) -> Option<TextRange> {
    visited.insert(first.clone());

    let mut last = first.clone();
    for element in first.siblings_with_tokens(Direction::Next) {
        let node = match element {
            NodeOrToken::Token(token) => {
                if let Some(ws) = ast::Whitespace::cast(token) {
                    if !ws.spans_multiple_lines() {
                        // Ignore whitespace without blank lines
                        continue;
                    }
                }
                // There is a blank line or another token, which means that the
                // group ends here
                break;
            }
            NodeOrToken::Node(node) => node,
        };

        // Stop if we find a node that doesn't belong to the group
        if node.kind() != first.kind() || unless(&node) {
            break;
        }

        visited.insert(node.clone());
        last = node;
    }

    if first != &last {
        Some(TextRange::new(first.text_range().start(), last.text_range().end()))
    } else {
        // The group consists of only one element, therefore it cannot be folded
        None
    }
}

fn contiguous_range_for_comment(
    first: ast::Comment,
    visited: &mut FxHashSet<ast::Comment>,
) -> Option<TextRange> {
    visited.insert(first.clone());

    // Only fold comments of the same flavor
    let group_kind = first.kind();
    if !group_kind.shape.is_line() {
        return None;
    }

    let mut last = first.clone();
    for element in first.syntax().siblings_with_tokens(Direction::Next) {
        match element {
            NodeOrToken::Token(token) => {
                if let Some(ws) = ast::Whitespace::cast(token.clone()) {
                    if !ws.spans_multiple_lines() {
                        // Ignore whitespace without blank lines
                        continue;
                    }
                }
                if let Some(c) = ast::Comment::cast(token) {
                    if c.kind() == group_kind {
                        visited.insert(c.clone());
                        last = c;
                        continue;
                    }
                }
                // The comment group ends because either:
                // * An element of a different kind was reached
                // * A comment of a different flavor was reached
                break;
            }
            NodeOrToken::Node(_) => break,
        };
    }

    if first != last {
        Some(TextRange::new(first.syntax().text_range().start(), last.syntax().text_range().end()))
    } else {
        // The group consists of only one element, therefore it cannot be folded
        None
    }
}

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

    use super::*;

    fn check(ra_fixture: &str) {
        let (ranges, text) = extract_tags(ra_fixture, "fold");

        let parse = SourceFile::parse(&text);
        let folds = folding_ranges(&parse.tree());
        assert_eq!(
            folds.len(),
            ranges.len(),
            "The amount of folds is different than the expected amount"
        );

        for (fold, (range, attr)) in folds.iter().zip(ranges.into_iter()) {
            assert_eq!(fold.range.start(), range.start());
            assert_eq!(fold.range.end(), range.end());

            let kind = match fold.kind {
                FoldKind::Comment => "comment",
                FoldKind::Imports => "imports",
                FoldKind::Mods => "mods",
                FoldKind::Block => "block",
                FoldKind::ArgList => "arglist",
            };
            assert_eq!(kind, &attr.unwrap());
        }
    }

    #[test]
    fn test_fold_comments() {
        check(
            r#"
<fold comment>// Hello
// this is a multiline
// comment
//</fold>

// But this is not

fn main() <fold block>{
    <fold comment>// We should
    // also
    // fold
    // this one.</fold>
    <fold comment>//! But this one is different
    //! because it has another flavor</fold>
    <fold comment>/* As does this
    multiline comment */</fold>
}</fold>"#,
        );
    }

    #[test]
    fn test_fold_imports() {
        check(
            r#"
<fold imports>use std::<fold block>{
    str,
    vec,
    io as iop
}</fold>;</fold>

fn main() <fold block>{
}</fold>"#,
        );
    }

    #[test]
    fn test_fold_mods() {
        check(
            r#"

pub mod foo;
<fold mods>mod after_pub;
mod after_pub_next;</fold>

<fold mods>mod before_pub;
mod before_pub_next;</fold>
pub mod bar;

mod not_folding_single;
pub mod foobar;
pub not_folding_single_next;

<fold mods>#[cfg(test)]
mod with_attribute;
mod with_attribute_next;</fold>

fn main() <fold block>{
}</fold>"#,
        );
    }

    #[test]
    fn test_fold_import_groups() {
        check(
            r#"
<fold imports>use std::str;
use std::vec;
use std::io as iop;</fold>

<fold imports>use std::mem;
use std::f64;</fold>

use std::collections::HashMap;
// Some random comment
use std::collections::VecDeque;

fn main() <fold block>{
}</fold>"#,
        );
    }

    #[test]
    fn test_fold_import_and_groups() {
        check(
            r#"
<fold imports>use std::str;
use std::vec;
use std::io as iop;</fold>

<fold imports>use std::mem;
use std::f64;</fold>

<fold imports>use std::collections::<fold block>{
    HashMap,
    VecDeque,
}</fold>;</fold>
// Some random comment

fn main() <fold block>{
}</fold>"#,
        );
    }

    #[test]
    fn test_folds_structs() {
        check(
            r#"
struct Foo <fold block>{
}</fold>
"#,
        );
    }

    #[test]
    fn test_folds_traits() {
        check(
            r#"
trait Foo <fold block>{
}</fold>
"#,
        );
    }

    #[test]
    fn test_folds_macros() {
        check(
            r#"
macro_rules! foo <fold block>{
    ($($tt:tt)*) => { $($tt)* }
}</fold>
"#,
        );
    }

    #[test]
    fn test_fold_match_arms() {
        check(
            r#"
fn main() <fold block>{
    match 0 <fold block>{
        0 => 0,
        _ => 1,
    }</fold>
}</fold>
"#,
        );
    }

    #[test]
    fn fold_big_calls() {
        check(
            r#"
fn main() <fold block>{
    frobnicate<fold arglist>(
        1,
        2,
        3,
    )</fold>
}</fold>
"#,
        )
    }

    #[test]
    fn fold_record_literals() {
        check(
            r#"
const _: S = S <fold block>{

}</fold>;
"#,
        )
    }

    #[test]
    fn fold_multiline_params() {
        check(
            r#"
fn foo<fold arglist>(
    x: i32,
    y: String,
)</fold> {}
"#,
        )
    }
}
<|endoftext|>


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

extern crate syntax;
extern crate syntax_pos;

use self::syntax::ast::{
    AttrStyle, Attribute, Expr, ExprKind, FnHeader, Ident, ImplItem, Item, Mac, MetaItem,
    MetaItemKind, NestedMetaItem, NestedMetaItemKind, TraitItem, Visibility, WhereClause,
};
use self::syntax::codemap::{self, Spanned};
use self::syntax::fold::{self, Folder};
use self::syntax::parse::lexer::comments;
use self::syntax::parse::token::{DelimToken, Lit, Token};
use self::syntax::ptr::P;
use self::syntax::symbol::Symbol;
use self::syntax::tokenstream::{Delimited, TokenStream, TokenTree};
use self::syntax::util::move_map::MoveMap;
use self::syntax::util::small_vector::SmallVector;

use self::syntax::ast;
use self::syntax_pos::{Span, DUMMY_SP};

struct Respanner;

impl Respanner {
    fn fold_spanned<T>(&mut self, spanned: Spanned<T>) -> Spanned<T> {
        codemap::respan(self.new_span(spanned.span), spanned.node)
    }

    fn fold_lit(&mut self, l: Lit) -> Lit {
        // Give up on comparing literals inside of macros because there are
        // so many equivalent representations of the same literal; they are
        // tested elsewhere
        match l {
            Lit::Byte(_) => Lit::Byte(Symbol::intern("")),
            Lit::Char(_) => Lit::Char(Symbol::intern("")),
            Lit::Integer(_) => Lit::Integer(Symbol::intern("")),
            Lit::Float(_) => Lit::Float(Symbol::intern("")),
            Lit::Str_(_) => Lit::Str_(Symbol::intern("")),
            Lit::ByteStr(_) => Lit::ByteStr(Symbol::intern("")),
            _ => l,
        }
    }
}

impl Folder for Respanner {
    fn new_span(&mut self, _: Span) -> Span {
        DUMMY_SP
    }

    fn fold_item(&mut self, i: P<Item>) -> SmallVector<P<Item>> {
        let i = i.map(|mut i| {
            i.tokens = None;
            i
        });
        fold::noop_fold_item(i, self)
    }

    fn fold_fn_header(&mut self, header: FnHeader) -> FnHeader {
        FnHeader {
            // default fold_item_kind does not fold this span
            constness: self.fold_spanned(header.constness),
            ..fold::noop_fold_fn_header(header, self)
        }
    }

    fn fold_expr(&mut self, e: P<Expr>) -> P<Expr> {
        e.map(|e| {
            let folded = fold::noop_fold_expr(e, self);
            Expr {
                node: match folded.node {
                    ExprKind::Lit(l) => {
                        // default fold_expr does not fold lits
                        ExprKind::Lit(l.map(|l| self.fold_spanned(l)))
                    }
                    ExprKind::Binary(op, lhs, rhs) => {
                        // default fold_expr does not fold the op span
                        ExprKind::Binary(self.fold_spanned(op), lhs, rhs)
                    }
                    ExprKind::AssignOp(op, lhs, rhs) => {
                        // default fold_expr does not fold the op span
                        ExprKind::AssignOp(self.fold_spanned(op), lhs, rhs)
                    }
                    other => other,
                },
                ..folded
            }
        })
    }

    fn fold_trait_item(&mut self, mut i: TraitItem) -> SmallVector<TraitItem> {
        i.tokens = None;
        fold::noop_fold_trait_item(i, self)
    }

    fn fold_impl_item(&mut self, mut i: ImplItem) -> SmallVector<ImplItem> {
        i.tokens = None;
        fold::noop_fold_impl_item(i, self)
    }

    fn fold_attribute(&mut self, mut at: Attribute) -> Option<Attribute> {
        at.id.0 = 0;
        at.is_sugared_doc = false;
        fold::noop_fold_attribute(at, self)
    }

    fn fold_meta_item(&mut self, meta_item: MetaItem) -> MetaItem {
        let MetaItem { ident, node, span } = meta_item;
        MetaItem {
            ident,
            node: match node {
                MetaItemKind::Word => MetaItemKind::Word,
                MetaItemKind::List(nested) => {
                    MetaItemKind::List(nested.move_map(|e| self.fold_meta_list_item(e)))
                }
                // default fold_meta_item does not fold the value span
                MetaItemKind::NameValue(lit) => MetaItemKind::NameValue(self.fold_spanned(lit)),
            },
            span: self.new_span(span),
        }
    }

    fn fold_meta_list_item(&mut self, list_item: NestedMetaItem) -> NestedMetaItem {
        Spanned {
            node: match list_item.node {
                NestedMetaItemKind::MetaItem(mi) => {
                    NestedMetaItemKind::MetaItem(self.fold_meta_item(mi))
                }
                // default fold_meta_list_item does not fold the span
                NestedMetaItemKind::Literal(lit) => {
                    NestedMetaItemKind::Literal(self.fold_spanned(lit))
                }
            },
            span: self.new_span(list_item.span),
        }
    }

    // This folder is disabled by default.
    fn fold_mac(&mut self, mac: Mac) -> Mac {
        fold::noop_fold_mac(mac, self)
    }

    fn fold_token(&mut self, t: Token) -> Token {
        fold::noop_fold_token(
            match t {
                // default fold_token does not fold literals
                Token::Literal(lit, repr) => Token::Literal(self.fold_lit(lit), repr),
                _ => t,
            },
            self,
        )
    }

    fn fold_vis(&mut self, vis: Visibility) -> Visibility {
        fold::noop_fold_vis(self.fold_spanned(vis), self)
    }

    fn fold_where_clause(&mut self, mut clause: WhereClause) -> WhereClause {
        // default fold_where_clause does not fold the span
        clause.span = self.new_span(clause.span);
        fold::noop_fold_where_clause(clause, self)
    }

    fn fold_tts(&mut self, tts: TokenStream) -> TokenStream {
        let mut tokens = Vec::new();
        for tt in tts.into_trees() {
            let c = match tt {
                TokenTree::Token(_, Token::DocComment(c)) => c,
                _ => {
                    tokens.push(tt);
                    continue;
                }
            };
            let contents = comments::strip_doc_comment_decoration(&c.as_str());
            let style = comments::doc_comment_style(&c.as_str());
            tokens.push(TokenTree::Token(DUMMY_SP, Token::Pound));
            if style == AttrStyle::Inner {
                tokens.push(TokenTree::Token(DUMMY_SP, Token::Not));
            }
            let lit = Lit::Str_(Symbol::intern(&contents));
            let mut tts = vec![
                TokenTree::Token(DUMMY_SP, Token::Ident(Ident::from_str("doc"), false)),
                TokenTree::Token(DUMMY_SP, Token::Eq),
                TokenTree::Token(DUMMY_SP, Token::Literal(lit, None)),
            ];
            tokens.push(TokenTree::Delimited(
                DUMMY_SP,
                Delimited {
                    delim: DelimToken::Bracket,
                    tts: tts.into_iter().collect::<TokenStream>().into(),
                },
            ));
        }
        tokens.into_iter().map(|tt| self.fold_tt(tt)).collect()
    }
}

#[allow(dead_code)]
pub fn respan_crate(krate: ast::Crate) -> ast::Crate {
    Respanner.fold_crate(krate)
}

#[allow(dead_code)]
pub fn respan_expr(expr: P<ast::Expr>) -> P<ast::Expr> {
    Respanner.fold_expr(expr)
}
<commit_msg>Update test suite to nightly-2018-06-27<commit_after>// Copyright 2018 Syn Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate syntax;
extern crate syntax_pos;

use self::syntax::ast::{
    AttrStyle, Attribute, Expr, ExprKind, FnHeader, Ident, ImplItem, Item, Mac, MetaItem,
    MetaItemKind, NestedMetaItem, NestedMetaItemKind, Pat, PatKind, TraitItem, Visibility,
    WhereClause,
};
use self::syntax::codemap::{self, Spanned};
use self::syntax::fold::{self, Folder};
use self::syntax::parse::lexer::comments;
use self::syntax::parse::token::{DelimToken, Lit, Token};
use self::syntax::ptr::P;
use self::syntax::symbol::Symbol;
use self::syntax::tokenstream::{Delimited, TokenStream, TokenTree};
use self::syntax::util::move_map::MoveMap;
use self::syntax::util::small_vector::SmallVector;

use self::syntax::ast;
use self::syntax_pos::{Span, DUMMY_SP};

struct Respanner;

impl Respanner {
    fn fold_spanned<T>(&mut self, spanned: Spanned<T>) -> Spanned<T> {
        codemap::respan(self.new_span(spanned.span), spanned.node)
    }

    fn fold_lit(&mut self, l: Lit) -> Lit {
        // Give up on comparing literals inside of macros because there are
        // so many equivalent representations of the same literal; they are
        // tested elsewhere
        match l {
            Lit::Byte(_) => Lit::Byte(Symbol::intern("")),
            Lit::Char(_) => Lit::Char(Symbol::intern("")),
            Lit::Integer(_) => Lit::Integer(Symbol::intern("")),
            Lit::Float(_) => Lit::Float(Symbol::intern("")),
            Lit::Str_(_) => Lit::Str_(Symbol::intern("")),
            Lit::ByteStr(_) => Lit::ByteStr(Symbol::intern("")),
            _ => l,
        }
    }
}

impl Folder for Respanner {
    fn new_span(&mut self, _: Span) -> Span {
        DUMMY_SP
    }

    fn fold_item(&mut self, i: P<Item>) -> SmallVector<P<Item>> {
        let i = i.map(|mut i| {
            i.tokens = None;
            i
        });
        fold::noop_fold_item(i, self)
    }

    fn fold_fn_header(&mut self, header: FnHeader) -> FnHeader {
        FnHeader {
            // default fold_item_kind does not fold this span
            constness: self.fold_spanned(header.constness),
            ..fold::noop_fold_fn_header(header, self)
        }
    }

    fn fold_expr(&mut self, e: P<Expr>) -> P<Expr> {
        e.map(|e| {
            let folded = fold::noop_fold_expr(e, self);
            Expr {
                node: match folded.node {
                    ExprKind::Lit(l) => {
                        // default fold_expr does not fold lits
                        ExprKind::Lit(l.map(|l| self.fold_spanned(l)))
                    }
                    ExprKind::Binary(op, lhs, rhs) => {
                        // default fold_expr does not fold the op span
                        ExprKind::Binary(self.fold_spanned(op), lhs, rhs)
                    }
                    ExprKind::AssignOp(op, lhs, rhs) => {
                        // default fold_expr does not fold the op span
                        ExprKind::AssignOp(self.fold_spanned(op), lhs, rhs)
                    }
                    other => other,
                },
                ..folded
            }
        })
    }

    fn fold_pat(&mut self, p: P<Pat>) -> P<Pat> {
        fold::noop_fold_pat(p, self).map(|mut p| {
            match p.node {
                PatKind::Range(_, _, ref mut end) => {
                    end.span = self.new_span(end.span);
                }
                _ => {}
            }
            p
        })
    }

    fn fold_trait_item(&mut self, mut i: TraitItem) -> SmallVector<TraitItem> {
        i.tokens = None;
        fold::noop_fold_trait_item(i, self)
    }

    fn fold_impl_item(&mut self, mut i: ImplItem) -> SmallVector<ImplItem> {
        i.tokens = None;
        fold::noop_fold_impl_item(i, self)
    }

    fn fold_attribute(&mut self, mut at: Attribute) -> Option<Attribute> {
        at.id.0 = 0;
        at.is_sugared_doc = false;
        fold::noop_fold_attribute(at, self)
    }

    fn fold_meta_item(&mut self, meta_item: MetaItem) -> MetaItem {
        let MetaItem { ident, node, span } = meta_item;
        MetaItem {
            ident,
            node: match node {
                MetaItemKind::Word => MetaItemKind::Word,
                MetaItemKind::List(nested) => {
                    MetaItemKind::List(nested.move_map(|e| self.fold_meta_list_item(e)))
                }
                // default fold_meta_item does not fold the value span
                MetaItemKind::NameValue(lit) => MetaItemKind::NameValue(self.fold_spanned(lit)),
            },
            span: self.new_span(span),
        }
    }

    fn fold_meta_list_item(&mut self, list_item: NestedMetaItem) -> NestedMetaItem {
        Spanned {
            node: match list_item.node {
                NestedMetaItemKind::MetaItem(mi) => {
                    NestedMetaItemKind::MetaItem(self.fold_meta_item(mi))
                }
                // default fold_meta_list_item does not fold the span
                NestedMetaItemKind::Literal(lit) => {
                    NestedMetaItemKind::Literal(self.fold_spanned(lit))
                }
            },
            span: self.new_span(list_item.span),
        }
    }

    // This folder is disabled by default.
    fn fold_mac(&mut self, mac: Mac) -> Mac {
        fold::noop_fold_mac(mac, self)
    }

    fn fold_token(&mut self, t: Token) -> Token {
        fold::noop_fold_token(
            match t {
                // default fold_token does not fold literals
                Token::Literal(lit, repr) => Token::Literal(self.fold_lit(lit), repr),
                _ => t,
            },
            self,
        )
    }

    fn fold_vis(&mut self, vis: Visibility) -> Visibility {
        fold::noop_fold_vis(self.fold_spanned(vis), self)
    }

    fn fold_where_clause(&mut self, mut clause: WhereClause) -> WhereClause {
        // default fold_where_clause does not fold the span
        clause.span = self.new_span(clause.span);
        fold::noop_fold_where_clause(clause, self)
    }

    fn fold_tts(&mut self, tts: TokenStream) -> TokenStream {
        let mut tokens = Vec::new();
        for tt in tts.into_trees() {
            let c = match tt {
                TokenTree::Token(_, Token::DocComment(c)) => c,
                _ => {
                    tokens.push(tt);
                    continue;
                }
            };
            let contents = comments::strip_doc_comment_decoration(&c.as_str());
            let style = comments::doc_comment_style(&c.as_str());
            tokens.push(TokenTree::Token(DUMMY_SP, Token::Pound));
            if style == AttrStyle::Inner {
                tokens.push(TokenTree::Token(DUMMY_SP, Token::Not));
            }
            let lit = Lit::Str_(Symbol::intern(&contents));
            let mut tts = vec![
                TokenTree::Token(DUMMY_SP, Token::Ident(Ident::from_str("doc"), false)),
                TokenTree::Token(DUMMY_SP, Token::Eq),
                TokenTree::Token(DUMMY_SP, Token::Literal(lit, None)),
            ];
            tokens.push(TokenTree::Delimited(
                DUMMY_SP,
                Delimited {
                    delim: DelimToken::Bracket,
                    tts: tts.into_iter().collect::<TokenStream>().into(),
                },
            ));
        }
        tokens.into_iter().map(|tt| self.fold_tt(tt)).collect()
    }
}

#[allow(dead_code)]
pub fn respan_crate(krate: ast::Crate) -> ast::Crate {
    Respanner.fold_crate(krate)
}

#[allow(dead_code)]
pub fn respan_expr(expr: P<ast::Expr>) -> P<ast::Expr> {
    Respanner.fold_expr(expr)
}
<|endoftext|>


<commit_before>extern crate cargo;
extern crate hyper;
extern crate hyper_native_tls;
#[macro_use]
extern crate lazy_static;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
extern crate toml;

use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::fs::File;
use std::io::Write;

use cargo::core::{Dependency, Registry, Source, SourceId, Summary};
use cargo::core::resolver::{self, Method, Resolve};
use cargo::sources::RegistrySource;
use cargo::util::Config;
use hyper::client::Client;
use hyper::net::HttpsConnector;
use hyper_native_tls::NativeTlsClient;

#[derive(Debug, Deserialize)]
struct TopCrates {
    crates: Vec<Crate>,
}

#[derive(Debug, Deserialize)]
struct Crate {
    #[serde(rename="id")]
    name: String,
    #[serde(rename="max_version")]
    version: String,
}

/// A Cargo.toml file.
#[derive(Serialize)]
struct TomlManifest {
    package: Package,
    dependencies: BTreeMap<String, String>,
}

/// Header of Cargo.toml file.
#[derive(Serialize)]
struct Package {
    name: String,
    version: String,
    authors: Vec<String>,
}

fn get_top_crates() -> TopCrates {
    let ssl = NativeTlsClient::new().expect("Unable to build TLS client");
    let connector = HttpsConnector::new(ssl);
    let client = Client::with_connector(connector);

    let res = client
        .get("https://crates.io/api/v1/crates?page=1&per_page=100&sort=downloads")
        .send()
        .expect("Could not fetch top crates");
    assert_eq!(res.status, hyper::Ok);

    serde_json::from_reader(res).expect("Invalid JSON")
}

fn decide_features(summary: &Summary) -> Method<'static> {
    lazy_static! {
        static ref PLAYGROUND_FEATURES: Vec<String> = vec!["playground".to_owned()];
    }

    // Enable `playground` feature if present.
    if summary.features().contains_key("playground") {
        Method::Required {
            dev_deps: false,
            features: &*PLAYGROUND_FEATURES,
            uses_default_features: false,
        }
    } else {
        Method::Required {
            dev_deps: false,
            features: &[],
            uses_default_features: true,
        }
    }
}

fn unique_latest_crates(resolve: Resolve) -> BTreeMap<String, String> {
    let mut uniqs = BTreeMap::new();
    for pkg in resolve.iter() {
        // Skip blacklisted crates.
        if BLACKLIST.contains(&pkg.name()) {
            continue;
        }

        match uniqs.entry(pkg.name()) {
            Entry::Vacant(entry) => {
                // First time seeing this package.
                entry.insert(pkg.version());
            }
            Entry::Occupied(mut entry) => {
                // Seen before, keep the newest version.
                if &pkg.version() > entry.get() {
                    entry.insert(pkg.version());
                }
            }
        }
    }

    uniqs.into_iter()
         .map(|(name, version)| (name.to_string(), version.to_string()))
         .collect()
}

fn write_manifest(manifest: TomlManifest, path: &str) {
    let mut f = File::create(path).expect("Unable to create Cargo.toml");
    let content = toml::to_vec(&manifest).expect("Couldn't serialize TOML");
    f.write_all(&content).expect("Couldn't write Cargo.toml");
}

static BLACKLIST: &'static [&'static str] = &[
    "libressl-pnacl-sys", // Fails to build
    "pnacl-build-helper", // Fails to build
    "aster", // Not supported on stable
    "quasi", // Not supported on stable
    "quasi_codegen", // Not supported on stable
    "quasi_macros", // Not supported on stable
    "serde_macros", // Apparently deleted
    "openssl", // Ecosystem is fragmented, only pull in via dependencies
    "openssl-sys", // Ecosystem is fragmented, only pull in via dependencies
    "openssl-sys-extras", // Ecosystem is fragmented, only pull in via dependencies
    "openssl-verify", // Ecosystem is fragmented, only pull in via dependencies
    "redox_syscall", // Not supported on stable
];

fn main() {
    // Setup to interact with cargo.
    let config = Config::default().expect("Unable to create default Cargo config");
    let crates_io = SourceId::crates_io(&config).expect("Unable to create crates.io source ID");
    let mut registry = RegistrySource::remote(&crates_io, &config);
    registry.update().expect("Unable to update registry");

    // List top 100 crates by number of downloads on crates.io.
    let top = get_top_crates();

    let mut summaries = Vec::new();
    for Crate { ref name, ref version } in top.crates {
        // Skip blacklisted crates.
        if BLACKLIST.contains(&&name[..]) {
            continue;
        }

        // Query the registry for summary of this crate.
        let dep = Dependency::parse_no_deprecated(name, Some(version), &crates_io)
            .unwrap_or_else(|e| panic!("Unable to parse dependency for {}:{}: {}", name, version, e));

        let matches = registry.query(&dep).unwrap_or_else(|e| {
            panic!("Unable to query registry for {}:{}: {}", name, version, e);
        });
        if matches.len() != 1 {
            panic!("expected one registry match for `{}:{}`", name, version);
        }
        let summary = matches.into_iter().next().unwrap();

        // Add a dependency on this crate.
        let method = decide_features(&summary);
        summaries.push((summary, method));
    }

    // Resolve transitive dependencies.
    let res = resolver::resolve(&summaries, &[], &mut registry)
        .expect("Unable to resolve dependencies");

    // Construct playground's Cargo.toml.
    let manifest = TomlManifest {
        package: Package {
            name: "playground".to_owned(),
            version: "0.0.1".to_owned(),
            authors: vec!["The Rust Playground".to_owned()],
        },
        dependencies: unique_latest_crates(res),
    };

    // Write manifest file.
    let cargo_toml = "result.Cargo.toml";
    write_manifest(manifest, cargo_toml);
    println!("wrote {}", cargo_toml);
}
<commit_msg>Save detailed information about the available crates<commit_after>extern crate cargo;
extern crate hyper;
extern crate hyper_native_tls;
#[macro_use]
extern crate lazy_static;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
extern crate toml;

use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::fs::File;
use std::io::Write;

use cargo::core::{Dependency, Registry, Source, SourceId, Summary};
use cargo::core::resolver::{self, Method, Resolve};
use cargo::sources::RegistrySource;
use cargo::util::Config;
use hyper::client::Client;
use hyper::net::HttpsConnector;
use hyper_native_tls::NativeTlsClient;

#[derive(Debug, Deserialize)]
struct TopCrates {
    crates: Vec<Crate>,
}

#[derive(Debug, Deserialize)]
struct Crate {
    #[serde(rename="id")]
    name: String,
    #[serde(rename="max_version")]
    version: String,
}

/// A Cargo.toml file.
#[derive(Serialize)]
struct TomlManifest {
    package: Package,
    dependencies: BTreeMap<String, String>,
}

/// Header of Cargo.toml file.
#[derive(Serialize)]
struct Package {
    name: String,
    version: String,
    authors: Vec<String>,
}

/// A mapping of a crates name to its identifier used in source code
#[derive(Debug, Serialize)]
struct CrateInformation {
    name: String,
    version: String,
    id: String,
}

fn get_top_crates() -> TopCrates {
    let ssl = NativeTlsClient::new().expect("Unable to build TLS client");
    let connector = HttpsConnector::new(ssl);
    let client = Client::with_connector(connector);

    let res = client
        .get("https://crates.io/api/v1/crates?page=1&per_page=100&sort=downloads")
        .send()
        .expect("Could not fetch top crates");
    assert_eq!(res.status, hyper::Ok);

    serde_json::from_reader(res).expect("Invalid JSON")
}

fn decide_features(summary: &Summary) -> Method<'static> {
    lazy_static! {
        static ref PLAYGROUND_FEATURES: Vec<String> = vec!["playground".to_owned()];
    }

    // Enable `playground` feature if present.
    if summary.features().contains_key("playground") {
        Method::Required {
            dev_deps: false,
            features: &*PLAYGROUND_FEATURES,
            uses_default_features: false,
        }
    } else {
        Method::Required {
            dev_deps: false,
            features: &[],
            uses_default_features: true,
        }
    }
}

fn unique_latest_crates(resolve: Resolve) -> BTreeMap<String, String> {
    let mut uniqs = BTreeMap::new();
    for pkg in resolve.iter() {
        // Skip blacklisted crates.
        if BLACKLIST.contains(&pkg.name()) {
            continue;
        }

        match uniqs.entry(pkg.name()) {
            Entry::Vacant(entry) => {
                // First time seeing this package.
                entry.insert(pkg.version());
            }
            Entry::Occupied(mut entry) => {
                // Seen before, keep the newest version.
                if &pkg.version() > entry.get() {
                    entry.insert(pkg.version());
                }
            }
        }
    }

    uniqs.into_iter()
         .map(|(name, version)| (name.to_string(), version.to_string()))
         .collect()
}

fn write_manifest(manifest: TomlManifest, path: &str) {
    let mut f = File::create(path).expect("Unable to create Cargo.toml");
    let content = toml::to_vec(&manifest).expect("Couldn't serialize TOML");
    f.write_all(&content).expect("Couldn't write Cargo.toml");
}

static BLACKLIST: &'static [&'static str] = &[
    "libressl-pnacl-sys", // Fails to build
    "pnacl-build-helper", // Fails to build
    "aster", // Not supported on stable
    "quasi", // Not supported on stable
    "quasi_codegen", // Not supported on stable
    "quasi_macros", // Not supported on stable
    "serde_macros", // Apparently deleted
    "openssl", // Ecosystem is fragmented, only pull in via dependencies
    "openssl-sys", // Ecosystem is fragmented, only pull in via dependencies
    "openssl-sys-extras", // Ecosystem is fragmented, only pull in via dependencies
    "openssl-verify", // Ecosystem is fragmented, only pull in via dependencies
    "redox_syscall", // Not supported on stable
];

fn main() {
    // Setup to interact with cargo.
    let config = Config::default().expect("Unable to create default Cargo config");
    let crates_io = SourceId::crates_io(&config).expect("Unable to create crates.io source ID");
    let mut registry = RegistrySource::remote(&crates_io, &config);
    registry.update().expect("Unable to update registry");

    // List top 100 crates by number of downloads on crates.io.
    let top = get_top_crates();

    let mut summaries = Vec::new();
    for Crate { ref name, ref version } in top.crates {
        // Skip blacklisted crates.
        if BLACKLIST.contains(&&name[..]) {
            continue;
        }

        // Query the registry for summary of this crate.
        let dep = Dependency::parse_no_deprecated(name, Some(version), &crates_io)
            .unwrap_or_else(|e| panic!("Unable to parse dependency for {}:{}: {}", name, version, e));

        let matches = registry.query(&dep).unwrap_or_else(|e| {
            panic!("Unable to query registry for {}:{}: {}", name, version, e);
        });
        if matches.len() != 1 {
            panic!("expected one registry match for `{}:{}`", name, version);
        }
        let summary = matches.into_iter().next().unwrap();

        // Add a dependency on this crate.
        let method = decide_features(&summary);
        summaries.push((summary, method));
    }

    // Resolve transitive dependencies.
    let res = resolver::resolve(&summaries, &[], &mut registry)
        .expect("Unable to resolve dependencies");

    // Construct playground's Cargo.toml.
    let unique_latest_crates = unique_latest_crates(res);
    let manifest = TomlManifest {
        package: Package {
            name: "playground".to_owned(),
            version: "0.0.1".to_owned(),
            authors: vec!["The Rust Playground".to_owned()],
        },
        dependencies: unique_latest_crates.clone(),
    };

    // Write manifest file.
    let cargo_toml = "result.Cargo.toml";
    write_manifest(manifest, cargo_toml);
    println!("wrote {}", cargo_toml);

    let mut infos = Vec::new();

    for (name, version) in unique_latest_crates {
        let pkgid = cargo::core::PackageId::new(&name, &version, &crates_io)
            .unwrap_or_else(|e| panic!("Unable to build PackageId for {} {}: {}", name, version, e));

        let pkg = registry.download(&pkgid)
            .unwrap_or_else(|e| panic!("Unable to download {} {}: {}", name, version, e));

        for target in pkg.targets() {
            if let cargo::core::TargetKind::Lib(_) = *target.kind() {
                infos.push(CrateInformation {
                    name: name.clone(),
                    version: version.clone(),
                    id: target.crate_name()
                })
            }
        }
    }

    let path = "crate-information.json";
    let mut f = File::create(path)
        .unwrap_or_else(|e| panic!("Unable to create {}: {}", path, e));
    serde_json::to_writer_pretty(&mut f, &infos)
        .unwrap_or_else(|e| panic!("Unable to write {}: {}", path, e));
    println!("Wrote {}", path);
}
<|endoftext|>


<commit_before>use std::convert::From;

#[derive(Debug, PartialEq)]
pub enum BindingType {
    Tcp,
    Unix,
}
<commit_msg>Implement From<&str> for BindingType<commit_after>use std::convert::From;

#[derive(Debug, PartialEq)]
pub enum BindingType {
    Tcp,
    Unix,
}

impl<'a> From<&'a str> for BindingType {
    fn from(string: &str) -> Self {
        match string {
            "tcp" => BindingType::Tcp,
            "unix" => BindingType::Unix,

            // TODO: move to `Result` and return `Err`
            _ => panic!("Unsupported binding type"),
        }
    }
}

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

    #[test]
    fn it_is_converted_from_tcp() {
        assert_eq!(BindingType::from("tcp"), BindingType::Tcp);
    }

    #[test]
    fn it_is_converted_from_unix() {
        assert_eq!(BindingType::from("unix"), BindingType::Unix);
    }
}
<|endoftext|>


<commit_before>use types::{Hash256}
use hashing::canonical_hash;

fn merkle_root(values: Vec<>) -> Hash256 {
    let o = values.len();

    for v in &values {
        canonical_hash(v.as_bytes());
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn calculate_merkle_root() {
        let values = vec!['abc', 'lmn', 'xyz', 'o0o'];

        let test_leaf_1 = canonical_hash(values[0]);
        let test_leaf_2 = canonical_hash(values[1]);
        let test_leaf_3 = canonical_hash(values[2]);
        let test_leaf_4 = canonical_hash(values[3]);
        let test_node_1 = canonical_hash(vec![test_leaf_1, test_leaf_2]);
        let test_node_2 = canonical_hash(vec![test_leaf_3, test_leaf_4]);
        let test_root   = canonical_hash(vec![test_node_1, test_node_2]);

        let result      = merkle_root(values);
        assert_eq!(result, test_root);
    }
}
<commit_msg>feat(hashing): fill o with 0s placeholders #146<commit_after>use types::{Hash256}
use hashing::canonical_hash;

fn merkle_root(values: Vec<T>) -> Hash256 {
    let mut o = vec![0; values.len()];
    o.append(values);

    for v in &values {
        canonical_hash(v.as_bytes());
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn calculate_merkle_root() {
        let values = vec!['abc', 'lmn', 'xyz', 'o0o'];

        let test_leaf_1 = canonical_hash(values[0]);
        let test_leaf_2 = canonical_hash(values[1]);
        let test_leaf_3 = canonical_hash(values[2]);
        let test_leaf_4 = canonical_hash(values[3]);
        let test_node_1 = canonical_hash(vec![test_leaf_4, test_leaf_3]);
        let test_node_2 = canonical_hash(vec![test_leaf_2, test_leaf_1]);
        let test_root   = canonical_hash(vec![test_node_1, test_node_2]);

        let result      = merkle_root(values);
        assert_eq!(result, test_root);
    }
}
<|endoftext|>


<commit_before>#![feature(plugin_registrar, rustc_private)]

extern crate itertools;
extern crate rustc_plugin;
extern crate syntax;

use itertools::Itertools;
use rustc_plugin::Registry;
use syntax::ast::{self, Ident, TraitRef, Ty, TyKind};
use syntax::ast::LitKind::Str;
use syntax::ast::MetaItemKind::NameValue;
use syntax::codemap::Spanned;
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ext::quote::rt::Span;
use syntax::parse::{self, token, PResult};
use syntax::parse::parser::{Parser, PathStyle};
use syntax::symbol::Symbol;
use syntax::ptr::P;
use syntax::tokenstream::TokenTree;
use syntax::util::small_vector::SmallVector;

fn snake_to_camel(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), tts.into());
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.

    let mut item = match parser.parse_trait_item() {
        Ok(s) => s,
        Err(mut diagnostic) => {
            diagnostic.emit();
            return DummyResult::any(sp);
        }
    };

    if let Err(mut diagnostic) = parser.expect(&token::Eof) {
        diagnostic.emit();
        return DummyResult::any(sp);
    }

    let old_ident = convert(&mut item.ident);

    // As far as I know, it's not possible in macro_rules! to reference an $ident in a doc string,
    // so this is the hacky workaround.
    //
    // This code looks intimidating, but it's just iterating through the trait item's attributes
    // (NameValues), filtering out non-doc attributes, and replacing any {} in the doc string with
    // the original, snake_case ident.
    for attr in item.attrs.iter_mut().filter(|attr| attr.is_sugared_doc) {
        if let NameValue(Spanned { node: Str(ref mut doc, _), .. }) = attr.value.node {
            *doc = Symbol::intern(&doc.as_str().replace("{}", &old_ident));
        } else {
            unreachable!()
        };
    }

    MacEager::trait_items(SmallVector::one(item))
}

fn impl_snake_to_camel(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), tts.into());
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.

    let mut item = match parser.parse_impl_item() {
        Ok(s) => s,
        Err(mut diagnostic) => {
            diagnostic.emit();
            return DummyResult::any(sp);
        }
    };

    if let Err(mut diagnostic) = parser.expect(&token::Eof) {
        diagnostic.emit();
        return DummyResult::any(sp);
    }

    convert(&mut item.ident);
    MacEager::impl_items(SmallVector::one(item))
}

fn ty_snake_to_camel(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), tts.into());
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.

    let mut ty = match parser.parse_ty_path() {
        Ok(s) => s,
        Err(mut diagnostic) => {
            diagnostic.emit();
            return DummyResult::any(sp);
        }
    };

    if let Err(mut diagnostic) = parser.expect(&token::Eof) {
        diagnostic.emit();
        return DummyResult::any(sp);
    }

    // Only capitalize the final segment
    if let TyKind::Path(_, ref mut path) = ty {
        convert(&mut path.segments.last_mut().unwrap().identifier);
    } else {
        unreachable!()
    }
    MacEager::ty(P(Ty {
        id: ast::DUMMY_NODE_ID,
        node: ty,
        span: sp,
    }))
}

/// Converts an ident in-place to CamelCase and returns the previous ident.
fn convert(ident: &mut Ident) -> String {
    let ident_str = ident.to_string();
    let mut camel_ty = String::new();

    {
        // Find the first non-underscore and add it capitalized.
        let mut chars = ident_str.chars();

        // Find the first non-underscore char, uppercase it, and append it.
        // Guaranteed to succeed because all idents must have at least one non-underscore char.
        camel_ty.extend(chars.find(|&c| c != '_').unwrap().to_uppercase());

        // When we find an underscore, we remove it and capitalize the next char. To do this,
        // we need to ensure the next char is not another underscore.
        let mut chars = chars.coalesce(|c1, c2| {
            if c1 == '_' && c2 == '_' {
                Ok(c1)
            } else {
                Err((c1, c2))
            }
        });

        while let Some(c) = chars.next() {
            if c != '_' {
                camel_ty.push(c);
            } else {
                if let Some(c) = chars.next() {
                    camel_ty.extend(c.to_uppercase());
                }
            }
        }
    }

    // The Fut suffix is hardcoded right now; this macro isn't really meant to be general-purpose.
    camel_ty.push_str("Fut");

    *ident = Ident::with_empty_ctxt(Symbol::intern(&camel_ty));
    ident_str
}

trait ParseTraitRef {
    fn parse_trait_ref(&mut self) -> PResult<TraitRef>;
}

impl<'a> ParseTraitRef for Parser<'a> {
    /// Parse a::B<String,i32>
    fn parse_trait_ref(&mut self) -> PResult<TraitRef> {
        Ok(TraitRef {
            path: self.parse_path(PathStyle::Type)?,
            ref_id: ast::DUMMY_NODE_ID,
        })
    }
}

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("snake_to_camel", snake_to_camel);
    reg.register_macro("impl_snake_to_camel", impl_snake_to_camel);
    reg.register_macro("ty_snake_to_camel", ty_snake_to_camel);
}
<commit_msg>Fix following removal of Attribute.value (#136)<commit_after>#![feature(plugin_registrar, rustc_private)]

extern crate itertools;
extern crate rustc_plugin;
extern crate syntax;

use itertools::Itertools;
use rustc_plugin::Registry;
use syntax::ast::{self, Ident, TraitRef, Ty, TyKind};
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ext::quote::rt::Span;
use syntax::parse::{self, token, str_lit, PResult};
use syntax::parse::parser::{Parser, PathStyle};
use syntax::symbol::Symbol;
use syntax::ptr::P;
use syntax::tokenstream::{TokenTree, TokenStream};
use syntax::util::small_vector::SmallVector;

fn snake_to_camel(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), tts.into());
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.

    let mut item = match parser.parse_trait_item() {
        Ok(s) => s,
        Err(mut diagnostic) => {
            diagnostic.emit();
            return DummyResult::any(sp);
        }
    };

    if let Err(mut diagnostic) = parser.expect(&token::Eof) {
        diagnostic.emit();
        return DummyResult::any(sp);
    }

    let old_ident = convert(&mut item.ident);

    // As far as I know, it's not possible in macro_rules! to reference an $ident in a doc string,
    // so this is the hacky workaround.
    //
    // This code looks intimidating, but it's just iterating through the trait item's attributes
    // copying non-doc attributes, and modifying doc attributes such that replacing any {} in the
    // doc string instead holds the original, snake_case ident.
    let attrs: Vec<_> = item.attrs
        .drain(..)
        .map(|mut attr| {
            if !attr.is_sugared_doc {
                return attr;
            }

            // Getting at the underlying doc comment is surprisingly painful.
            // The call-chain goes something like:
            //
            //  - https://github.com/rust-lang/rust/blob/9c15de4fd59bee290848b5443c7e194fd5afb02c/src/libsyntax/attr.rs#L283
            //  - https://github.com/rust-lang/rust/blob/9c15de4fd59bee290848b5443c7e194fd5afb02c/src/libsyntax/attr.rs#L1067
            //  - https://github.com/rust-lang/rust/blob/9c15de4fd59bee290848b5443c7e194fd5afb02c/src/libsyntax/attr.rs#L1196
            //  - https://github.com/rust-lang/rust/blob/9c15de4fd59bee290848b5443c7e194fd5afb02c/src/libsyntax/parse/mod.rs#L399
            //  - https://github.com/rust-lang/rust/blob/9c15de4fd59bee290848b5443c7e194fd5afb02c/src/libsyntax/parse/mod.rs#L268
            //
            // Note that a docstring (i.e., something with is_sugared_doc) *always* has exactly two
            // tokens: an Eq followed by a Literal, where the Literal contains a Str_. We therefore
            // match against that, modifying the inner Str with our modified Symbol.
            let mut tokens = attr.tokens.clone().into_trees();
            if let Some(tt @ TokenTree::Token(_, token::Eq)) = tokens.next() {
                let mut docstr = tokens.next().expect("Docstrings must have literal docstring");
                if let TokenTree::Token(_, token::Literal(token::Str_(ref mut doc), _)) = docstr {
                    *doc = Symbol::intern(&str_lit(&doc.as_str()).replace("{}", &old_ident));
                } else {
                    unreachable!();
                }
                attr.tokens = TokenStream::concat(vec![tt.into(), docstr.into()]);
            } else {
                unreachable!();
            }

            attr
        })
        .collect();
    item.attrs.extend(attrs.into_iter());

    MacEager::trait_items(SmallVector::one(item))
}

fn impl_snake_to_camel(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), tts.into());
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.

    let mut item = match parser.parse_impl_item() {
        Ok(s) => s,
        Err(mut diagnostic) => {
            diagnostic.emit();
            return DummyResult::any(sp);
        }
    };

    if let Err(mut diagnostic) = parser.expect(&token::Eof) {
        diagnostic.emit();
        return DummyResult::any(sp);
    }

    convert(&mut item.ident);
    MacEager::impl_items(SmallVector::one(item))
}

fn ty_snake_to_camel(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), tts.into());
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.

    let mut ty = match parser.parse_ty_path() {
        Ok(s) => s,
        Err(mut diagnostic) => {
            diagnostic.emit();
            return DummyResult::any(sp);
        }
    };

    if let Err(mut diagnostic) = parser.expect(&token::Eof) {
        diagnostic.emit();
        return DummyResult::any(sp);
    }

    // Only capitalize the final segment
    if let TyKind::Path(_, ref mut path) = ty {
        convert(&mut path.segments.last_mut().unwrap().identifier);
    } else {
        unreachable!()
    }
    MacEager::ty(P(Ty {
        id: ast::DUMMY_NODE_ID,
        node: ty,
        span: sp,
    }))
}

/// Converts an ident in-place to CamelCase and returns the previous ident.
fn convert(ident: &mut Ident) -> String {
    let ident_str = ident.to_string();
    let mut camel_ty = String::new();

    {
        // Find the first non-underscore and add it capitalized.
        let mut chars = ident_str.chars();

        // Find the first non-underscore char, uppercase it, and append it.
        // Guaranteed to succeed because all idents must have at least one non-underscore char.
        camel_ty.extend(chars.find(|&c| c != '_').unwrap().to_uppercase());

        // When we find an underscore, we remove it and capitalize the next char. To do this,
        // we need to ensure the next char is not another underscore.
        let mut chars = chars.coalesce(|c1, c2| {
            if c1 == '_' && c2 == '_' {
                Ok(c1)
            } else {
                Err((c1, c2))
            }
        });

        while let Some(c) = chars.next() {
            if c != '_' {
                camel_ty.push(c);
            } else {
                if let Some(c) = chars.next() {
                    camel_ty.extend(c.to_uppercase());
                }
            }
        }
    }

    // The Fut suffix is hardcoded right now; this macro isn't really meant to be general-purpose.
    camel_ty.push_str("Fut");

    *ident = Ident::with_empty_ctxt(Symbol::intern(&camel_ty));
    ident_str
}

trait ParseTraitRef {
    fn parse_trait_ref(&mut self) -> PResult<TraitRef>;
}

impl<'a> ParseTraitRef for Parser<'a> {
    /// Parse a::B<String,i32>
    fn parse_trait_ref(&mut self) -> PResult<TraitRef> {
        Ok(TraitRef {
            path: self.parse_path(PathStyle::Type)?,
            ref_id: ast::DUMMY_NODE_ID,
        })
    }
}

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("snake_to_camel", snake_to_camel);
    reg.register_macro("impl_snake_to_camel", impl_snake_to_camel);
    reg.register_macro("ty_snake_to_camel", ty_snake_to_camel);
}
<|endoftext|>


<commit_before>// Copyright 2014 Tyler Neely
//
// 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.
//
extern crate rocksdb;

use rocksdb::{DB, Direction, IteratorMode, Options};

fn cba(input: &Box<[u8]>) -> Box<[u8]> {
    input.iter().cloned().collect::<Vec<_>>().into_boxed_slice()
}

#[test]
pub fn test_iterator() {
    let path = "_rust_rocksdb_iteratortest";
    {
        let k1: Box<[u8]> = b"k1".to_vec().into_boxed_slice();
        let k2: Box<[u8]> = b"k2".to_vec().into_boxed_slice();
        let k3: Box<[u8]> = b"k3".to_vec().into_boxed_slice();
        let k4: Box<[u8]> = b"k4".to_vec().into_boxed_slice();
        let v1: Box<[u8]> = b"v1111".to_vec().into_boxed_slice();
        let v2: Box<[u8]> = b"v2222".to_vec().into_boxed_slice();
        let v3: Box<[u8]> = b"v3333".to_vec().into_boxed_slice();
        let v4: Box<[u8]> = b"v4444".to_vec().into_boxed_slice();
        let db = DB::open_default(path).unwrap();
        let p = db.put(&*k1, &*v1);
        assert!(p.is_ok());
        let p = db.put(&*k2, &*v2);
        assert!(p.is_ok());
        let p = db.put(&*k3, &*v3);
        assert!(p.is_ok());
        let expected = vec![(cba(&k1), cba(&v1)), (cba(&k2), cba(&v2)), (cba(&k3), cba(&v3))];
        {
            let iterator1 = db.iterator(IteratorMode::Start);
            assert_eq!(iterator1.collect::<Vec<_>>(), expected);
        }
        // Test that it's idempotent
        {
            let iterator1 = db.iterator(IteratorMode::Start);
            assert_eq!(iterator1.collect::<Vec<_>>(), expected);
        }
        {
            let iterator1 = db.iterator(IteratorMode::Start);
            assert_eq!(iterator1.collect::<Vec<_>>(), expected);
        }
        {
            let iterator1 = db.iterator(IteratorMode::Start);
            assert_eq!(iterator1.collect::<Vec<_>>(), expected);
        }
        // Test it in reverse a few times
        {
            let iterator1 = db.iterator(IteratorMode::End);
            let mut tmp_vec = iterator1.collect::<Vec<_>>();
            tmp_vec.reverse();
            assert_eq!(tmp_vec, expected);
        }
        {
            let iterator1 = db.iterator(IteratorMode::End);
            let mut tmp_vec = iterator1.collect::<Vec<_>>();
            tmp_vec.reverse();
            assert_eq!(tmp_vec, expected);
        }
        {
            let iterator1 = db.iterator(IteratorMode::End);
            let mut tmp_vec = iterator1.collect::<Vec<_>>();
            tmp_vec.reverse();
            assert_eq!(tmp_vec, expected);
        }
        {
            let iterator1 = db.iterator(IteratorMode::End);
            let mut tmp_vec = iterator1.collect::<Vec<_>>();
            tmp_vec.reverse();
            assert_eq!(tmp_vec, expected);
        }
        {
            let iterator1 = db.iterator(IteratorMode::End);
            let mut tmp_vec = iterator1.collect::<Vec<_>>();
            tmp_vec.reverse();
            assert_eq!(tmp_vec, expected);
        }
        // Try it forward again
        {
            let iterator1 = db.iterator(IteratorMode::Start);
            assert_eq!(iterator1.collect::<Vec<_>>(), expected);
        }
        {
            let iterator1 = db.iterator(IteratorMode::Start);
            assert_eq!(iterator1.collect::<Vec<_>>(), expected);
        }

        let old_iterator = db.iterator(IteratorMode::Start);
        let p = db.put(&*k4, &*v4);
        assert!(p.is_ok());
        let expected2 = vec![(cba(&k1), cba(&v1)),
                             (cba(&k2), cba(&v2)),
                             (cba(&k3), cba(&v3)),
                             (cba(&k4), cba(&v4))];
        {
            assert_eq!(old_iterator.collect::<Vec<_>>(), expected);
        }
        {
            let iterator1 = db.iterator(IteratorMode::Start);
            assert_eq!(iterator1.collect::<Vec<_>>(), expected2);
        }
        {
            let iterator1 = db.iterator(IteratorMode::From(b"k2", Direction::Forward));
            let expected = vec![(cba(&k2), cba(&v2)), (cba(&k3), cba(&v3)), (cba(&k4), cba(&v4))];
            assert_eq!(iterator1.collect::<Vec<_>>(), expected);
        }
        {
            let iterator1 = db.iterator(IteratorMode::From(b"k2", Direction::Reverse));
            let expected = vec![(cba(&k2), cba(&v2)), (cba(&k1), cba(&v1))];
            assert_eq!(iterator1.collect::<Vec<_>>(), expected);
        }
        {
            let iterator1 = db.iterator(IteratorMode::From(b"k0", Direction::Forward));
            assert!(iterator1.valid());
            let iterator2 = db.iterator(IteratorMode::From(b"k1", Direction::Forward));
            assert!(iterator2.valid());
            let iterator3 = db.iterator(IteratorMode::From(b"k11", Direction::Forward));
            assert!(iterator3.valid());
            let iterator4 = db.iterator(IteratorMode::From(b"k5", Direction::Forward));
            assert!(!iterator4.valid());
            let iterator5 = db.iterator(IteratorMode::From(b"k0", Direction::Reverse));
            assert!(iterator5.valid());
            let iterator6 = db.iterator(IteratorMode::From(b"k1", Direction::Reverse));
            assert!(iterator6.valid());
            let iterator7 = db.iterator(IteratorMode::From(b"k11", Direction::Reverse));
            assert!(iterator7.valid());
            let iterator8 = db.iterator(IteratorMode::From(b"k5", Direction::Reverse));
            assert!(!iterator8.valid());
        }
        {
            let mut iterator1 = db.iterator(IteratorMode::From(b"k4", Direction::Forward));
            iterator1.next();
            assert!(iterator1.valid());
            iterator1.next();
            assert!(!iterator1.valid());
        }
    }
    let opts = Options::default();
    assert!(DB::destroy(&opts, path).is_ok());
}

fn key(k: &[u8]) -> Box<[u8]> { k.to_vec().into_boxed_slice() }

#[test]
pub fn test_prefix_iterator() {
    let path = "_rust_rocksdb_prefixiteratortest";
    {
        let a1: Box<[u8]> = key(b"aaa1");
        let a2: Box<[u8]> = key(b"aaa2");
        let b1: Box<[u8]> = key(b"bbb1");
        let b2: Box<[u8]> = key(b"bbb2");

        let db = DB::open_default(path).unwrap();

        assert!(db.put(&*a1, &*a1).is_ok());
        assert!(db.put(&*a2, &*a2).is_ok());
        assert!(db.put(&*b1, &*b1).is_ok());
        assert!(db.put(&*b2, &*b2).is_ok());

        {
            let expected = vec![(cba(&a1), cba(&a1)), (cba(&a2), cba(&a2))];
            let a_iterator = db.prefix_iterator(b"aaa");
            assert_eq!(a_iterator.collect::<Vec<_>>(), expected)
        }

        {
            let expected = vec![(cba(&b1), cba(&b1)), (cba(&b2), cba(&b2))];
            let b_iterator = db.prefix_iterator(b"bbb");
            assert_eq!(b_iterator.collect::<Vec<_>>(), expected)
        }
    }
}
<commit_msg>fix prefix iterator by using a prefix extractor<commit_after>// Copyright 2014 Tyler Neely
//
// 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.
//
extern crate rocksdb;

use rocksdb::{DB, Direction, IteratorMode, Options};

fn cba(input: &Box<[u8]>) -> Box<[u8]> {
    input.iter().cloned().collect::<Vec<_>>().into_boxed_slice()
}

#[test]
pub fn test_iterator() {
    let path = "_rust_rocksdb_iteratortest";
    {
        let k1: Box<[u8]> = b"k1".to_vec().into_boxed_slice();
        let k2: Box<[u8]> = b"k2".to_vec().into_boxed_slice();
        let k3: Box<[u8]> = b"k3".to_vec().into_boxed_slice();
        let k4: Box<[u8]> = b"k4".to_vec().into_boxed_slice();
        let v1: Box<[u8]> = b"v1111".to_vec().into_boxed_slice();
        let v2: Box<[u8]> = b"v2222".to_vec().into_boxed_slice();
        let v3: Box<[u8]> = b"v3333".to_vec().into_boxed_slice();
        let v4: Box<[u8]> = b"v4444".to_vec().into_boxed_slice();
        let db = DB::open_default(path).unwrap();
        let p = db.put(&*k1, &*v1);
        assert!(p.is_ok());
        let p = db.put(&*k2, &*v2);
        assert!(p.is_ok());
        let p = db.put(&*k3, &*v3);
        assert!(p.is_ok());
        let expected = vec![(cba(&k1), cba(&v1)), (cba(&k2), cba(&v2)), (cba(&k3), cba(&v3))];
        {
            let iterator1 = db.iterator(IteratorMode::Start);
            assert_eq!(iterator1.collect::<Vec<_>>(), expected);
        }
        // Test that it's idempotent
        {
            let iterator1 = db.iterator(IteratorMode::Start);
            assert_eq!(iterator1.collect::<Vec<_>>(), expected);
        }
        {
            let iterator1 = db.iterator(IteratorMode::Start);
            assert_eq!(iterator1.collect::<Vec<_>>(), expected);
        }
        {
            let iterator1 = db.iterator(IteratorMode::Start);
            assert_eq!(iterator1.collect::<Vec<_>>(), expected);
        }
        // Test it in reverse a few times
        {
            let iterator1 = db.iterator(IteratorMode::End);
            let mut tmp_vec = iterator1.collect::<Vec<_>>();
            tmp_vec.reverse();
            assert_eq!(tmp_vec, expected);
        }
        {
            let iterator1 = db.iterator(IteratorMode::End);
            let mut tmp_vec = iterator1.collect::<Vec<_>>();
            tmp_vec.reverse();
            assert_eq!(tmp_vec, expected);
        }
        {
            let iterator1 = db.iterator(IteratorMode::End);
            let mut tmp_vec = iterator1.collect::<Vec<_>>();
            tmp_vec.reverse();
            assert_eq!(tmp_vec, expected);
        }
        {
            let iterator1 = db.iterator(IteratorMode::End);
            let mut tmp_vec = iterator1.collect::<Vec<_>>();
            tmp_vec.reverse();
            assert_eq!(tmp_vec, expected);
        }
        {
            let iterator1 = db.iterator(IteratorMode::End);
            let mut tmp_vec = iterator1.collect::<Vec<_>>();
            tmp_vec.reverse();
            assert_eq!(tmp_vec, expected);
        }
        // Try it forward again
        {
            let iterator1 = db.iterator(IteratorMode::Start);
            assert_eq!(iterator1.collect::<Vec<_>>(), expected);
        }
        {
            let iterator1 = db.iterator(IteratorMode::Start);
            assert_eq!(iterator1.collect::<Vec<_>>(), expected);
        }

        let old_iterator = db.iterator(IteratorMode::Start);
        let p = db.put(&*k4, &*v4);
        assert!(p.is_ok());
        let expected2 = vec![(cba(&k1), cba(&v1)),
                             (cba(&k2), cba(&v2)),
                             (cba(&k3), cba(&v3)),
                             (cba(&k4), cba(&v4))];
        {
            assert_eq!(old_iterator.collect::<Vec<_>>(), expected);
        }
        {
            let iterator1 = db.iterator(IteratorMode::Start);
            assert_eq!(iterator1.collect::<Vec<_>>(), expected2);
        }
        {
            let iterator1 = db.iterator(IteratorMode::From(b"k2", Direction::Forward));
            let expected = vec![(cba(&k2), cba(&v2)), (cba(&k3), cba(&v3)), (cba(&k4), cba(&v4))];
            assert_eq!(iterator1.collect::<Vec<_>>(), expected);
        }
        {
            let iterator1 = db.iterator(IteratorMode::From(b"k2", Direction::Reverse));
            let expected = vec![(cba(&k2), cba(&v2)), (cba(&k1), cba(&v1))];
            assert_eq!(iterator1.collect::<Vec<_>>(), expected);
        }
        {
            let iterator1 = db.iterator(IteratorMode::From(b"k0", Direction::Forward));
            assert!(iterator1.valid());
            let iterator2 = db.iterator(IteratorMode::From(b"k1", Direction::Forward));
            assert!(iterator2.valid());
            let iterator3 = db.iterator(IteratorMode::From(b"k11", Direction::Forward));
            assert!(iterator3.valid());
            let iterator4 = db.iterator(IteratorMode::From(b"k5", Direction::Forward));
            assert!(!iterator4.valid());
            let iterator5 = db.iterator(IteratorMode::From(b"k0", Direction::Reverse));
            assert!(iterator5.valid());
            let iterator6 = db.iterator(IteratorMode::From(b"k1", Direction::Reverse));
            assert!(iterator6.valid());
            let iterator7 = db.iterator(IteratorMode::From(b"k11", Direction::Reverse));
            assert!(iterator7.valid());
            let iterator8 = db.iterator(IteratorMode::From(b"k5", Direction::Reverse));
            assert!(!iterator8.valid());
        }
        {
            let mut iterator1 = db.iterator(IteratorMode::From(b"k4", Direction::Forward));
            iterator1.next();
            assert!(iterator1.valid());
            iterator1.next();
            assert!(!iterator1.valid());
        }
    }
    let opts = Options::default();
    assert!(DB::destroy(&opts, path).is_ok());
}

fn key(k: &[u8]) -> Box<[u8]> { k.to_vec().into_boxed_slice() }

#[test]
pub fn test_prefix_iterator() {
    let path = "_rust_rocksdb_prefixiteratortest";
    {
        let a1: Box<[u8]> = key(b"aaa1");
        let a2: Box<[u8]> = key(b"aaa2");
        let b1: Box<[u8]> = key(b"bbb1");
        let b2: Box<[u8]> = key(b"bbb2");

        let mut opts = Options::default();
        let prefix_extractor = rocksdb::SliceTransform::create_fixed_prefix(3);
        opts.set_prefix_extractor(prefix_extractor);

        let db = DB::open(&opts, path).unwrap();

        assert!(db.put(&*a1, &*a1).is_ok());
        assert!(db.put(&*a2, &*a2).is_ok());
        assert!(db.put(&*b1, &*b1).is_ok());
        assert!(db.put(&*b2, &*b2).is_ok());

        {
            let expected = vec![(cba(&a1), cba(&a1)), (cba(&a2), cba(&a2))];
            let a_iterator = db.prefix_iterator(b"aaa");
            assert_eq!(a_iterator.collect::<Vec<_>>(), expected)
        }

        {
            let expected = vec![(cba(&b1), cba(&b1)), (cba(&b2), cba(&b2))];
            let b_iterator = db.prefix_iterator(b"bbb");
            assert_eq!(b_iterator.collect::<Vec<_>>(), expected)
        }
    }
}
<|endoftext|>


<commit_before>//! Mock request dispatcher and credentials for unit testing rusoto AWS service clients
//!
//! All rusoto generated service clients come with a constuctor function named `new_with` which
//! accepts three arguments
//!
//! * A `rusoto_core::DispatchSignedRequest` implementation
//! * A `rusoto_core::credential::ProvideAwsCredentials` implementation
//! * A `rusoto_core::Region`
//!
//! This crate provides mock implementations to satisfy the first two.
//!
//! # Example
//!
//! ```rust
//! extern crate rusoto_mock;
//! // extern crate rusoto_s3;
//!
//! use rusoto_mock::{MockCredentialsProvider, MockRequestDispatcher, MockResponseReader};
//!
//! fn main() {
//!    // let s3 = rusoto_s3::S3Client::new_with(
//!    //   MockRequestDispatcher::default().with_body(
//!    //      MockResponseReader::read_response("test-data", "s3-response.json")
//!    //   ),
//!    //   MockCredentialsProvider,
//!    //   Default::default()
//!    // );
//! }
//! ```
#![deny(missing_docs)]
extern crate chrono;
extern crate futures;
extern crate http;
extern crate rusoto_core;

use std::fs::File;
use std::io::Read;
use std::collections::HashMap;
use std::time::Duration;

use rusoto_core::{DispatchSignedRequest, HttpDispatchError};
use rusoto_core::credential::{ProvideAwsCredentials, CredentialsError, AwsCredentials};
use rusoto_core::request::{Headers, HttpResponse};
use rusoto_core::signature::SignedRequest;
use futures::future::{FutureResult, ok};
use futures::stream::once;
use http::{HttpTryFrom, StatusCode};

/// Provides a set of credentials that always resolve
/// successfully
pub struct MockCredentialsProvider;

impl ProvideAwsCredentials for MockCredentialsProvider {
    type Future = FutureResult<AwsCredentials, CredentialsError>;

    fn credentials(&self) -> Self::Future {
        ok(AwsCredentials::new("mock_key",
                               "mock_secret",
                               None,
                               None))
    }
}

/// Composes mock API responses
///
/// A Default is provided which returns an successful response with an empty body
///
/// These can be constructed using either a Default implementation or
///  with the [with_status](method.with_status) function.
///
#[derive(Default)]
pub struct MockRequestDispatcher {
    status: StatusCode,
    body: Vec<u8>,
    headers: HashMap<String, String>,
    request_checker: Option<Box<Fn(&SignedRequest) + Send + Sync>>,
}

impl MockRequestDispatcher {
    /// Returns a instance that mocks the status code that would
    /// be returned from AWS
    pub fn with_status(status: u16) -> MockRequestDispatcher {
        MockRequestDispatcher {
            status: StatusCode::try_from(status).unwrap(),
            ..MockRequestDispatcher::default()
        }
    }

    /// Mocks the service response body what would be
    /// returned from AWS
    pub fn with_body(mut self, body: &str) -> MockRequestDispatcher {
        self.body = body.as_bytes().to_vec();
        self
    }

    /// Mocks the signed request checking applied to a request before sending
    /// to AWS
    pub fn with_request_checker<F>(mut self, checker: F) -> MockRequestDispatcher
        where F: Fn(&SignedRequest) + Send + Sync + 'static {
        self.request_checker = Some(Box::new(checker));
        self
    }

    /// Mocks a single service header that would be returned from AWS
    pub fn with_header(mut self, key: &str, value: &str) -> MockRequestDispatcher {
        self.headers.insert(key.into(), value.into());
        self
    }
}

impl DispatchSignedRequest for MockRequestDispatcher {
    type Future = FutureResult<HttpResponse, HttpDispatchError>;

    fn dispatch(&self, request: SignedRequest, _timeout: Option<Duration>) -> Self::Future {
        if self.request_checker.is_some() {
            self.request_checker.as_ref().unwrap()(&request);
        }
        ok(HttpResponse {
            status: self.status,
            body: Box::new(once(Ok(self.body.clone()))),
            headers: Headers::new(self.headers.iter().map(|(k, v)| (k.as_ref(), v.to_owned()))),
        })
    }
}

/// An interface for producing response body content
pub trait ReadMockResponse {
    /// Return a response body string for a given directory and file name
    fn read_response(dir_name: &str, file_name: &str) -> String;
}

/// Reads response body content from disk
pub struct MockResponseReader;

impl ReadMockResponse for MockResponseReader {
    fn read_response(dir_name: &str, response_name: &str) -> String {
        let file_name = format!("{}/{}", dir_name, response_name);

        let mut input_file = File::open(&file_name).expect("couldn't find file");

        let mut mock_response = String::new();

        input_file.read_to_string(&mut mock_response).expect(&format!(
	        "Failed to read {:?}",
	        file_name,
	    ));

        mock_response
    }
}
<commit_msg>document the example<commit_after>//! Mock request dispatcher and credentials for unit testing rusoto AWS service clients
//!
//! All rusoto generated service clients come with a constuctor function named `new_with` which
//! accepts three arguments
//!
//! * A `rusoto_core::DispatchSignedRequest` implementation
//! * A `rusoto_core::credential::ProvideAwsCredentials` implementation
//! * A `rusoto_core::Region`
//!
//! This crate provides mock implementations to satisfy the first two.
//!
//! # Example
//!
//! The following is an example for the `rusoto_s3` crate but should
//! work for all service crates just the same. The code is commented
//! out for illustration but also to avoid a cyclic dependency in this crate.
//!
//! ```rust
//! extern crate rusoto_mock;
//! // extern crate rusoto_s3;
//!
//! use rusoto_mock::{MockCredentialsProvider, MockRequestDispatcher, MockResponseReader};
//!
//! fn main() {
//!    // let s3 = rusoto_s3::S3Client::new_with(
//!    //   MockRequestDispatcher::default().with_body(
//!    //      MockResponseReader::read_response("test-data", "s3-response.json")
//!    //   ),
//!    //   MockCredentialsProvider,
//!    //   Default::default()
//!    // );
//! }
//! ```
#![deny(missing_docs)]
extern crate chrono;
extern crate futures;
extern crate http;
extern crate rusoto_core;

use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::time::Duration;

use futures::future::{ok, FutureResult};
use futures::stream::once;
use http::{HttpTryFrom, StatusCode};
use rusoto_core::credential::{AwsCredentials, CredentialsError, ProvideAwsCredentials};
use rusoto_core::request::{Headers, HttpResponse};
use rusoto_core::signature::SignedRequest;
use rusoto_core::{DispatchSignedRequest, HttpDispatchError};

/// Provides a set of credentials that always resolve
/// successfully
pub struct MockCredentialsProvider;

impl ProvideAwsCredentials for MockCredentialsProvider {
    type Future = FutureResult<AwsCredentials, CredentialsError>;

    fn credentials(&self) -> Self::Future {
        ok(AwsCredentials::new("mock_key", "mock_secret", None, None))
    }
}

/// Composes mock API responses
///
/// A Default is provided which returns an successful response with an empty body
///
/// These can be constructed using either a Default implementation or
///  with the [with_status](method.with_status) function.
///
#[derive(Default)]
pub struct MockRequestDispatcher {
    status: StatusCode,
    body: Vec<u8>,
    headers: HashMap<String, String>,
    request_checker: Option<Box<Fn(&SignedRequest) + Send + Sync>>,
}

impl MockRequestDispatcher {
    /// Returns a instance that mocks the status code that would
    /// be returned from AWS
    pub fn with_status(status: u16) -> MockRequestDispatcher {
        MockRequestDispatcher {
            status: StatusCode::try_from(status).unwrap(),
            ..MockRequestDispatcher::default()
        }
    }

    /// Mocks the service response body what would be
    /// returned from AWS
    pub fn with_body(mut self, body: &str) -> MockRequestDispatcher {
        self.body = body.as_bytes().to_vec();
        self
    }

    /// Mocks the signed request checking applied to a request before sending
    /// to AWS
    pub fn with_request_checker<F>(mut self, checker: F) -> MockRequestDispatcher
    where
        F: Fn(&SignedRequest) + Send + Sync + 'static,
    {
        self.request_checker = Some(Box::new(checker));
        self
    }

    /// Mocks a single service header that would be returned from AWS
    pub fn with_header(mut self, key: &str, value: &str) -> MockRequestDispatcher {
        self.headers.insert(key.into(), value.into());
        self
    }
}

impl DispatchSignedRequest for MockRequestDispatcher {
    type Future = FutureResult<HttpResponse, HttpDispatchError>;

    fn dispatch(&self, request: SignedRequest, _timeout: Option<Duration>) -> Self::Future {
        if self.request_checker.is_some() {
            self.request_checker.as_ref().unwrap()(&request);
        }
        ok(HttpResponse {
            status: self.status,
            body: Box::new(once(Ok(self.body.clone()))),
            headers: Headers::new(self.headers.iter().map(|(k, v)| (k.as_ref(), v.to_owned()))),
        })
    }
}

/// An interface for producing response body content
pub trait ReadMockResponse {
    /// Return a response body string for a given directory and file name
    fn read_response(dir_name: &str, file_name: &str) -> String;
}

/// Reads response body content from disk
pub struct MockResponseReader;

impl ReadMockResponse for MockResponseReader {
    fn read_response(dir_name: &str, response_name: &str) -> String {
        let file_name = format!("{}/{}", dir_name, response_name);

        let mut input_file = File::open(&file_name).expect("couldn't find file");

        let mut mock_response = String::new();

        input_file
            .read_to_string(&mut mock_response)
            .expect(&format!("Failed to read {:?}", file_name,));

        mock_response
    }
}
<|endoftext|>