<commit_before>//! This module handles fuzzy-searching of functions, structs and other symbols
//! by name across the whole workspace and dependencies.
//!
//! It works by building an incrementally-updated text-search index of all
//! symbols. The backbone of the index is the **awesome** `fst` crate by
//! @BurntSushi.
//!
//! In a nutshell, you give a set of strings to `fst`, and it builds a
//! finite state machine describing this set of strings. The strings which
//! could fuzzy-match a pattern can also be described by a finite state machine.
//! What is freaking cool is that you can now traverse both state machines in
//! lock-step to enumerate the strings which are both in the input set and
//! fuzz-match the query. Or, more formally, given two languages described by
//! FSTs, one can build a product FST which describes the intersection of the
//! languages.
//!
//! `fst` does not support cheap updating of the index, but it supports unioning
//! of state machines. So, to account for changing source code, we build an FST
//! for each library (which is assumed to never change) and an FST for each Rust
//! file in the current workspace, and run a query against the union of all
//! those FSTs.

use std::{
    cmp::Ordering,
    fmt,
    hash::{Hash, Hasher},
    mem,
    sync::Arc,
};

use fst::{self, Streamer};
use ra_db::{
    salsa::{self, ParallelDatabase},
    FileId, SourceDatabaseExt, SourceRootId,
};
use ra_syntax::{
    ast::{self, NameOwner},
    match_ast, AstNode, Parse, SmolStr, SourceFile,
    SyntaxKind::{self, *},
    SyntaxNode, SyntaxNodePtr, TextRange, WalkEvent,
};
#[cfg(not(feature = "wasm"))]
use rayon::prelude::*;

use crate::RootDatabase;

#[derive(Debug)]
pub struct Query {
    query: String,
    lowercased: String,
    only_types: bool,
    libs: bool,
    exact: bool,
    limit: usize,
}

impl Query {
    pub fn new(query: String) -> Query {
        let lowercased = query.to_lowercase();
        Query {
            query,
            lowercased,
            only_types: false,
            libs: false,
            exact: false,
            limit: usize::max_value(),
        }
    }

    pub fn only_types(&mut self) {
        self.only_types = true;
    }

    pub fn libs(&mut self) {
        self.libs = true;
    }

    pub fn exact(&mut self) {
        self.exact = true;
    }

    pub fn limit(&mut self, limit: usize) {
        self.limit = limit
    }
}

#[salsa::query_group(SymbolsDatabaseStorage)]
pub trait SymbolsDatabase: hir::db::HirDatabase {
    fn file_symbols(&self, file_id: FileId) -> Arc<SymbolIndex>;
    #[salsa::input]
    fn library_symbols(&self, id: SourceRootId) -> Arc<SymbolIndex>;
    /// The set of "local" (that is, from the current workspace) roots.
    /// Files in local roots are assumed to change frequently.
    #[salsa::input]
    fn local_roots(&self) -> Arc<Vec<SourceRootId>>;
    /// The set of roots for crates.io libraries.
    /// Files in libraries are assumed to never change.
    #[salsa::input]
    fn library_roots(&self) -> Arc<Vec<SourceRootId>>;
}

fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> {
    db.check_canceled();
    let parse = db.parse(file_id);

    let symbols = source_file_to_file_symbols(&parse.tree(), file_id);

    // FIXME: add macros here

    Arc::new(SymbolIndex::new(symbols))
}

// Feature: Workspace Symbol
//
// Uses fuzzy-search to find types, modules and functions by name across your
// project and dependencies. This is **the** most useful feature, which improves code
// navigation tremendously. It mostly works on top of the built-in LSP
// functionality, however `#` and `*` symbols can be used to narrow down the
// search. Specifically,
//
// - `Foo` searches for `Foo` type in the current workspace
// - `foo#` searches for `foo` function in the current workspace
// - `Foo*` searches for `Foo` type among dependencies, including `stdlib`
// - `foo#*` searches for `foo` function among dependencies
//
// That is, `#` switches from "types" to all symbols, `*` switches from the current
// workspace to dependencies.
//
// |===
// | Editor  | Shortcut
//
// | VS Code | kbd:[Ctrl+T]
// |===
pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
    let _p = ra_prof::profile("world_symbols").detail(|| query.query.clone());

    /// Need to wrap Snapshot to provide `Clone` impl for `map_with`
    struct Snap(salsa::Snapshot<RootDatabase>);
    impl Clone for Snap {
        fn clone(&self) -> Snap {
            Snap(self.0.snapshot())
        }
    }

    let buf: Vec<Arc<SymbolIndex>> = if query.libs {
        let snap = Snap(db.snapshot());
        #[cfg(not(feature = "wasm"))]
        let buf = db
            .library_roots()
            .par_iter()
            .map_with(snap, |db, &lib_id| db.0.library_symbols(lib_id))
            .collect();

        #[cfg(feature = "wasm")]
        let buf = db.library_roots().iter().map(|&lib_id| snap.0.library_symbols(lib_id)).collect();

        buf
    } else {
        let mut files = Vec::new();
        for &root in db.local_roots().iter() {
            let sr = db.source_root(root);
            files.extend(sr.walk())
        }

        let snap = Snap(db.snapshot());
        #[cfg(not(feature = "wasm"))]
        let buf =
            files.par_iter().map_with(snap, |db, &file_id| db.0.file_symbols(file_id)).collect();

        #[cfg(feature = "wasm")]
        let buf = files.iter().map(|&file_id| snap.0.file_symbols(file_id)).collect();

        buf
    };
    query.search(&buf)
}

pub fn index_resolve(db: &RootDatabase, name_ref: &ast::NameRef) -> Vec<FileSymbol> {
    let name = name_ref.text();
    let mut query = Query::new(name.to_string());
    query.exact();
    query.limit(4);
    world_symbols(db, query)
}

#[derive(Default)]
pub struct SymbolIndex {
    symbols: Vec<FileSymbol>,
    map: fst::Map<Vec<u8>>,
}

impl fmt::Debug for SymbolIndex {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("SymbolIndex").field("n_symbols", &self.symbols.len()).finish()
    }
}

impl PartialEq for SymbolIndex {
    fn eq(&self, other: &SymbolIndex) -> bool {
        self.symbols == other.symbols
    }
}

impl Eq for SymbolIndex {}

impl Hash for SymbolIndex {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.symbols.hash(hasher)
    }
}

impl SymbolIndex {
    fn new(mut symbols: Vec<FileSymbol>) -> SymbolIndex {
        fn cmp(lhs: &FileSymbol, rhs: &FileSymbol) -> Ordering {
            let lhs_chars = lhs.name.chars().map(|c| c.to_ascii_lowercase());
            let rhs_chars = rhs.name.chars().map(|c| c.to_ascii_lowercase());
            lhs_chars.cmp(rhs_chars)
        }

        #[cfg(not(feature = "wasm"))]
        symbols.par_sort_by(cmp);

        #[cfg(feature = "wasm")]
        symbols.sort_by(cmp);

        let mut builder = fst::MapBuilder::memory();

        let mut last_batch_start = 0;

        for idx in 0..symbols.len() {
            if let Some(next_symbol) = symbols.get(idx + 1) {
                if cmp(&symbols[last_batch_start], next_symbol) == Ordering::Equal {
                    continue;
                }
            }

            let start = last_batch_start;
            let end = idx + 1;
            last_batch_start = end;

            let key = symbols[start].name.as_str().to_ascii_lowercase();
            let value = SymbolIndex::range_to_map_value(start, end);

            builder.insert(key, value).unwrap();
        }

        let map = fst::Map::new(builder.into_inner().unwrap()).unwrap();
        SymbolIndex { symbols, map }
    }

    pub fn len(&self) -> usize {
        self.symbols.len()
    }

    pub fn memory_size(&self) -> usize {
        self.map.as_fst().size() + self.symbols.len() * mem::size_of::<FileSymbol>()
    }

    #[cfg(not(feature = "wasm"))]
    pub(crate) fn for_files(
        files: impl ParallelIterator<Item = (FileId, Parse<ast::SourceFile>)>,
    ) -> SymbolIndex {
        let symbols = files
            .flat_map(|(file_id, file)| source_file_to_file_symbols(&file.tree(), file_id))
            .collect::<Vec<_>>();
        SymbolIndex::new(symbols)
    }

    #[cfg(feature = "wasm")]
    pub(crate) fn for_files(
        files: impl Iterator<Item = (FileId, Parse<ast::SourceFile>)>,
    ) -> SymbolIndex {
        let symbols = files
            .flat_map(|(file_id, file)| source_file_to_file_symbols(&file.tree(), file_id))
            .collect::<Vec<_>>();
        SymbolIndex::new(symbols)
    }

    fn range_to_map_value(start: usize, end: usize) -> u64 {
        debug_assert![start <= (std::u32::MAX as usize)];
        debug_assert![end <= (std::u32::MAX as usize)];

        ((start as u64) << 32) | end as u64
    }

    fn map_value_to_range(value: u64) -> (usize, usize) {
        let end = value as u32 as usize;
        let start = (value >> 32) as usize;
        (start, end)
    }
}

impl Query {
    pub(crate) fn search(self, indices: &[Arc<SymbolIndex>]) -> Vec<FileSymbol> {
        let mut op = fst::map::OpBuilder::new();
        for file_symbols in indices.iter() {
            let automaton = fst::automaton::Subsequence::new(&self.lowercased);
            op = op.add(file_symbols.map.search(automaton))
        }
        let mut stream = op.union();
        let mut res = Vec::new();
        while let Some((_, indexed_values)) = stream.next() {
            if res.len() >= self.limit {
                break;
            }
            for indexed_value in indexed_values {
                let symbol_index = &indices[indexed_value.index];
                let (start, end) = SymbolIndex::map_value_to_range(indexed_value.value);

                for symbol in &symbol_index.symbols[start..end] {
                    if self.only_types && !is_type(symbol.kind) {
                        continue;
                    }
                    if self.exact && symbol.name != self.query {
                        continue;
                    }
                    res.push(symbol.clone());
                }
            }
        }
        res
    }
}

fn is_type(kind: SyntaxKind) -> bool {
    match kind {
        STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => true,
        _ => false,
    }
}

/// The actual data that is stored in the index. It should be as compact as
/// possible.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FileSymbol {
    pub file_id: FileId,
    pub name: SmolStr,
    pub kind: SyntaxKind,
    pub range: TextRange,
    pub ptr: SyntaxNodePtr,
    pub name_range: Option<TextRange>,
    pub container_name: Option<SmolStr>,
}

fn source_file_to_file_symbols(source_file: &SourceFile, file_id: FileId) -> Vec<FileSymbol> {
    let mut symbols = Vec::new();
    let mut stack = Vec::new();

    for event in source_file.syntax().preorder() {
        match event {
            WalkEvent::Enter(node) => {
                if let Some(mut symbol) = to_file_symbol(&node, file_id) {
                    symbol.container_name = stack.last().cloned();

                    stack.push(symbol.name.clone());
                    symbols.push(symbol);
                }
            }

            WalkEvent::Leave(node) => {
                if to_symbol(&node).is_some() {
                    stack.pop();
                }
            }
        }
    }

    symbols
}

fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> {
    fn decl<N: NameOwner>(node: N) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> {
        let name = node.name()?;
        let name_range = name.syntax().text_range();
        let name = name.text().clone();
        let ptr = SyntaxNodePtr::new(node.syntax());

        Some((name, ptr, name_range))
    }
    match_ast! {
        match node {
            ast::FnDef(it) => decl(it),
            ast::StructDef(it) => decl(it),
            ast::EnumDef(it) => decl(it),
            ast::TraitDef(it) => decl(it),
            ast::Module(it) => decl(it),
            ast::TypeAliasDef(it) => decl(it),
            ast::ConstDef(it) => decl(it),
            ast::StaticDef(it) => decl(it),
            ast::MacroCall(it) => {
                if it.is_macro_rules().is_some() {
                    decl(it)
                } else {
                    None
                }
            },
            _ => None,
        }
    }
}

fn to_file_symbol(node: &SyntaxNode, file_id: FileId) -> Option<FileSymbol> {
    to_symbol(node).map(move |(name, ptr, name_range)| FileSymbol {
        name,
        kind: node.kind(),
        range: node.text_range(),
        ptr,
        file_id,
        name_range: Some(name_range),
        container_name: None,
    })
}
<commit_msg>Fix the symbol query limit<commit_after>//! This module handles fuzzy-searching of functions, structs and other symbols
//! by name across the whole workspace and dependencies.
//!
//! It works by building an incrementally-updated text-search index of all
//! symbols. The backbone of the index is the **awesome** `fst` crate by
//! @BurntSushi.
//!
//! In a nutshell, you give a set of strings to `fst`, and it builds a
//! finite state machine describing this set of strings. The strings which
//! could fuzzy-match a pattern can also be described by a finite state machine.
//! What is freaking cool is that you can now traverse both state machines in
//! lock-step to enumerate the strings which are both in the input set and
//! fuzz-match the query. Or, more formally, given two languages described by
//! FSTs, one can build a product FST which describes the intersection of the
//! languages.
//!
//! `fst` does not support cheap updating of the index, but it supports unioning
//! of state machines. So, to account for changing source code, we build an FST
//! for each library (which is assumed to never change) and an FST for each Rust
//! file in the current workspace, and run a query against the union of all
//! those FSTs.

use std::{
    cmp::Ordering,
    fmt,
    hash::{Hash, Hasher},
    mem,
    sync::Arc,
};

use fst::{self, Streamer};
use ra_db::{
    salsa::{self, ParallelDatabase},
    FileId, SourceDatabaseExt, SourceRootId,
};
use ra_syntax::{
    ast::{self, NameOwner},
    match_ast, AstNode, Parse, SmolStr, SourceFile,
    SyntaxKind::{self, *},
    SyntaxNode, SyntaxNodePtr, TextRange, WalkEvent,
};
#[cfg(not(feature = "wasm"))]
use rayon::prelude::*;

use crate::RootDatabase;

#[derive(Debug)]
pub struct Query {
    query: String,
    lowercased: String,
    only_types: bool,
    libs: bool,
    exact: bool,
    limit: usize,
}

impl Query {
    pub fn new(query: String) -> Query {
        let lowercased = query.to_lowercase();
        Query {
            query,
            lowercased,
            only_types: false,
            libs: false,
            exact: false,
            limit: usize::max_value(),
        }
    }

    pub fn only_types(&mut self) {
        self.only_types = true;
    }

    pub fn libs(&mut self) {
        self.libs = true;
    }

    pub fn exact(&mut self) {
        self.exact = true;
    }

    pub fn limit(&mut self, limit: usize) {
        self.limit = limit
    }
}

#[salsa::query_group(SymbolsDatabaseStorage)]
pub trait SymbolsDatabase: hir::db::HirDatabase {
    fn file_symbols(&self, file_id: FileId) -> Arc<SymbolIndex>;
    #[salsa::input]
    fn library_symbols(&self, id: SourceRootId) -> Arc<SymbolIndex>;
    /// The set of "local" (that is, from the current workspace) roots.
    /// Files in local roots are assumed to change frequently.
    #[salsa::input]
    fn local_roots(&self) -> Arc<Vec<SourceRootId>>;
    /// The set of roots for crates.io libraries.
    /// Files in libraries are assumed to never change.
    #[salsa::input]
    fn library_roots(&self) -> Arc<Vec<SourceRootId>>;
}

fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> {
    db.check_canceled();
    let parse = db.parse(file_id);

    let symbols = source_file_to_file_symbols(&parse.tree(), file_id);

    // FIXME: add macros here

    Arc::new(SymbolIndex::new(symbols))
}

// Feature: Workspace Symbol
//
// Uses fuzzy-search to find types, modules and functions by name across your
// project and dependencies. This is **the** most useful feature, which improves code
// navigation tremendously. It mostly works on top of the built-in LSP
// functionality, however `#` and `*` symbols can be used to narrow down the
// search. Specifically,
//
// - `Foo` searches for `Foo` type in the current workspace
// - `foo#` searches for `foo` function in the current workspace
// - `Foo*` searches for `Foo` type among dependencies, including `stdlib`
// - `foo#*` searches for `foo` function among dependencies
//
// That is, `#` switches from "types" to all symbols, `*` switches from the current
// workspace to dependencies.
//
// |===
// | Editor  | Shortcut
//
// | VS Code | kbd:[Ctrl+T]
// |===
pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
    let _p = ra_prof::profile("world_symbols").detail(|| query.query.clone());

    /// Need to wrap Snapshot to provide `Clone` impl for `map_with`
    struct Snap(salsa::Snapshot<RootDatabase>);
    impl Clone for Snap {
        fn clone(&self) -> Snap {
            Snap(self.0.snapshot())
        }
    }

    let buf: Vec<Arc<SymbolIndex>> = if query.libs {
        let snap = Snap(db.snapshot());
        #[cfg(not(feature = "wasm"))]
        let buf = db
            .library_roots()
            .par_iter()
            .map_with(snap, |db, &lib_id| db.0.library_symbols(lib_id))
            .collect();

        #[cfg(feature = "wasm")]
        let buf = db.library_roots().iter().map(|&lib_id| snap.0.library_symbols(lib_id)).collect();

        buf
    } else {
        let mut files = Vec::new();
        for &root in db.local_roots().iter() {
            let sr = db.source_root(root);
            files.extend(sr.walk())
        }

        let snap = Snap(db.snapshot());
        #[cfg(not(feature = "wasm"))]
        let buf =
            files.par_iter().map_with(snap, |db, &file_id| db.0.file_symbols(file_id)).collect();

        #[cfg(feature = "wasm")]
        let buf = files.iter().map(|&file_id| snap.0.file_symbols(file_id)).collect();

        buf
    };
    query.search(&buf)
}

pub fn index_resolve(db: &RootDatabase, name_ref: &ast::NameRef) -> Vec<FileSymbol> {
    let name = name_ref.text();
    let mut query = Query::new(name.to_string());
    query.exact();
    query.limit(4);
    world_symbols(db, query)
}

#[derive(Default)]
pub struct SymbolIndex {
    symbols: Vec<FileSymbol>,
    map: fst::Map<Vec<u8>>,
}

impl fmt::Debug for SymbolIndex {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("SymbolIndex").field("n_symbols", &self.symbols.len()).finish()
    }
}

impl PartialEq for SymbolIndex {
    fn eq(&self, other: &SymbolIndex) -> bool {
        self.symbols == other.symbols
    }
}

impl Eq for SymbolIndex {}

impl Hash for SymbolIndex {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.symbols.hash(hasher)
    }
}

impl SymbolIndex {
    fn new(mut symbols: Vec<FileSymbol>) -> SymbolIndex {
        fn cmp(lhs: &FileSymbol, rhs: &FileSymbol) -> Ordering {
            let lhs_chars = lhs.name.chars().map(|c| c.to_ascii_lowercase());
            let rhs_chars = rhs.name.chars().map(|c| c.to_ascii_lowercase());
            lhs_chars.cmp(rhs_chars)
        }

        #[cfg(not(feature = "wasm"))]
        symbols.par_sort_by(cmp);

        #[cfg(feature = "wasm")]
        symbols.sort_by(cmp);

        let mut builder = fst::MapBuilder::memory();

        let mut last_batch_start = 0;

        for idx in 0..symbols.len() {
            if let Some(next_symbol) = symbols.get(idx + 1) {
                if cmp(&symbols[last_batch_start], next_symbol) == Ordering::Equal {
                    continue;
                }
            }

            let start = last_batch_start;
            let end = idx + 1;
            last_batch_start = end;

            let key = symbols[start].name.as_str().to_ascii_lowercase();
            let value = SymbolIndex::range_to_map_value(start, end);

            builder.insert(key, value).unwrap();
        }

        let map = fst::Map::new(builder.into_inner().unwrap()).unwrap();
        SymbolIndex { symbols, map }
    }

    pub fn len(&self) -> usize {
        self.symbols.len()
    }

    pub fn memory_size(&self) -> usize {
        self.map.as_fst().size() + self.symbols.len() * mem::size_of::<FileSymbol>()
    }

    #[cfg(not(feature = "wasm"))]
    pub(crate) fn for_files(
        files: impl ParallelIterator<Item = (FileId, Parse<ast::SourceFile>)>,
    ) -> SymbolIndex {
        let symbols = files
            .flat_map(|(file_id, file)| source_file_to_file_symbols(&file.tree(), file_id))
            .collect::<Vec<_>>();
        SymbolIndex::new(symbols)
    }

    #[cfg(feature = "wasm")]
    pub(crate) fn for_files(
        files: impl Iterator<Item = (FileId, Parse<ast::SourceFile>)>,
    ) -> SymbolIndex {
        let symbols = files
            .flat_map(|(file_id, file)| source_file_to_file_symbols(&file.tree(), file_id))
            .collect::<Vec<_>>();
        SymbolIndex::new(symbols)
    }

    fn range_to_map_value(start: usize, end: usize) -> u64 {
        debug_assert![start <= (std::u32::MAX as usize)];
        debug_assert![end <= (std::u32::MAX as usize)];

        ((start as u64) << 32) | end as u64
    }

    fn map_value_to_range(value: u64) -> (usize, usize) {
        let end = value as u32 as usize;
        let start = (value >> 32) as usize;
        (start, end)
    }
}

impl Query {
    pub(crate) fn search(self, indices: &[Arc<SymbolIndex>]) -> Vec<FileSymbol> {
        let mut op = fst::map::OpBuilder::new();
        for file_symbols in indices.iter() {
            let automaton = fst::automaton::Subsequence::new(&self.lowercased);
            op = op.add(file_symbols.map.search(automaton))
        }
        let mut stream = op.union();
        let mut res = Vec::new();
        while let Some((_, indexed_values)) = stream.next() {
            for indexed_value in indexed_values {
                let symbol_index = &indices[indexed_value.index];
                let (start, end) = SymbolIndex::map_value_to_range(indexed_value.value);

                for symbol in &symbol_index.symbols[start..end] {
                    if self.only_types && !is_type(symbol.kind) {
                        continue;
                    }
                    if self.exact && symbol.name != self.query {
                        continue;
                    }

                    if res.len() >= self.limit {
                        return res;
                    }
                    res.push(symbol.clone());
                }
            }
        }
        res
    }
}

fn is_type(kind: SyntaxKind) -> bool {
    match kind {
        STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => true,
        _ => false,
    }
}

/// The actual data that is stored in the index. It should be as compact as
/// possible.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FileSymbol {
    pub file_id: FileId,
    pub name: SmolStr,
    pub kind: SyntaxKind,
    pub range: TextRange,
    pub ptr: SyntaxNodePtr,
    pub name_range: Option<TextRange>,
    pub container_name: Option<SmolStr>,
}

fn source_file_to_file_symbols(source_file: &SourceFile, file_id: FileId) -> Vec<FileSymbol> {
    let mut symbols = Vec::new();
    let mut stack = Vec::new();

    for event in source_file.syntax().preorder() {
        match event {
            WalkEvent::Enter(node) => {
                if let Some(mut symbol) = to_file_symbol(&node, file_id) {
                    symbol.container_name = stack.last().cloned();

                    stack.push(symbol.name.clone());
                    symbols.push(symbol);
                }
            }

            WalkEvent::Leave(node) => {
                if to_symbol(&node).is_some() {
                    stack.pop();
                }
            }
        }
    }

    symbols
}

fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> {
    fn decl<N: NameOwner>(node: N) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> {
        let name = node.name()?;
        let name_range = name.syntax().text_range();
        let name = name.text().clone();
        let ptr = SyntaxNodePtr::new(node.syntax());

        Some((name, ptr, name_range))
    }
    match_ast! {
        match node {
            ast::FnDef(it) => decl(it),
            ast::StructDef(it) => decl(it),
            ast::EnumDef(it) => decl(it),
            ast::TraitDef(it) => decl(it),
            ast::Module(it) => decl(it),
            ast::TypeAliasDef(it) => decl(it),
            ast::ConstDef(it) => decl(it),
            ast::StaticDef(it) => decl(it),
            ast::MacroCall(it) => {
                if it.is_macro_rules().is_some() {
                    decl(it)
                } else {
                    None
                }
            },
            _ => None,
        }
    }
}

fn to_file_symbol(node: &SyntaxNode, file_id: FileId) -> Option<FileSymbol> {
    to_symbol(node).map(move |(name, ptr, name_range)| FileSymbol {
        name,
        kind: node.kind(),
        range: node.text_range(),
        ptr,
        file_id,
        name_range: Some(name_range),
        container_name: None,
    })
}
<|endoftext|>


<commit_before>extern mod freetype;

use font::{FontMetrics, FractionalPixel};

use gfx::geometry;
use gfx::geometry::Au;
use util::*;
use vec_as_buf = vec::as_imm_buf;
use ptr::{addr_of, null};
use cast::reinterpret_cast;
use glyph::GlyphIndex;

use freetype::{ FT_Error, FT_Library, FT_Face, FT_Long, FT_ULong, FT_Size, FT_SizeRec,
               FT_UInt, FT_GlyphSlot, FT_Size_Metrics, FT_FaceRec };
use freetype::bindgen::{
    FT_Init_FreeType,
    FT_Done_FreeType,
    FT_New_Memory_Face,
    FT_Done_Face,
    FT_Get_Char_Index,
    FT_Load_Glyph,
    FT_Set_Char_Size
};

fn float_to_fixed_ft(f: float) -> i32 {
    float_to_fixed(6, f)
}

fn fixed_to_float_ft(f: i32) -> float {
    fixed_to_float(6, f)
}

pub struct FreeTypeNativeFont {
    /// The font binary. This must stay valid for the lifetime of the font
    buf: @~[u8],
    face: FT_Face,

    drop {
        assert self.face.is_not_null();
        if !FT_Done_Face(self.face).succeeded() {
            fail ~"FT_Done_Face failed";
        }
    }
}

pub fn FreeTypeNativeFont(face: FT_Face, buf: @~[u8]) -> FreeTypeNativeFont {
    assert face.is_not_null();
    FreeTypeNativeFont { buf: buf, face: face }
}

pub impl FreeTypeNativeFont {

    fn glyph_index(codepoint: char) -> Option<GlyphIndex> {
        assert self.face.is_not_null();
        let idx = FT_Get_Char_Index(self.face, codepoint as FT_ULong);
        return if idx != 0 as FT_UInt {
            Some(idx as GlyphIndex)
        } else {
            debug!("Invalid codepoint: %?", codepoint);
            None
        };
    }

    // FIXME: What unit is this returning? Let's have a custom type
    fn glyph_h_advance(glyph: GlyphIndex) -> Option<FractionalPixel> {
        assert self.face.is_not_null();
        let res =  FT_Load_Glyph(self.face, glyph as FT_UInt, 0);
        if res.succeeded() {
            unsafe {
                let void_glyph = (*self.face).glyph;
                let slot: FT_GlyphSlot = reinterpret_cast(&void_glyph);
                assert slot.is_not_null();
                debug!("metrics: %?", (*slot).metrics);
                let advance = (*slot).metrics.horiAdvance;
                debug!("h_advance for %? is %?", glyph, advance);
                let advance = advance as i32;
                return Some(fixed_to_float_ft(advance) as FractionalPixel);
            }
        } else {
            debug!("Unable to load glyph %?. reason: %?", glyph, res);
            return None;
        }
    }

    fn get_metrics() -> FontMetrics {
        /* TODO: complete me (Issue #76) */

        let face = self.get_face_rec();

        let underline_size = self.font_units_to_au(face.underline_thickness as float);
        let underline_offset = self.font_units_to_au(face.underline_position as float);
        let em_size = self.font_units_to_au(face.units_per_EM as float);
        let ascent = self.font_units_to_au(face.ascender as float);
        let descent = self.font_units_to_au(face.descender as float);
        let max_advance = self.font_units_to_au(face.max_advance_width as float);

        return FontMetrics {
            underline_size:   underline_size,
            underline_offset: underline_offset,
            leading:          geometry::from_pt(0.0), //FIXME
            x_height:         geometry::from_pt(0.0), //FIXME
            em_size:          em_size,
            ascent:           ascent,
            descent:          descent,
            max_advance:      max_advance
        }
    }

    priv fn get_face_rec() -> &self/FT_FaceRec unsafe {
        &(*self.face)
    }

    priv fn font_units_to_au(value: float) -> Au {

        let face = self.get_face_rec();

        // face.size is a *c_void in the bindings, presumably to avoid
        // recursive structural types
        let size: &FT_SizeRec = unsafe { cast::transmute(&(*face.size)) };
        let metrics: &FT_Size_Metrics = unsafe { &((*size).metrics) };

        let em_size = face.units_per_EM as float;
        let x_scale = (metrics.x_ppem as float) / em_size as float;

        // If this isn't true then we're scaling one of the axes wrong
        assert metrics.x_ppem == metrics.y_ppem;

        return geometry::from_frac_px(value * x_scale);
    }
}

pub fn create(lib: &FT_Library, buf: @~[u8], pt_size: float) -> Result<FreeTypeNativeFont, ()> {
    assert lib.is_not_null();
    let face: FT_Face = null();
    return vec_as_buf(*buf, |cbuf, _len| {
           if FT_New_Memory_Face(*lib, cbuf, (*buf).len() as FT_Long,
                                 0 as FT_Long, addr_of(&face)).succeeded() {
               // FIXME: These values are placeholders
               let res = FT_Set_Char_Size(face, // the face
                                          float_to_fixed_ft(pt_size), // char width
                                          float_to_fixed_ft(pt_size), // char height
                                          72, // horiz. DPI
                                          72); // vert. DPI
               if !res.succeeded() { fail ~"unable to set font char size" }
               Ok(FreeTypeNativeFont(face, buf))
           } else {
               Err(())
           }
    })
}

trait FTErrorMethods {
    fn succeeded() -> bool;
}

impl FT_Error : FTErrorMethods {
    fn succeeded() -> bool { self == 0 as FT_Error }
}
<commit_msg>Add casts to FreeType code to fix build<commit_after>extern mod freetype;

use font::{FontMetrics, FractionalPixel};

use gfx::geometry;
use gfx::geometry::Au;
use util::*;
use vec_as_buf = vec::as_imm_buf;
use ptr::{addr_of, null};
use cast::reinterpret_cast;
use glyph::GlyphIndex;

use freetype::{ FT_Error, FT_Library, FT_Face, FT_Long, FT_ULong, FT_Size, FT_SizeRec,
               FT_UInt, FT_GlyphSlot, FT_Size_Metrics, FT_FaceRec, FT_F26Dot6 };
use freetype::bindgen::{
    FT_Init_FreeType,
    FT_Done_FreeType,
    FT_New_Memory_Face,
    FT_Done_Face,
    FT_Get_Char_Index,
    FT_Load_Glyph,
    FT_Set_Char_Size
};

fn float_to_fixed_ft(f: float) -> i32 {
    float_to_fixed(6, f)
}

fn fixed_to_float_ft(f: i32) -> float {
    fixed_to_float(6, f)
}

pub struct FreeTypeNativeFont {
    /// The font binary. This must stay valid for the lifetime of the font
    buf: @~[u8],
    face: FT_Face,

    drop {
        assert self.face.is_not_null();
        if !FT_Done_Face(self.face).succeeded() {
            fail ~"FT_Done_Face failed";
        }
    }
}

pub fn FreeTypeNativeFont(face: FT_Face, buf: @~[u8]) -> FreeTypeNativeFont {
    assert face.is_not_null();
    FreeTypeNativeFont { buf: buf, face: face }
}

pub impl FreeTypeNativeFont {

    fn glyph_index(codepoint: char) -> Option<GlyphIndex> {
        assert self.face.is_not_null();
        let idx = FT_Get_Char_Index(self.face, codepoint as FT_ULong);
        return if idx != 0 as FT_UInt {
            Some(idx as GlyphIndex)
        } else {
            debug!("Invalid codepoint: %?", codepoint);
            None
        };
    }

    // FIXME: What unit is this returning? Let's have a custom type
    fn glyph_h_advance(glyph: GlyphIndex) -> Option<FractionalPixel> {
        assert self.face.is_not_null();
        let res =  FT_Load_Glyph(self.face, glyph as FT_UInt, 0);
        if res.succeeded() {
            unsafe {
                let void_glyph = (*self.face).glyph;
                let slot: FT_GlyphSlot = reinterpret_cast(&void_glyph);
                assert slot.is_not_null();
                debug!("metrics: %?", (*slot).metrics);
                let advance = (*slot).metrics.horiAdvance;
                debug!("h_advance for %? is %?", glyph, advance);
                let advance = advance as i32;
                return Some(fixed_to_float_ft(advance) as FractionalPixel);
            }
        } else {
            debug!("Unable to load glyph %?. reason: %?", glyph, res);
            return None;
        }
    }

    fn get_metrics() -> FontMetrics {
        /* TODO: complete me (Issue #76) */

        let face = self.get_face_rec();

        let underline_size = self.font_units_to_au(face.underline_thickness as float);
        let underline_offset = self.font_units_to_au(face.underline_position as float);
        let em_size = self.font_units_to_au(face.units_per_EM as float);
        let ascent = self.font_units_to_au(face.ascender as float);
        let descent = self.font_units_to_au(face.descender as float);
        let max_advance = self.font_units_to_au(face.max_advance_width as float);

        return FontMetrics {
            underline_size:   underline_size,
            underline_offset: underline_offset,
            leading:          geometry::from_pt(0.0), //FIXME
            x_height:         geometry::from_pt(0.0), //FIXME
            em_size:          em_size,
            ascent:           ascent,
            descent:          descent,
            max_advance:      max_advance
        }
    }

    priv fn get_face_rec() -> &self/FT_FaceRec unsafe {
        &(*self.face)
    }

    priv fn font_units_to_au(value: float) -> Au {

        let face = self.get_face_rec();

        // face.size is a *c_void in the bindings, presumably to avoid
        // recursive structural types
        let size: &FT_SizeRec = unsafe { cast::transmute(&(*face.size)) };
        let metrics: &FT_Size_Metrics = unsafe { &((*size).metrics) };

        let em_size = face.units_per_EM as float;
        let x_scale = (metrics.x_ppem as float) / em_size as float;

        // If this isn't true then we're scaling one of the axes wrong
        assert metrics.x_ppem == metrics.y_ppem;

        return geometry::from_frac_px(value * x_scale);
    }
}

pub fn create(lib: &FT_Library, buf: @~[u8], pt_size: float) -> Result<FreeTypeNativeFont, ()> {
    assert lib.is_not_null();
    let face: FT_Face = null();
    return vec_as_buf(*buf, |cbuf, _len| {
           if FT_New_Memory_Face(*lib, cbuf, (*buf).len() as FT_Long,
                                 0 as FT_Long, addr_of(&face)).succeeded() {
               // FIXME: These values are placeholders
               let res = FT_Set_Char_Size(face, // the face
                                          float_to_fixed_ft(pt_size) as FT_F26Dot6, // char width
                                          float_to_fixed_ft(pt_size) as FT_F26Dot6, // char height
                                          72, // horiz. DPI
                                          72); // vert. DPI
               if !res.succeeded() { fail ~"unable to set font char size" }
               Ok(FreeTypeNativeFont(face, buf))
           } else {
               Err(())
           }
    })
}

trait FTErrorMethods {
    fn succeeded() -> bool;
}

impl FT_Error : FTErrorMethods {
    fn succeeded() -> bool { self == 0 as FT_Error }
}
<|endoftext|>


<commit_before>use crate::utils::{
    is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then,
    visitors::find_all_ret_expressions,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::*;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for private functions that only return `Ok` or `Some`.
    ///
    /// **Why is this bad?** It is not meaningful to wrap values when no `None` or `Err` is returned.
    ///
    /// **Known problems:** Since this lint changes function type signature, you may need to
    /// adjust some code at callee side.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// fn get_cool_number(a: bool, b: bool) -> Option<i32> {
    ///     if a && b {
    ///         return Some(50);
    ///     }
    ///     if a {
    ///         Some(0)
    ///     } else {
    ///         Some(10)
    ///     }
    /// }
    /// ```
    /// Use instead:
    /// ```rust
    /// fn get_cool_number(a: bool, b: bool) -> i32 {
    ///     if a && b {
    ///         return 50;
    ///     }
    ///     if a {
    ///         0
    ///     } else {
    ///         10
    ///     }
    /// }
    /// ```
    pub UNNECESSARY_WRAP,
    complexity,
    "functions that only return `Ok` or `Some`"
}

declare_lint_pass!(UnnecessaryWrap => [UNNECESSARY_WRAP]);

impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap {
    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        fn_kind: FnKind<'tcx>,
        fn_decl: &FnDecl<'tcx>,
        body: &Body<'tcx>,
        span: Span,
        hir_id: HirId,
    ) {
        if_chain! {
            if let FnKind::ItemFn(.., visibility, _) = fn_kind;
            if visibility.node.is_pub();
            then {
                return;
            }
        }

        let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) {
            ("Option", &paths::OPTION_SOME)
        } else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) {
            ("Result", &paths::RESULT_OK)
        } else {
            return;
        };

        let mut suggs = Vec::new();
        let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| {
            if_chain! {
                if let ExprKind::Call(ref func, ref args) = ret_expr.kind;
                if let ExprKind::Path(ref qpath) = func.kind;
                if match_qpath(qpath, path);
                if args.len() == 1;
                then {
                    suggs.push((ret_expr.span, snippet(cx, args[0].span.source_callsite(), "..").to_string()));
                    true
                } else {
                    false
                }
            }
        });

        if can_sugg {
            span_lint_and_then(
                cx,
                UNNECESSARY_WRAP,
                span,
                format!(
                    "this function's return value is unnecessarily wrapped by `{}`",
                    return_type
                )
                .as_str(),
                |diag| {
                    let inner_ty = return_ty(cx, hir_id)
                        .walk()
                        .skip(1) // skip `std::option::Option` or `std::result::Result`
                        .take(1) // take the first outermost inner type
                        .filter_map(|inner| match inner.unpack() {
                            GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()),
                            _ => None,
                        });
                    inner_ty.for_each(|inner_ty| {
                        diag.span_suggestion(
                            fn_decl.output.span(),
                            format!("remove `{}` from the return type...", return_type).as_str(),
                            inner_ty,
                            Applicability::MachineApplicable,
                        );
                    });
                    diag.multipart_suggestion(
                        "...and change the returning expressions",
                        suggs,
                        Applicability::MachineApplicable,
                    );
                },
            );
        }
    }
}
<commit_msg>Make lint skip closures<commit_after>use crate::utils::{
    is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then,
    visitors::find_all_ret_expressions,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::*;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for private functions that only return `Ok` or `Some`.
    ///
    /// **Why is this bad?** It is not meaningful to wrap values when no `None` or `Err` is returned.
    ///
    /// **Known problems:** Since this lint changes function type signature, you may need to
    /// adjust some code at callee side.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// fn get_cool_number(a: bool, b: bool) -> Option<i32> {
    ///     if a && b {
    ///         return Some(50);
    ///     }
    ///     if a {
    ///         Some(0)
    ///     } else {
    ///         Some(10)
    ///     }
    /// }
    /// ```
    /// Use instead:
    /// ```rust
    /// fn get_cool_number(a: bool, b: bool) -> i32 {
    ///     if a && b {
    ///         return 50;
    ///     }
    ///     if a {
    ///         0
    ///     } else {
    ///         10
    ///     }
    /// }
    /// ```
    pub UNNECESSARY_WRAP,
    complexity,
    "functions that only return `Ok` or `Some`"
}

declare_lint_pass!(UnnecessaryWrap => [UNNECESSARY_WRAP]);

impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap {
    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        fn_kind: FnKind<'tcx>,
        fn_decl: &FnDecl<'tcx>,
        body: &Body<'tcx>,
        span: Span,
        hir_id: HirId,
    ) {
        match fn_kind {
            FnKind::ItemFn(.., visibility, _) if visibility.node.is_pub() => return,
            FnKind::Closure(..) => return,
            _ => (),
        }

        let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) {
            ("Option", &paths::OPTION_SOME)
        } else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) {
            ("Result", &paths::RESULT_OK)
        } else {
            return;
        };

        let mut suggs = Vec::new();
        let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| {
            if_chain! {
                if let ExprKind::Call(ref func, ref args) = ret_expr.kind;
                if let ExprKind::Path(ref qpath) = func.kind;
                if match_qpath(qpath, path);
                if args.len() == 1;
                then {
                    suggs.push((ret_expr.span, snippet(cx, args[0].span.source_callsite(), "..").to_string()));
                    true
                } else {
                    false
                }
            }
        });

        if can_sugg {
            span_lint_and_then(
                cx,
                UNNECESSARY_WRAP,
                span,
                format!(
                    "this function's return value is unnecessarily wrapped by `{}`",
                    return_type
                )
                .as_str(),
                |diag| {
                    let inner_ty = return_ty(cx, hir_id)
                        .walk()
                        .skip(1) // skip `std::option::Option` or `std::result::Result`
                        .take(1) // take the first outermost inner type
                        .filter_map(|inner| match inner.unpack() {
                            GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()),
                            _ => None,
                        });
                    inner_ty.for_each(|inner_ty| {
                        diag.span_suggestion(
                            fn_decl.output.span(),
                            format!("remove `{}` from the return type...", return_type).as_str(),
                            inner_ty,
                            Applicability::MachineApplicable,
                        );
                    });
                    diag.multipart_suggestion(
                        "...and change the returning expressions",
                        suggs,
                        Applicability::MachineApplicable,
                    );
                },
            );
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Minor fix in custom pipeline macro<commit_after><|endoftext|>


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

use std::{io, str};
use std::convert::From;
use std::marker::PhantomData;
use std::net::SocketAddr;
use std::sync::Arc;
use std::thread;

use net2;

use futures::{future, Future, Stream};
use tokio_core::io::{Io, Codec, EasyBuf, Framed};
use tokio_core::net::{TcpStream, TcpListener};
use tokio_core::reactor::{Core, Handle};
use tokio_proto::{TcpClient, TcpServer, BindClient, BindServer};
use tokio_proto::streaming::{Message, Body};
use tokio_proto::streaming::multiplex::{Frame, ServerProto, ClientProto};
use tokio_service::{Service, NewService};

use core::ser;
use msg::*;

struct GrinCodec {
  decoding_head: bool,
}

impl Codec for GrinCodec {
  type In = Frame<MsgHeader, Vec<u8>, io::Error>;
  type Out = Frame<MsgHeader, Vec<u8>, io::Error>;

  fn encode(&mut self, msg: Self::In, mut buf: &mut Vec<u8>) -> io::Result<()> {
    match msg {
      Frame::Message{id, message, ..} => {
        ser::serialize(&mut buf, &message).map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Encoding error: {:?}", e)))?;
      },
      Frame::Body{id, chunk} => {
        if let Some(chunk) = chunk {
          buf.extend(chunk);
        }
      },
      Frame::Error{error, ..} => return Err(error),
    }
    Ok(())
  }

  fn decode(&mut self, buf: &mut EasyBuf) -> Result<Option<Self::Out>, io::Error> {
    unimplemented!();
  }
}

struct GrinProto;

impl <T: Io + 'static> ServerProto<T> for GrinProto {
  type Request = MsgHeader;
  type RequestBody = Vec<u8>;
  type Response = MsgHeader;
  type ResponseBody = Vec<u8>;
  type Error = io::Error;

  type Transport = Framed<T, GrinCodec>;
  type BindTransport = Result<Self::Transport, io::Error>;

  fn bind_transport(&self, io: T) -> Self::BindTransport {
    Ok(io.framed(GrinCodec{decoding_head: true}))
  }
}

struct GrinReceiver;

impl Service for GrinReceiver {
  type Request = Message<MsgHeader, Body<Vec<u8>, io::Error>>;
  type Response = Message<MsgHeader, Body<Vec<u8>, io::Error>>;
  type Error = io::Error;
  type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;

  fn call(&self, req: Self::Request) -> Self::Future {
    let header = req.get_ref();
    let response = match header.msg_type {
      Type::Ping => {
        let data = ser::ser_vec(&MsgHeader::new(Type::Pong, 0)).unwrap();
        Message::WithoutBody(MsgHeader::new(Type::Pong, 0))
      },
      _ => {
        unimplemented!()
      }
    };
    Box::new(future::ok(response))
  }
}

struct GrinClient;

impl Service for GrinClient {
  type Request = Message<MsgHeader, Body<Vec<u8>, io::Error>>;
  type Response = Message<MsgHeader, Body<Vec<u8>, io::Error>>;
  type Error = io::Error;
  type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;

  fn call(&self, req: Self::Request) -> Self::Future {
    unimplemented!();
  }
}

pub struct TcpClientServer<Kind, P> {
  _kind: PhantomData<Kind>,
  proto: Arc<P>,
  threads: usize,
  addr: SocketAddr,
}

impl<Kind, P> TcpClientServer<Kind, P> where
  P: BindServer<Kind, TcpStream> + BindClient<Kind, TcpStream> + Send + Sync + 'static {

  pub fn new(protocol: P, addr: SocketAddr) -> TcpClientServer<Kind, P> {
    TcpClientServer{
      _kind: PhantomData,
      proto: Arc::new(protocol),
      threads: 1,
      addr: addr,
    }
  }

    /// Set the number of threads running simultaneous event loops (Unix only).
    pub fn threads(&mut self, threads: usize) {
        assert!(threads > 0);
        if cfg!(unix) {
            self.threads = threads;
        }
    }

    /// Start up the server, providing the given service on it.
    ///
    /// This method will block the current thread until the server is shut down.
    pub fn serve<S>(&self, new_service: S) where
        S: NewService<Request = <P as BindServer<Kind, TcpStream>>::ServiceRequest,
                      Response = <P as BindServer<Kind, TcpStream>>::ServiceResponse,
                      Error = <P as BindServer<Kind, TcpStream>>::ServiceError> + Send + Sync + 'static,
    {
        let new_service = Arc::new(new_service);
        self.with_handle(move |_| new_service.clone())
    }

    /// Start up the server, providing the given service on it, and providing
    /// access to the event loop handle.
    ///
    /// The `new_service` argument is a closure that is given an event loop
    /// handle, and produces a value implementing `NewService`. That value is in
    /// turned used to make a new service instance for each incoming connection.
    ///
    /// This method will block the current thread until the server is shut down.
    pub fn with_handle<F, S>(&self, new_service: F) where
        F: Fn(&Handle) -> S + Send + Sync + 'static,
        S: NewService<Request = <P as BindServer<Kind, TcpStream>>::ServiceRequest,
                      Response = <P as BindServer<Kind, TcpStream>>::ServiceResponse,
                      Error = <P as BindServer<Kind, TcpStream>>::ServiceError> + Send + Sync + 'static,
    {
        let proto = self.proto.clone();
        let new_service = Arc::new(new_service);
        let addr = self.addr;
        let workers = self.threads;

        let threads = (0..self.threads - 1).map(|i| {
            let proto = proto.clone();
            let new_service = new_service.clone();

            thread::Builder::new().name(format!("worker{}", i)).spawn(move || {
                serve(proto, addr, workers, &*new_service)
            }).unwrap()
        }).collect::<Vec<_>>();

        serve(proto, addr, workers, &*new_service);

        for thread in threads {
            thread.join().unwrap();
        }
    }
}

fn serve<P, Kind, F, S>(binder: Arc<P>, addr: SocketAddr, workers: usize, new_service: &F)
    where P: BindServer<Kind, TcpStream> + BindClient<Kind, TcpStream>,
          F: Fn(&Handle) -> S,
          S: NewService<Request = <P as BindServer<Kind, TcpStream>>::ServiceRequest,
                        Response = <P as BindServer<Kind, TcpStream>>::ServiceResponse,
                        Error = <P as BindServer<Kind, TcpStream>>::ServiceError> + 'static,
{
    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let new_service = new_service(&handle);
    let listener = listener(&addr, workers, &handle).unwrap();

    let server = listener.incoming().for_each(move |(socket, _)| {
        // Create the service
        let service = try!(new_service.new_service());

        // Bind it!
        binder.bind_server(&handle, socket, service);
        binder.bind_client(&handle, socket);

        Ok(())
    });

    core.run(server).unwrap();
}

fn listener(addr: &SocketAddr,
            workers: usize,
            handle: &Handle) -> io::Result<TcpListener> {
    let listener = match *addr {
        SocketAddr::V4(_) => try!(net2::TcpBuilder::new_v4()),
        SocketAddr::V6(_) => try!(net2::TcpBuilder::new_v6()),
    };
    // TODO re-add
    // try!(configure_tcp(workers, &listener));
    try!(listener.reuse_address(true));
    try!(listener.bind(addr));
    listener.listen(1024).and_then(|l| {
        TcpListener::from_listener(l, addr, handle)
    })
}

<commit_msg>Deprecated.<commit_after><|endoftext|>


<commit_before>use nom::{self, IResult};
use std::str;

pub enum Expr<'a> {
    StrLit(&'a str),
    Var(&'a str),
    Filter(&'a str, Box<Expr<'a>>),
    Compare(&'a str, Box<Expr<'a>>, Box<Expr<'a>>),
}

pub enum Target<'a> {
    Name(&'a str),
}

#[derive(Clone, Copy)]
pub struct WS(pub bool, pub bool);

pub enum Node<'a> {
    Lit(&'a str, &'a str, &'a str),
    Expr(WS, Expr<'a>),
    Cond(Vec<(WS, Option<Expr<'a>>, Vec<Node<'a>>)>, WS),
    Loop(WS, Target<'a>, Expr<'a>, Vec<Node<'a>>, WS),
    Extends(Expr<'a>),
    BlockDef(WS, &'a str, Vec<Node<'a>>, WS),
    Block(WS, &'a str, WS),
}

pub type Cond<'a> = (WS, Option<Expr<'a>>, Vec<Node<'a>>);

fn split_ws_parts(s: &[u8]) -> Node {
    if s.is_empty() {
        let rs = str::from_utf8(s).unwrap();
        return Node::Lit(rs, rs, rs);
    }
    let is_ws = |c: &u8| {
        *c != b' ' && *c != b'\t' && *c != b'\r' && *c != b'\n'
    };
    let start = s.iter().position(&is_ws);
    let res = if let None = start {
            (s, &s[0..0], &s[0..0])
        } else {
            let start = start.unwrap();
            let end = s.iter().rposition(&is_ws);
            if let None = end {
                (&s[..start], &s[start..], &s[0..0])
            } else {
                let end = end.unwrap();
                (&s[..start], &s[start..end + 1], &s[end + 1..])
            }
        };
    Node::Lit(str::from_utf8(res.0).unwrap(),
              str::from_utf8(res.1).unwrap(),
              str::from_utf8(res.2).unwrap())
}

fn take_content(i: &[u8]) -> IResult<&[u8], Node> {
    if i.len() < 1 || i[0] == b'{' {
        return IResult::Error(error_position!(nom::ErrorKind::TakeUntil, i));
    }
    for (j, c) in i.iter().enumerate() {
        if *c == b'{' {
            if i.len() < j + 2 {
                return IResult::Done(&i[..0], split_ws_parts(&i[..]));
            } else if i[j + 1] == b'{' || i[j + 1] == b'%' {
                return IResult::Done(&i[j..], split_ws_parts(&i[..j]));
            }
        }
    }
    IResult::Done(&i[..0], split_ws_parts(&i[..]))
}

named!(expr_str_lit<Expr>, map!(
    delimited!(char!('"'), is_not!("\""), char!('"')),
    |s| Expr::StrLit(str::from_utf8(s).unwrap())
));

named!(expr_var<Expr>, map!(nom::alphanumeric,
    |s| Expr::Var(str::from_utf8(s).unwrap())
));

named!(target_single<Target>, map!(nom::alphanumeric,
    |s| Target::Name(str::from_utf8(s).unwrap())
));

fn expr_filtered(i: &[u8]) -> IResult<&[u8], Expr> {
    let (mut left, mut expr) = match expr_var(i) {
        IResult::Error(err) => { return IResult::Error(err); },
        IResult::Incomplete(needed) => { return IResult::Incomplete(needed); },
        IResult::Done(left, res) => (left, res),
    };
    while left[0] == b'|' {
        match nom::alphanumeric(&left[1..]) {
            IResult::Error(err) => {
                return IResult::Error(err);
            },
            IResult::Incomplete(needed) => {
                return IResult::Incomplete(needed);
            },
            IResult::Done(new_left, res) => {
                left = new_left;
                expr = Expr::Filter(str::from_utf8(res).unwrap(), Box::new(expr));
            },
        };
    }
    IResult::Done(left, expr)
}

named!(expr_compare<Expr>, do_parse!(
    left: expr_filtered >>
    op: ws!(alt!(
        tag_s!("==") | tag_s!("!=") |
        tag_s!(">=") | tag_s!(">") |
        tag_s!("<=") | tag_s!("<")
    )) >>
    right: expr_filtered >>
    (Expr::Compare(str::from_utf8(op).unwrap(),
                   Box::new(left), Box::new(right)))
));

named!(expr_any<Expr>, alt!(
    expr_compare |
    expr_filtered |
    expr_str_lit
));

named!(expr_node<Node>, do_parse!(
    tag_s!("{{") >>
    pws: opt!(tag_s!("-")) >>
    expr: ws!(expr_any) >>
    nws: opt!(tag_s!("-")) >>
    tag_s!("}}") >>
    (Node::Expr(WS(pws.is_some(), nws.is_some()), expr))
));

named!(cond_if<Expr>, do_parse!(
    ws!(tag_s!("if")) >>
    cond: ws!(expr_any) >>
    (cond)
));

named!(cond_block<Cond>, do_parse!(
    tag_s!("{%") >>
    pws: opt!(tag_s!("-")) >>
    ws!(tag_s!("else")) >>
    cond: opt!(cond_if) >>
    nws: opt!(tag_s!("-")) >>
    tag_s!("%}") >>
    block: parse_template >>
    (WS(pws.is_some(), nws.is_some()), cond, block)
));

named!(block_if<Node>, do_parse!(
    tag_s!("{%") >>
    pws1: opt!(tag_s!("-")) >>
    cond: ws!(cond_if) >>
    nws1: opt!(tag_s!("-")) >>
    tag_s!("%}") >>
    block: parse_template >>
    elifs: many0!(cond_block) >>
    tag_s!("{%") >>
    pws2: opt!(tag_s!("-")) >>
    ws!(tag_s!("endif")) >>
    nws2: opt!(tag_s!("-")) >>
    tag_s!("%}") >>
    ({
       let mut res = Vec::new();
       res.push((WS(pws1.is_some(), nws1.is_some()), Some(cond), block));
       res.extend(elifs);
       Node::Cond(res, WS(pws2.is_some(), nws2.is_some()))
    })
));

named!(block_for<Node>, do_parse!(
    tag_s!("{%") >>
    pws1: opt!(tag_s!("-")) >>
    ws!(tag_s!("for")) >>
    var: ws!(target_single) >>
    ws!(tag_s!("in")) >>
    iter: ws!(expr_any) >>
    nws1: opt!(tag_s!("-")) >>
    tag_s!("%}") >>
    block: parse_template >>
    tag_s!("{%") >>
    pws2: opt!(tag_s!("-")) >>
    ws!(tag_s!("endfor")) >>
    nws2: opt!(tag_s!("-")) >>
    tag_s!("%}") >>
    (Node::Loop(WS(pws1.is_some(), nws1.is_some()),
                var, iter, block,
                WS(pws2.is_some(), pws2.is_some())))
));

named!(block_extends<Node>, do_parse!(
    tag_s!("{%") >>
    ws!(tag_s!("extends")) >>
    name: ws!(expr_str_lit) >>
    tag_s!("%}") >>
    (Node::Extends(name))
));

named!(block_block<Node>, do_parse!(
    tag_s!("{%") >>
    pws1: opt!(tag_s!("-")) >>
    ws!(tag_s!("block")) >>
    name: ws!(nom::alphanumeric) >>
    nws1: opt!(tag_s!("-")) >>
    tag_s!("%}") >>
    contents: parse_template >>
    tag_s!("{%") >>
    pws2: opt!(tag_s!("-")) >>
    ws!(tag_s!("endblock")) >>
    nws2: opt!(tag_s!("-")) >>
    tag_s!("%}") >>
    (Node::BlockDef(WS(pws1.is_some(), nws1.is_some()),
                    str::from_utf8(name).unwrap(), contents,
                    WS(pws2.is_some(), pws2.is_some())))
));

named!(parse_template<Vec<Node<'a>>>, many0!(alt!(
    take_content |
    expr_node |
    block_if |
    block_for |
    block_extends |
    block_block
)));

pub fn parse(src: &str) -> Vec<Node> {
    match parse_template(src.as_bytes()) {
        IResult::Done(_, res) => res,
        IResult::Error(err) => panic!("problems parsing template source: {}", err),
        IResult::Incomplete(_) => panic!("parsing incomplete"),
    }
}

#[cfg(test)]
mod tests {
    fn check_ws_split(s: &str, res: &(&str, &str, &str)) {
        let node = super::split_ws_parts(s.as_bytes());
        match node {
            super::Node::Lit(lws, s, rws) => {
                assert_eq!(lws, res.0);
                assert_eq!(s, res.1);
                assert_eq!(rws, res.2);
            },
            _ => { panic!("fail"); },
        }
    }
    #[test]
    fn test_ws_splitter() {
        check_ws_split("", &("", "", ""));
        check_ws_split("a", &("", "a", ""));
        check_ws_split("\ta", &("\t", "a", ""));
        check_ws_split("b\n", &("", "b", "\n"));
        check_ws_split(" \t\r\n", &(" \t\r\n", "", ""));
    }
}
<commit_msg>Use is_none() for simple Option tests<commit_after>use nom::{self, IResult};
use std::str;

pub enum Expr<'a> {
    StrLit(&'a str),
    Var(&'a str),
    Filter(&'a str, Box<Expr<'a>>),
    Compare(&'a str, Box<Expr<'a>>, Box<Expr<'a>>),
}

pub enum Target<'a> {
    Name(&'a str),
}

#[derive(Clone, Copy)]
pub struct WS(pub bool, pub bool);

pub enum Node<'a> {
    Lit(&'a str, &'a str, &'a str),
    Expr(WS, Expr<'a>),
    Cond(Vec<(WS, Option<Expr<'a>>, Vec<Node<'a>>)>, WS),
    Loop(WS, Target<'a>, Expr<'a>, Vec<Node<'a>>, WS),
    Extends(Expr<'a>),
    BlockDef(WS, &'a str, Vec<Node<'a>>, WS),
    Block(WS, &'a str, WS),
}

pub type Cond<'a> = (WS, Option<Expr<'a>>, Vec<Node<'a>>);

fn split_ws_parts(s: &[u8]) -> Node {
    if s.is_empty() {
        let rs = str::from_utf8(s).unwrap();
        return Node::Lit(rs, rs, rs);
    }
    let is_ws = |c: &u8| {
        *c != b' ' && *c != b'\t' && *c != b'\r' && *c != b'\n'
    };
    let start = s.iter().position(&is_ws);
    let res = if start.is_none() {
            (s, &s[0..0], &s[0..0])
        } else {
            let start = start.unwrap();
            let end = s.iter().rposition(&is_ws);
            if end.is_none() {
                (&s[..start], &s[start..], &s[0..0])
            } else {
                let end = end.unwrap();
                (&s[..start], &s[start..end + 1], &s[end + 1..])
            }
        };
    Node::Lit(str::from_utf8(res.0).unwrap(),
              str::from_utf8(res.1).unwrap(),
              str::from_utf8(res.2).unwrap())
}

fn take_content(i: &[u8]) -> IResult<&[u8], Node> {
    if i.len() < 1 || i[0] == b'{' {
        return IResult::Error(error_position!(nom::ErrorKind::TakeUntil, i));
    }
    for (j, c) in i.iter().enumerate() {
        if *c == b'{' {
            if i.len() < j + 2 {
                return IResult::Done(&i[..0], split_ws_parts(&i[..]));
            } else if i[j + 1] == b'{' || i[j + 1] == b'%' {
                return IResult::Done(&i[j..], split_ws_parts(&i[..j]));
            }
        }
    }
    IResult::Done(&i[..0], split_ws_parts(&i[..]))
}

named!(expr_str_lit<Expr>, map!(
    delimited!(char!('"'), is_not!("\""), char!('"')),
    |s| Expr::StrLit(str::from_utf8(s).unwrap())
));

named!(expr_var<Expr>, map!(nom::alphanumeric,
    |s| Expr::Var(str::from_utf8(s).unwrap())
));

named!(target_single<Target>, map!(nom::alphanumeric,
    |s| Target::Name(str::from_utf8(s).unwrap())
));

fn expr_filtered(i: &[u8]) -> IResult<&[u8], Expr> {
    let (mut left, mut expr) = match expr_var(i) {
        IResult::Error(err) => { return IResult::Error(err); },
        IResult::Incomplete(needed) => { return IResult::Incomplete(needed); },
        IResult::Done(left, res) => (left, res),
    };
    while left[0] == b'|' {
        match nom::alphanumeric(&left[1..]) {
            IResult::Error(err) => {
                return IResult::Error(err);
            },
            IResult::Incomplete(needed) => {
                return IResult::Incomplete(needed);
            },
            IResult::Done(new_left, res) => {
                left = new_left;
                expr = Expr::Filter(str::from_utf8(res).unwrap(), Box::new(expr));
            },
        };
    }
    IResult::Done(left, expr)
}

named!(expr_compare<Expr>, do_parse!(
    left: expr_filtered >>
    op: ws!(alt!(
        tag_s!("==") | tag_s!("!=") |
        tag_s!(">=") | tag_s!(">") |
        tag_s!("<=") | tag_s!("<")
    )) >>
    right: expr_filtered >>
    (Expr::Compare(str::from_utf8(op).unwrap(),
                   Box::new(left), Box::new(right)))
));

named!(expr_any<Expr>, alt!(
    expr_compare |
    expr_filtered |
    expr_str_lit
));

named!(expr_node<Node>, do_parse!(
    tag_s!("{{") >>
    pws: opt!(tag_s!("-")) >>
    expr: ws!(expr_any) >>
    nws: opt!(tag_s!("-")) >>
    tag_s!("}}") >>
    (Node::Expr(WS(pws.is_some(), nws.is_some()), expr))
));

named!(cond_if<Expr>, do_parse!(
    ws!(tag_s!("if")) >>
    cond: ws!(expr_any) >>
    (cond)
));

named!(cond_block<Cond>, do_parse!(
    tag_s!("{%") >>
    pws: opt!(tag_s!("-")) >>
    ws!(tag_s!("else")) >>
    cond: opt!(cond_if) >>
    nws: opt!(tag_s!("-")) >>
    tag_s!("%}") >>
    block: parse_template >>
    (WS(pws.is_some(), nws.is_some()), cond, block)
));

named!(block_if<Node>, do_parse!(
    tag_s!("{%") >>
    pws1: opt!(tag_s!("-")) >>
    cond: ws!(cond_if) >>
    nws1: opt!(tag_s!("-")) >>
    tag_s!("%}") >>
    block: parse_template >>
    elifs: many0!(cond_block) >>
    tag_s!("{%") >>
    pws2: opt!(tag_s!("-")) >>
    ws!(tag_s!("endif")) >>
    nws2: opt!(tag_s!("-")) >>
    tag_s!("%}") >>
    ({
       let mut res = Vec::new();
       res.push((WS(pws1.is_some(), nws1.is_some()), Some(cond), block));
       res.extend(elifs);
       Node::Cond(res, WS(pws2.is_some(), nws2.is_some()))
    })
));

named!(block_for<Node>, do_parse!(
    tag_s!("{%") >>
    pws1: opt!(tag_s!("-")) >>
    ws!(tag_s!("for")) >>
    var: ws!(target_single) >>
    ws!(tag_s!("in")) >>
    iter: ws!(expr_any) >>
    nws1: opt!(tag_s!("-")) >>
    tag_s!("%}") >>
    block: parse_template >>
    tag_s!("{%") >>
    pws2: opt!(tag_s!("-")) >>
    ws!(tag_s!("endfor")) >>
    nws2: opt!(tag_s!("-")) >>
    tag_s!("%}") >>
    (Node::Loop(WS(pws1.is_some(), nws1.is_some()),
                var, iter, block,
                WS(pws2.is_some(), pws2.is_some())))
));

named!(block_extends<Node>, do_parse!(
    tag_s!("{%") >>
    ws!(tag_s!("extends")) >>
    name: ws!(expr_str_lit) >>
    tag_s!("%}") >>
    (Node::Extends(name))
));

named!(block_block<Node>, do_parse!(
    tag_s!("{%") >>
    pws1: opt!(tag_s!("-")) >>
    ws!(tag_s!("block")) >>
    name: ws!(nom::alphanumeric) >>
    nws1: opt!(tag_s!("-")) >>
    tag_s!("%}") >>
    contents: parse_template >>
    tag_s!("{%") >>
    pws2: opt!(tag_s!("-")) >>
    ws!(tag_s!("endblock")) >>
    nws2: opt!(tag_s!("-")) >>
    tag_s!("%}") >>
    (Node::BlockDef(WS(pws1.is_some(), nws1.is_some()),
                    str::from_utf8(name).unwrap(), contents,
                    WS(pws2.is_some(), pws2.is_some())))
));

named!(parse_template<Vec<Node<'a>>>, many0!(alt!(
    take_content |
    expr_node |
    block_if |
    block_for |
    block_extends |
    block_block
)));

pub fn parse(src: &str) -> Vec<Node> {
    match parse_template(src.as_bytes()) {
        IResult::Done(_, res) => res,
        IResult::Error(err) => panic!("problems parsing template source: {}", err),
        IResult::Incomplete(_) => panic!("parsing incomplete"),
    }
}

#[cfg(test)]
mod tests {
    fn check_ws_split(s: &str, res: &(&str, &str, &str)) {
        let node = super::split_ws_parts(s.as_bytes());
        match node {
            super::Node::Lit(lws, s, rws) => {
                assert_eq!(lws, res.0);
                assert_eq!(s, res.1);
                assert_eq!(rws, res.2);
            },
            _ => { panic!("fail"); },
        }
    }
    #[test]
    fn test_ws_splitter() {
        check_ws_split("", &("", "", ""));
        check_ws_split("a", &("", "a", ""));
        check_ws_split("\ta", &("\t", "a", ""));
        check_ws_split("b\n", &("", "b", "\n"));
        check_ws_split(" \t\r\n", &(" \t\r\n", "", ""));
    }
}
<|endoftext|>


<commit_before>use crate::command_prelude::*;
use anyhow::{bail, format_err};
use cargo::core::dependency::DepKind;
use cargo::ops::tree;
use cargo::util::CargoResult;
use std::collections::HashSet;
use std::str::FromStr;

pub fn cli() -> App {
    subcommand("tree")
        .about("Display a tree visualization of a dependency graph")
        .arg(opt("quiet", "Suppress status messages").short("q"))
        .arg_manifest_path()
        .arg_package_spec_no_all(
            "Package to be used as the root of the tree",
            "Display the tree for all packages in the workspace",
            "Exclude specific workspace members",
        )
        .arg(Arg::with_name("all").long("all").short("a").hidden(true))
        .arg(
            Arg::with_name("all-targets")
                .long("all-targets")
                .hidden(true),
        )
        .arg_features()
        .arg_target_triple(
            "Filter dependencies matching the given target-triple (default host platform)",
        )
        .arg(
            Arg::with_name("no-dev-dependencies")
                .long("no-dev-dependencies")
                .hidden(true),
        )
        .arg(
            opt(
                "dep-kinds",
                "Dependency kinds to display \
                 (normal, build, dev, no-dev, no-build, no-normal, all)",
            )
            .value_name("KINDS"),
        )
        .arg(opt("invert", "Invert the tree direction").short("i"))
        .arg(Arg::with_name("no-indent").long("no-indent").hidden(true))
        .arg(
            Arg::with_name("prefix-depth")
                .long("prefix-depth")
                .hidden(true),
        )
        .arg(
            opt(
                "prefix",
                "Change the prefix (indentation) of how each entry is displayed",
            )
            .value_name("PREFIX")
            .possible_values(&["depth", "indent", "none"])
            .default_value("indent"),
        )
        .arg(opt(
            "no-dedupe",
            "Do not de-duplicate (repeats all shared dependencies)",
        ))
        .arg(
            opt(
                "duplicates",
                "Show only dependencies which come in multiple versions (implies -i)",
            )
            .short("d")
            .alias("duplicate"),
        )
        .arg(
            opt("charset", "Character set to use in output: utf8, ascii")
                .value_name("CHARSET")
                .possible_values(&["utf8", "ascii"])
                .default_value("utf8"),
        )
        .arg(
            opt("format", "Format string used for printing dependencies")
                .value_name("FORMAT")
                .short("f")
                .default_value("{p}"),
        )
        .arg(opt("graph-features", "Include features in the tree"))
}

pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
    if args.is_present("no-indent") {
        return Err(format_err!("the --no-indent flag has been changed to --prefix=none").into());
    }
    if args.is_present("prefix-depth") {
        return Err(
            format_err!("the --prefix-depth flag has been changed to --prefix=depth").into(),
        );
    }
    if args.is_present("all") {
        return Err(format_err!(
            "The `cargo tree` --all flag has been changed to --no-dedupe.\n\
            If you are looking to display all workspace members, use the --workspace flag."
        )
        .into());
    }
    if args.is_present("all-targets") {
        return Err(format_err!("the --all-targets flag has been changed to --target=all").into());
    }
    if args.is_present("no-dev-dependencies") {
        return Err(format_err!(
            "the --no-dev-dependencies flag has changed to --dep-kinds=no-dev"
        )
        .into());
    }
    let ws = args.workspace(config)?;
    let charset = tree::Charset::from_str(args.value_of("charset").unwrap())
        .map_err(|e| anyhow::anyhow!("{}", e))?;
    let prefix = tree::Prefix::from_str(args.value_of("prefix").unwrap())
        .map_err(|e| anyhow::anyhow!("{}", e))?;
    let target = tree::Target::from_cli(args.value_of("target"));
    let dep_kinds = parse_dep_kinds(args.value_of("dep-kinds"))?;
    let opts = tree::TreeOptions {
        features: values(args, "features"),
        all_features: args.is_present("all-features"),
        no_default_features: args.is_present("no-default-features"),
        packages: args.packages_from_flags()?,
        target,
        dep_kinds,
        invert: args.is_present("invert"),
        prefix,
        no_dedupe: args.is_present("no-dedupe"),
        duplicates: args.is_present("duplicates"),
        charset,
        format: args.value_of("format").unwrap().to_string(),
        graph_features: args.is_present("graph-features"),
    };

    tree::build_and_print(&ws, &opts)?;
    Ok(())
}

fn parse_dep_kinds(kinds: Option<&str>) -> CargoResult<HashSet<DepKind>> {
    let kinds: Vec<&str> = kinds.unwrap_or("all").split(',').collect();
    let mut result = HashSet::new();
    let insert_all = |result: &mut HashSet<DepKind>| {
        result.insert(DepKind::Normal);
        result.insert(DepKind::Build);
        result.insert(DepKind::Development);
    };
    let unknown = |k| {
        bail!(
            "unknown dependency kind `{}`, valid values are \
                \"normal\", \"build\", \"dev\", \
                \"no-normal\", \"no-build\", \"no-dev\", \
                or \"all\"",
            k
        )
    };
    if kinds.iter().any(|k| k.starts_with("no-")) {
        insert_all(&mut result);
        for kind in &kinds {
            match *kind {
                "no-normal" => result.remove(&DepKind::Normal),
                "no-build" => result.remove(&DepKind::Build),
                "no-dev" => result.remove(&DepKind::Development),
                "normal" | "build" | "dev" | "all" => {
                    bail!("`no-` dependency kinds cannot be mixed with other dependency kinds")
                }
                k => return unknown(k),
            };
        }
        return Ok(result);
    }
    for kind in kinds {
        match kind {
            "all" => insert_all(&mut result),
            "normal" => {
                result.insert(DepKind::Normal);
            }
            "build" => {
                result.insert(DepKind::Build);
            }
            "dev" => {
                result.insert(DepKind::Development);
            }
            k => return unknown(k),
        }
    }
    Ok(result)
}
<commit_msg>Change old flags to warnings instead of errors.<commit_after>use crate::command_prelude::*;
use anyhow::{bail, format_err};
use cargo::core::dependency::DepKind;
use cargo::ops::tree;
use cargo::util::CargoResult;
use std::collections::HashSet;
use std::str::FromStr;

pub fn cli() -> App {
    subcommand("tree")
        .about("Display a tree visualization of a dependency graph")
        .arg(opt("quiet", "Suppress status messages").short("q"))
        .arg_manifest_path()
        .arg_package_spec_no_all(
            "Package to be used as the root of the tree",
            "Display the tree for all packages in the workspace",
            "Exclude specific workspace members",
        )
        .arg(Arg::with_name("all").long("all").short("a").hidden(true))
        .arg(
            Arg::with_name("all-targets")
                .long("all-targets")
                .hidden(true),
        )
        .arg_features()
        .arg_target_triple(
            "Filter dependencies matching the given target-triple (default host platform)",
        )
        .arg(
            Arg::with_name("no-dev-dependencies")
                .long("no-dev-dependencies")
                .hidden(true),
        )
        .arg(
            opt(
                "dep-kinds",
                "Dependency kinds to display \
                 (normal, build, dev, no-dev, no-build, no-normal, all)",
            )
            .value_name("KINDS"),
        )
        .arg(opt("invert", "Invert the tree direction").short("i"))
        .arg(Arg::with_name("no-indent").long("no-indent").hidden(true))
        .arg(
            Arg::with_name("prefix-depth")
                .long("prefix-depth")
                .hidden(true),
        )
        .arg(
            opt(
                "prefix",
                "Change the prefix (indentation) of how each entry is displayed",
            )
            .value_name("PREFIX")
            .possible_values(&["depth", "indent", "none"])
            .default_value("indent"),
        )
        .arg(opt(
            "no-dedupe",
            "Do not de-duplicate (repeats all shared dependencies)",
        ))
        .arg(
            opt(
                "duplicates",
                "Show only dependencies which come in multiple versions (implies -i)",
            )
            .short("d")
            .alias("duplicate"),
        )
        .arg(
            opt("charset", "Character set to use in output: utf8, ascii")
                .value_name("CHARSET")
                .possible_values(&["utf8", "ascii"])
                .default_value("utf8"),
        )
        .arg(
            opt("format", "Format string used for printing dependencies")
                .value_name("FORMAT")
                .short("f")
                .default_value("{p}"),
        )
        .arg(opt("graph-features", "Include features in the tree"))
}

pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
    let prefix = if args.is_present("no-indent") {
        config
            .shell()
            .warn("the --no-indent flag has been changed to --prefix=none")?;
        "none"
    } else if args.is_present("prefix-depth") {
        config
            .shell()
            .warn("the --prefix-depth flag has been changed to --prefix=depth")?;
        "depth"
    } else {
        args.value_of("prefix").unwrap()
    };
    let prefix = tree::Prefix::from_str(prefix).map_err(|e| anyhow::anyhow!("{}", e))?;

    if args.is_present("all") {
        return Err(format_err!(
            "The `cargo tree` --all flag has been changed to --no-dedupe.\n\
            If you are looking to display all workspace members, use the --workspace flag."
        )
        .into());
    }

    let target = if args.is_present("all-targets") {
        config
            .shell()
            .warn("the --all-targets flag has been changed to --target=all")?;
        Some("all")
    } else {
        args.value_of("target")
    };
    let target = tree::Target::from_cli(target);

    let dep_kinds = if args.is_present("no-dev-dependencies") {
        config
            .shell()
            .warn("the --no-dev-dependencies flag has changed to --dep-kinds=no-dev")?;
        Some("no-dev")
    } else {
        args.value_of("dep-kinds")
    };
    let dep_kinds = parse_dep_kinds(dep_kinds)?;

    let ws = args.workspace(config)?;
    let charset = tree::Charset::from_str(args.value_of("charset").unwrap())
        .map_err(|e| anyhow::anyhow!("{}", e))?;
    let opts = tree::TreeOptions {
        features: values(args, "features"),
        all_features: args.is_present("all-features"),
        no_default_features: args.is_present("no-default-features"),
        packages: args.packages_from_flags()?,
        target,
        dep_kinds,
        invert: args.is_present("invert"),
        prefix,
        no_dedupe: args.is_present("no-dedupe"),
        duplicates: args.is_present("duplicates"),
        charset,
        format: args.value_of("format").unwrap().to_string(),
        graph_features: args.is_present("graph-features"),
    };

    tree::build_and_print(&ws, &opts)?;
    Ok(())
}

fn parse_dep_kinds(kinds: Option<&str>) -> CargoResult<HashSet<DepKind>> {
    let kinds: Vec<&str> = kinds.unwrap_or("all").split(',').collect();
    let mut result = HashSet::new();
    let insert_all = |result: &mut HashSet<DepKind>| {
        result.insert(DepKind::Normal);
        result.insert(DepKind::Build);
        result.insert(DepKind::Development);
    };
    let unknown = |k| {
        bail!(
            "unknown dependency kind `{}`, valid values are \
                \"normal\", \"build\", \"dev\", \
                \"no-normal\", \"no-build\", \"no-dev\", \
                or \"all\"",
            k
        )
    };
    if kinds.iter().any(|k| k.starts_with("no-")) {
        insert_all(&mut result);
        for kind in &kinds {
            match *kind {
                "no-normal" => result.remove(&DepKind::Normal),
                "no-build" => result.remove(&DepKind::Build),
                "no-dev" => result.remove(&DepKind::Development),
                "normal" | "build" | "dev" | "all" => {
                    bail!("`no-` dependency kinds cannot be mixed with other dependency kinds")
                }
                k => return unknown(k),
            };
        }
        return Ok(result);
    }
    for kind in kinds {
        match kind {
            "all" => insert_all(&mut result),
            "normal" => {
                result.insert(DepKind::Normal);
            }
            "build" => {
                result.insert(DepKind::Build);
            }
            "dev" => {
                result.insert(DepKind::Development);
            }
            k => return unknown(k),
        }
    }
    Ok(result)
}
<|endoftext|>


<commit_before>use super::*;
use crate::test;
use ci_info;
use envmnt;
#[cfg(target_os = "linux")]
use rust_info::types::RustChannel;

#[test]
#[ignore]
fn get_cargo_home_env() {
    let directory_path = env::current_dir().unwrap();
    let directory = directory_path.to_str().unwrap();
    envmnt::set("CARGO_HOME", directory);

    let output = get_cargo_home().unwrap();
    envmnt::remove("CARGO_HOME");

    assert_eq!(output, directory);
}

#[test]
#[ignore]
fn get_cargo_home_no_env() {
    envmnt::remove("CARGO_HOME");

    let output = get_cargo_home().unwrap();

    assert!(output.contains(".cargo"));
}

#[test]
#[ignore]
fn get_cargo_home_file() {
    let directory_path = env::current_dir().unwrap();
    let directory = directory_path.to_str().unwrap();
    let file_path = Path::new(directory).join("Cargo.toml");
    envmnt::set("CARGO_HOME", file_path);

    let output = get_cargo_home();
    envmnt::remove("CARGO_HOME");

    assert!(output.is_none());
}

#[test]
fn load_crates_toml_valid() {
    let cwd = envmnt::get_or_panic("CARGO_MAKE_WORKING_DIRECTORY");
    let file_path = Path::new(&cwd).join("src/lib/test/test_files");
    let directory = file_path.to_str().unwrap();
    let info_option = load_crates_toml(&directory);

    assert!(info_option.is_some());
    let info = info_option.unwrap();
    assert!(info.v1.is_some());
    assert_eq!(info.v1.unwrap().len(), 3);
}

#[test]
fn load_crates_toml_file_not_found() {
    let cwd = envmnt::get_or_panic("CARGO_MAKE_WORKING_DIRECTORY");
    let info_option = load_crates_toml(&cwd);

    assert!(info_option.is_none());
}

#[test]
fn get_crate_version_from_info_no_info() {
    let info = CratesRegistryInfo { v1: None };
    let version = get_crate_version_from_info("cargo-make", &info);

    assert!(version.is_none());
}

#[test]
fn get_crate_version_from_info_empty_info() {
    let info = CratesRegistryInfo {
        v1: Some(HashMap::new()),
    };
    let version = get_crate_version_from_info("cargo-make", &info);

    assert!(version.is_none());
}

#[test]
fn get_crate_version_from_info_not_found() {
    let mut map = HashMap::new();
    map.insert("1 1 1".to_string(), vec![]);
    map.insert("2 2 2".to_string(), vec![]);
    let info = CratesRegistryInfo { v1: Some(map) };
    let version = get_crate_version_from_info("cargo-make", &info);

    assert!(version.is_none());
}

#[test]
fn get_crate_version_from_info_found_invalid_line() {
    let mut map = HashMap::new();
    map.insert("1 1 1".to_string(), vec![]);
    map.insert("cargo-make".to_string(), vec![]);
    map.insert("2 2 2".to_string(), vec![]);
    let info = CratesRegistryInfo { v1: Some(map) };
    let version = get_crate_version_from_info("cargo-make", &info);

    assert!(version.is_none());
}

#[test]
fn get_crate_version_from_info_found_invalid_version() {
    let mut map = HashMap::new();
    map.insert("1 1 1".to_string(), vec![]);
    map.insert("cargo-make abc 2".to_string(), vec![]);
    map.insert("2 2 2".to_string(), vec![]);
    let info = CratesRegistryInfo { v1: Some(map) };
    let version = get_crate_version_from_info("cargo-make", &info);

    assert!(version.is_none());
}

#[test]
fn get_crate_version_from_info_valid() {
    let mut map = HashMap::new();
    map.insert("1 1 1".to_string(), vec![]);
    map.insert("cargo-make 1.2.3 2".to_string(), vec![]);
    map.insert("2 2 2".to_string(), vec![]);
    let info = CratesRegistryInfo { v1: Some(map) };
    let version = get_crate_version_from_info("cargo-make", &info);

    let semver_version = version.unwrap();
    assert_eq!(semver_version.major, 1);
    assert_eq!(semver_version.minor, 2);
    assert_eq!(semver_version.patch, 3);
}

#[test]
#[cfg(target_os = "linux")]
fn get_crate_version_for_rustup_component() {
    if test::is_rust_channel(RustChannel::Stable) || !ci_info::is_ci() {
        let mut version = get_crate_version("rustfmt", None);
        assert!(version.is_none());

        version = get_crate_version("rustfmt", Some("rustfmt"));
        assert!(version.is_some());
    }
}

#[test]
fn is_min_version_valid_for_versions_equal() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.2.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(valid);
}

#[test]
fn is_min_version_valid_for_versions_false_major() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("2.2.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_min_version_valid_for_versions_false_minor() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.3.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_min_version_valid_for_versions_false_patch() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.2.4").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_min_version_valid_for_versions_true_major() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.2.3").unwrap(),
        &Version::parse("2.2.3").unwrap(),
    );

    assert!(valid);
}

#[test]
fn is_min_version_valid_for_versions_true_minor() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.2.3").unwrap(),
        &Version::parse("1.3.3").unwrap(),
    );

    assert!(valid);
}

#[test]
fn is_min_version_valid_for_versions_true_patch() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.2.3").unwrap(),
        &Version::parse("1.2.4").unwrap(),
    );

    assert!(valid);
}

#[test]
fn is_min_version_valid_not_found() {
    let valid = is_min_version_valid("bad_crate", "1.2.3", None);

    assert!(valid);
}

#[test]
fn is_min_version_valid_invalid_version() {
    let valid = is_min_version_valid("cargo-make", "bad_version", None);

    assert!(valid);
}

#[test]
fn is_min_version_valid_old_version() {
    let valid = is_min_version_valid("cargo-make", "0.0.1", None);

    assert!(valid);
}

#[test]
fn is_min_version_valid_newer_version() {
    let valid = is_min_version_valid("cargo-make", "10000.0.0", None);

    assert!(!valid);
}

#[test]
fn is_min_version_valid_same_version() {
    let version = get_crate_version("cargo-make", None).unwrap();
    let mut version_string = String::new();
    version_string.push_str(&version.major.to_string());
    version_string.push_str(".");
    version_string.push_str(&version.minor.to_string());
    version_string.push_str(".");
    version_string.push_str(&version.patch.to_string());

    let valid = is_min_version_valid("cargo-make", &version_string, None);

    assert!(valid);
}

#[test]
fn is_version_valid_for_versions_equal() {
    let valid = is_version_valid_for_versions(
        &Version::parse("1.2.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(valid);
}

#[test]
fn is_version_valid_for_versions_false_major() {
    let valid = is_version_valid_for_versions(
        &Version::parse("2.2.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_version_valid_for_versions_false_minor() {
    let valid = is_version_valid_for_versions(
        &Version::parse("1.3.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_version_valid_for_versions_false_patch() {
    let valid = is_version_valid_for_versions(
        &Version::parse("1.2.4").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_version_valid_not_found() {
    let valid = is_version_valid("bad_crate", "1.2.3", None);

    assert!(valid);
}

#[test]
fn is_version_valid_invalid_version() {
    let valid = is_version_valid("cargo-make", "bad_version", None);

    assert!(valid);
}

#[test]
fn is_version_valid_old_version() {
    let valid = is_version_valid("cargo-make", "0.0.1", None);

    assert!(!valid);
}

#[test]
fn is_version_valid_newer_version() {
    let valid = is_version_valid("cargo-make", "10000.0.0", None);

    assert!(!valid);
}

#[test]
fn is_version_valid_same_version() {
    let version = get_crate_version("cargo-make", None).unwrap();
    let mut version_string = String::new();
    version_string.push_str(&version.major.to_string());
    version_string.push_str(".");
    version_string.push_str(&version.minor.to_string());
    version_string.push_str(".");
    version_string.push_str(&version.patch.to_string());

    let valid = is_min_version_valid("cargo-make", &version_string, None);

    assert!(valid);
}
<commit_msg>fix build<commit_after>use super::*;
use crate::test;
#[cfg(target_os = "linux")]
use ci_info;
use envmnt;
#[cfg(target_os = "linux")]
use rust_info::types::RustChannel;

#[test]
#[ignore]
fn get_cargo_home_env() {
    let directory_path = env::current_dir().unwrap();
    let directory = directory_path.to_str().unwrap();
    envmnt::set("CARGO_HOME", directory);

    let output = get_cargo_home().unwrap();
    envmnt::remove("CARGO_HOME");

    assert_eq!(output, directory);
}

#[test]
#[ignore]
fn get_cargo_home_no_env() {
    envmnt::remove("CARGO_HOME");

    let output = get_cargo_home().unwrap();

    assert!(output.contains(".cargo"));
}

#[test]
#[ignore]
fn get_cargo_home_file() {
    let directory_path = env::current_dir().unwrap();
    let directory = directory_path.to_str().unwrap();
    let file_path = Path::new(directory).join("Cargo.toml");
    envmnt::set("CARGO_HOME", file_path);

    let output = get_cargo_home();
    envmnt::remove("CARGO_HOME");

    assert!(output.is_none());
}

#[test]
fn load_crates_toml_valid() {
    let cwd = envmnt::get_or_panic("CARGO_MAKE_WORKING_DIRECTORY");
    let file_path = Path::new(&cwd).join("src/lib/test/test_files");
    let directory = file_path.to_str().unwrap();
    let info_option = load_crates_toml(&directory);

    assert!(info_option.is_some());
    let info = info_option.unwrap();
    assert!(info.v1.is_some());
    assert_eq!(info.v1.unwrap().len(), 3);
}

#[test]
fn load_crates_toml_file_not_found() {
    let cwd = envmnt::get_or_panic("CARGO_MAKE_WORKING_DIRECTORY");
    let info_option = load_crates_toml(&cwd);

    assert!(info_option.is_none());
}

#[test]
fn get_crate_version_from_info_no_info() {
    let info = CratesRegistryInfo { v1: None };
    let version = get_crate_version_from_info("cargo-make", &info);

    assert!(version.is_none());
}

#[test]
fn get_crate_version_from_info_empty_info() {
    let info = CratesRegistryInfo {
        v1: Some(HashMap::new()),
    };
    let version = get_crate_version_from_info("cargo-make", &info);

    assert!(version.is_none());
}

#[test]
fn get_crate_version_from_info_not_found() {
    let mut map = HashMap::new();
    map.insert("1 1 1".to_string(), vec![]);
    map.insert("2 2 2".to_string(), vec![]);
    let info = CratesRegistryInfo { v1: Some(map) };
    let version = get_crate_version_from_info("cargo-make", &info);

    assert!(version.is_none());
}

#[test]
fn get_crate_version_from_info_found_invalid_line() {
    let mut map = HashMap::new();
    map.insert("1 1 1".to_string(), vec![]);
    map.insert("cargo-make".to_string(), vec![]);
    map.insert("2 2 2".to_string(), vec![]);
    let info = CratesRegistryInfo { v1: Some(map) };
    let version = get_crate_version_from_info("cargo-make", &info);

    assert!(version.is_none());
}

#[test]
fn get_crate_version_from_info_found_invalid_version() {
    let mut map = HashMap::new();
    map.insert("1 1 1".to_string(), vec![]);
    map.insert("cargo-make abc 2".to_string(), vec![]);
    map.insert("2 2 2".to_string(), vec![]);
    let info = CratesRegistryInfo { v1: Some(map) };
    let version = get_crate_version_from_info("cargo-make", &info);

    assert!(version.is_none());
}

#[test]
fn get_crate_version_from_info_valid() {
    let mut map = HashMap::new();
    map.insert("1 1 1".to_string(), vec![]);
    map.insert("cargo-make 1.2.3 2".to_string(), vec![]);
    map.insert("2 2 2".to_string(), vec![]);
    let info = CratesRegistryInfo { v1: Some(map) };
    let version = get_crate_version_from_info("cargo-make", &info);

    let semver_version = version.unwrap();
    assert_eq!(semver_version.major, 1);
    assert_eq!(semver_version.minor, 2);
    assert_eq!(semver_version.patch, 3);
}

#[test]
#[cfg(target_os = "linux")]
fn get_crate_version_for_rustup_component() {
    if test::is_rust_channel(RustChannel::Stable) || !ci_info::is_ci() {
        let mut version = get_crate_version("rustfmt", None);
        assert!(version.is_none());

        version = get_crate_version("rustfmt", Some("rustfmt"));
        assert!(version.is_some());
    }
}

#[test]
fn is_min_version_valid_for_versions_equal() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.2.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(valid);
}

#[test]
fn is_min_version_valid_for_versions_false_major() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("2.2.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_min_version_valid_for_versions_false_minor() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.3.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_min_version_valid_for_versions_false_patch() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.2.4").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_min_version_valid_for_versions_true_major() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.2.3").unwrap(),
        &Version::parse("2.2.3").unwrap(),
    );

    assert!(valid);
}

#[test]
fn is_min_version_valid_for_versions_true_minor() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.2.3").unwrap(),
        &Version::parse("1.3.3").unwrap(),
    );

    assert!(valid);
}

#[test]
fn is_min_version_valid_for_versions_true_patch() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.2.3").unwrap(),
        &Version::parse("1.2.4").unwrap(),
    );

    assert!(valid);
}

#[test]
fn is_min_version_valid_not_found() {
    let valid = is_min_version_valid("bad_crate", "1.2.3", None);

    assert!(valid);
}

#[test]
fn is_min_version_valid_invalid_version() {
    let valid = is_min_version_valid("cargo-make", "bad_version", None);

    assert!(valid);
}

#[test]
fn is_min_version_valid_old_version() {
    let valid = is_min_version_valid("cargo-make", "0.0.1", None);

    assert!(valid);
}

#[test]
fn is_min_version_valid_newer_version() {
    let valid = is_min_version_valid("cargo-make", "10000.0.0", None);

    assert!(!valid);
}

#[test]
fn is_min_version_valid_same_version() {
    let version = get_crate_version("cargo-make", None).unwrap();
    let mut version_string = String::new();
    version_string.push_str(&version.major.to_string());
    version_string.push_str(".");
    version_string.push_str(&version.minor.to_string());
    version_string.push_str(".");
    version_string.push_str(&version.patch.to_string());

    let valid = is_min_version_valid("cargo-make", &version_string, None);

    assert!(valid);
}

#[test]
fn is_version_valid_for_versions_equal() {
    let valid = is_version_valid_for_versions(
        &Version::parse("1.2.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(valid);
}

#[test]
fn is_version_valid_for_versions_false_major() {
    let valid = is_version_valid_for_versions(
        &Version::parse("2.2.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_version_valid_for_versions_false_minor() {
    let valid = is_version_valid_for_versions(
        &Version::parse("1.3.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_version_valid_for_versions_false_patch() {
    let valid = is_version_valid_for_versions(
        &Version::parse("1.2.4").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_version_valid_not_found() {
    let valid = is_version_valid("bad_crate", "1.2.3", None);

    assert!(valid);
}

#[test]
fn is_version_valid_invalid_version() {
    let valid = is_version_valid("cargo-make", "bad_version", None);

    assert!(valid);
}

#[test]
fn is_version_valid_old_version() {
    let valid = is_version_valid("cargo-make", "0.0.1", None);

    assert!(!valid);
}

#[test]
fn is_version_valid_newer_version() {
    let valid = is_version_valid("cargo-make", "10000.0.0", None);

    assert!(!valid);
}

#[test]
fn is_version_valid_same_version() {
    let version = get_crate_version("cargo-make", None).unwrap();
    let mut version_string = String::new();
    version_string.push_str(&version.major.to_string());
    version_string.push_str(".");
    version_string.push_str(&version.minor.to_string());
    version_string.push_str(".");
    version_string.push_str(&version.patch.to_string());

    let valid = is_min_version_valid("cargo-make", &version_string, None);

    assert!(valid);
}
<|endoftext|>