<commit_before>//! Implements syntax highlighting.

mod tags;
mod html;
#[cfg(test)]
mod tests;

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

use crate::{call_info::call_info_for_token, references::classify_name_ref, Analysis, FileId};

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

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

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

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

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

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

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

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

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

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

        let range = element.text_range();

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

        if let Some(token) = element.as_token().cloned().and_then(ast::RawString::cast) {
            let expanded = element_to_highlight.as_token().unwrap().clone();
            if highlight_injection(&mut res, &sema, token, expanded).is_some() {
                eprintln!("res = {:?}", res);
                continue;
            }
        }

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

    res
}

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

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

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

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

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

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

            match name_kind {
                Some(NameClass::NameDefinition(def)) => {
                    highlight_name(db, def) | HighlightModifier::Definition
                }
                Some(NameClass::ConstReference(def)) => highlight_name(db, def),
                None => highlight_name_by_syntax(name) | HighlightModifier::Definition,
            }
        }

        // Highlight references like the definitions they resolve to

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

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

            highlight_name(db, name_kind)
        }

        // Simple token-based highlighting
        COMMENT => HighlightTag::Comment.into(),
        STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => HighlightTag::StringLiteral.into(),
        ATTR => HighlightTag::Attribute.into(),
        INT_NUMBER | FLOAT_NUMBER => HighlightTag::NumericLiteral.into(),
        BYTE => HighlightTag::ByteLiteral.into(),
        CHAR => HighlightTag::CharLiteral.into(),
        LIFETIME => {
            let h = Highlight::new(HighlightTag::Lifetime);
            dbg!(match element.parent().map(|it| it.kind()) {
                Some(LIFETIME_PARAM) | Some(LABEL) => h | HighlightModifier::Definition,
                _ => h,
            })
        }

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

        _ => return None,
    };

    return Some((highlight, binding_hash));

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

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

        hash((name, shadow_count))
    }
}

fn highlight_name(db: &RootDatabase, def: NameDefinition) -> Highlight {
    match def {
        NameDefinition::Macro(_) => HighlightTag::Macro,
        NameDefinition::StructField(_) => HighlightTag::Field,
        NameDefinition::ModuleDef(def) => match def {
            hir::ModuleDef::Module(_) => HighlightTag::Module,
            hir::ModuleDef::Function(_) => HighlightTag::Function,
            hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Struct,
            hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HighlightTag::Enum,
            hir::ModuleDef::Adt(hir::Adt::Union(_)) => HighlightTag::Union,
            hir::ModuleDef::EnumVariant(_) => HighlightTag::EnumVariant,
            hir::ModuleDef::Const(_) => HighlightTag::Constant,
            hir::ModuleDef::Static(_) => HighlightTag::Static,
            hir::ModuleDef::Trait(_) => HighlightTag::Trait,
            hir::ModuleDef::TypeAlias(_) => HighlightTag::TypeAlias,
            hir::ModuleDef::BuiltinType(_) => HighlightTag::BuiltinType,
        },
        NameDefinition::SelfType(_) => HighlightTag::SelfType,
        NameDefinition::TypeParam(_) => HighlightTag::TypeParam,
        // FIXME: distinguish between locals and parameters
        NameDefinition::Local(local) => {
            let mut h = Highlight::new(HighlightTag::Local);
            if local.is_mut(db) || local.ty(db).is_mutable_reference() {
                h |= HighlightModifier::Mutable;
            }
            return h;
        }
    }
    .into()
}

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

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

    match parent.kind() {
        STRUCT_DEF => HighlightTag::Struct.into(),
        ENUM_DEF => HighlightTag::Enum.into(),
        UNION_DEF => HighlightTag::Union.into(),
        TRAIT_DEF => HighlightTag::Trait.into(),
        TYPE_ALIAS_DEF => HighlightTag::TypeAlias.into(),
        TYPE_PARAM => HighlightTag::TypeParam.into(),
        RECORD_FIELD_DEF => HighlightTag::Field.into(),
        _ => default,
    }
}

fn highlight_injection(
    acc: &mut Vec<HighlightedRange>,
    sema: &Semantics<RootDatabase>,
    literal: ast::RawString,
    expanded: SyntaxToken,
) -> Option<()> {
    let call_info = call_info_for_token(&sema, expanded)?;
    let idx = call_info.active_parameter?;
    let name = call_info.signature.parameter_names.get(idx)?;
    if name != "ra_fixture" {
        return None;
    }
    let value = literal.value()?;
    let (analysis, tmp_file_id) = Analysis::from_single_file(value);

    if let Some(range) = literal.open_quote_text_range() {
        acc.push(HighlightedRange {
            range,
            highlight: HighlightTag::StringLiteral.into(),
            binding_hash: None,
        })
    }

    for mut h in analysis.highlight(tmp_file_id).unwrap() {
        if let Some(r) = literal.map_range_up(h.range) {
            h.range = r;
            acc.push(h)
        }
    }

    if let Some(range) = literal.close_quote_text_range() {
        acc.push(HighlightedRange {
            range,
            highlight: HighlightTag::StringLiteral.into(),
            binding_hash: None,
        })
    }

    Some(())
}
<commit_msg>Remove debug print<commit_after>//! Implements syntax highlighting.

mod tags;
mod html;
#[cfg(test)]
mod tests;

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

use crate::{call_info::call_info_for_token, references::classify_name_ref, Analysis, FileId};

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

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

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

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

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

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

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

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

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

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

        let range = element.text_range();

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

        if let Some(token) = element.as_token().cloned().and_then(ast::RawString::cast) {
            let expanded = element_to_highlight.as_token().unwrap().clone();
            if highlight_injection(&mut res, &sema, token, expanded).is_some() {
                continue;
            }
        }

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

    res
}

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

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

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

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

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

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

            match name_kind {
                Some(NameClass::NameDefinition(def)) => {
                    highlight_name(db, def) | HighlightModifier::Definition
                }
                Some(NameClass::ConstReference(def)) => highlight_name(db, def),
                None => highlight_name_by_syntax(name) | HighlightModifier::Definition,
            }
        }

        // Highlight references like the definitions they resolve to

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

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

            highlight_name(db, name_kind)
        }

        // Simple token-based highlighting
        COMMENT => HighlightTag::Comment.into(),
        STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => HighlightTag::StringLiteral.into(),
        ATTR => HighlightTag::Attribute.into(),
        INT_NUMBER | FLOAT_NUMBER => HighlightTag::NumericLiteral.into(),
        BYTE => HighlightTag::ByteLiteral.into(),
        CHAR => HighlightTag::CharLiteral.into(),
        LIFETIME => {
            let h = Highlight::new(HighlightTag::Lifetime);
            dbg!(match element.parent().map(|it| it.kind()) {
                Some(LIFETIME_PARAM) | Some(LABEL) => h | HighlightModifier::Definition,
                _ => h,
            })
        }

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

        _ => return None,
    };

    return Some((highlight, binding_hash));

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

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

        hash((name, shadow_count))
    }
}

fn highlight_name(db: &RootDatabase, def: NameDefinition) -> Highlight {
    match def {
        NameDefinition::Macro(_) => HighlightTag::Macro,
        NameDefinition::StructField(_) => HighlightTag::Field,
        NameDefinition::ModuleDef(def) => match def {
            hir::ModuleDef::Module(_) => HighlightTag::Module,
            hir::ModuleDef::Function(_) => HighlightTag::Function,
            hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Struct,
            hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HighlightTag::Enum,
            hir::ModuleDef::Adt(hir::Adt::Union(_)) => HighlightTag::Union,
            hir::ModuleDef::EnumVariant(_) => HighlightTag::EnumVariant,
            hir::ModuleDef::Const(_) => HighlightTag::Constant,
            hir::ModuleDef::Static(_) => HighlightTag::Static,
            hir::ModuleDef::Trait(_) => HighlightTag::Trait,
            hir::ModuleDef::TypeAlias(_) => HighlightTag::TypeAlias,
            hir::ModuleDef::BuiltinType(_) => HighlightTag::BuiltinType,
        },
        NameDefinition::SelfType(_) => HighlightTag::SelfType,
        NameDefinition::TypeParam(_) => HighlightTag::TypeParam,
        // FIXME: distinguish between locals and parameters
        NameDefinition::Local(local) => {
            let mut h = Highlight::new(HighlightTag::Local);
            if local.is_mut(db) || local.ty(db).is_mutable_reference() {
                h |= HighlightModifier::Mutable;
            }
            return h;
        }
    }
    .into()
}

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

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

    match parent.kind() {
        STRUCT_DEF => HighlightTag::Struct.into(),
        ENUM_DEF => HighlightTag::Enum.into(),
        UNION_DEF => HighlightTag::Union.into(),
        TRAIT_DEF => HighlightTag::Trait.into(),
        TYPE_ALIAS_DEF => HighlightTag::TypeAlias.into(),
        TYPE_PARAM => HighlightTag::TypeParam.into(),
        RECORD_FIELD_DEF => HighlightTag::Field.into(),
        _ => default,
    }
}

fn highlight_injection(
    acc: &mut Vec<HighlightedRange>,
    sema: &Semantics<RootDatabase>,
    literal: ast::RawString,
    expanded: SyntaxToken,
) -> Option<()> {
    let call_info = call_info_for_token(&sema, expanded)?;
    let idx = call_info.active_parameter?;
    let name = call_info.signature.parameter_names.get(idx)?;
    if name != "ra_fixture" {
        return None;
    }
    let value = literal.value()?;
    let (analysis, tmp_file_id) = Analysis::from_single_file(value);

    if let Some(range) = literal.open_quote_text_range() {
        acc.push(HighlightedRange {
            range,
            highlight: HighlightTag::StringLiteral.into(),
            binding_hash: None,
        })
    }

    for mut h in analysis.highlight(tmp_file_id).unwrap() {
        if let Some(r) = literal.map_range_up(h.range) {
            h.range = r;
            acc.push(h)
        }
    }

    if let Some(range) = literal.close_quote_text_range() {
        acc.push(HighlightedRange {
            range,
            highlight: HighlightTag::StringLiteral.into(),
            binding_hash: None,
        })
    }

    Some(())
}
<|endoftext|>


<commit_before>use std::borrow::Borrow;
use std::io;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::cmp::min;

pub use mio::{EventSet, PollOpt, Token};
use mio::Timeout as MioTimeout;
use mio::tcp::{TcpListener, TcpStream};
use mio::util::Slab;

use super::connection::{IncomingConnection, OutgoingConnection};
use super::{Timeout, InternalTimeout, EventLoop};

use super::super::messages::{MessageBuffer, RawMessage};

pub type PeerId = Token;

const SERVER_ID: PeerId = Token(1);
const RECONNECT_GROW_FACTOR: f32 = 2.0;

#[derive(Debug)]
pub enum Output {
    Data(MessageBuffer),
    Connected(SocketAddr),
    Disconnected(SocketAddr),
}

#[derive(Debug, Clone, Copy)]
pub struct NetworkConfiguration {
    // TODO: think more about config parameters
    pub listen_address: SocketAddr,
    pub max_incoming_connections: usize,
    pub max_outgoing_connections: usize,
    pub tcp_nodelay: bool,
    pub tcp_keep_alive: Option<u32>,
    pub tcp_reconnect_timeout: u64,
    pub tcp_reconnect_timeout_max: u64,
}

pub struct Network {
    config: NetworkConfiguration,
    listener: Option<TcpListener>,

    incoming: Slab<IncomingConnection>,
    outgoing: Slab<OutgoingConnection>,
    addresses: HashMap<SocketAddr, PeerId>,

    reconnects: HashMap<SocketAddr, MioTimeout>,
}

enum PeerKind {
    Server,
    Incoming,
    Outgoing,
}

fn make_error<T: Borrow<str>>(s: T) -> io::Error {
    io::Error::new(io::ErrorKind::Other, s.borrow())
}

impl Network {
    pub fn with_config(config: NetworkConfiguration) -> Network {
        Network {
            config: config,
            listener: None,

            incoming: Slab::new_starting_at(Token(2), config.max_incoming_connections),
            outgoing: Slab::new_starting_at(Token(2 + config.max_incoming_connections),
                                            config.max_outgoing_connections),
            addresses: HashMap::new(),

            reconnects: HashMap::new(),
        }
    }

    pub fn address(&self) -> &SocketAddr {
        &self.config.listen_address
    }

    // TODO use error trait
    pub fn bind(&mut self, event_loop: &mut EventLoop) -> io::Result<()> {
        if let Some(_) = self.listener {
            return Err(make_error("Already binded"));
        }
        let listener = TcpListener::bind(&self.config.listen_address)?;
        let r = event_loop.register(&listener, SERVER_ID, EventSet::readable(), PollOpt::edge());
        match r {
            Ok(()) => {
                self.listener = Some(listener);
                Ok(())
            }
            Err(e) => Err(e),
        }
    }

    // TODO: Use ticks for fast reregistering sockets
    // TODO: Implement Connections collection with (re)registering
    pub fn io(&mut self,
              event_loop: &mut EventLoop,
              id: PeerId,
              set: EventSet)
              -> io::Result<Option<Output>> {

        match self.peer_kind(id) {
            PeerKind::Server => {
                // Accept new connections
                // FIXME: Fail-safe accepting of new connections?
                let pair = match self.listener {
                    Some(ref listener) => listener.accept()?,
                    None => None,
                };
                if let Some((socket, address)) = pair {
                    let peer = IncomingConnection::new(socket, address);
                    self.add_incoming_connection(event_loop, peer)?;

                    debug!("{}: Accepted incoming connection from {} id: {}",
                           self.address(),
                           address,
                           id.0);
                }
                return Ok(None);
            }
            PeerKind::Incoming => {
                if !self.incoming.contains(id) {
                    return Ok(None)
                }

                if set.is_hup() | set.is_error() {
                    debug!("{}: incoming connection with addr {} closed",
                           self.address(),
                           self.incoming[id].address());

                    self.remove_incoming_connection(event_loop, id);
                    return Ok(None);
                }

                if set.is_readable() {
                    let address = *self.incoming[id].address();

                    trace!("{}: Socket is readable {} id: {}",
                           self.address(),
                           address,
                           id.0);

                    return match self.incoming[id].try_read() {
                        Ok(Some(buffer)) => Ok(Some(Output::Data(buffer))),
                        Ok(None) => Ok(None),
                        Err(e) => {
                            self.remove_incoming_connection(event_loop, id);
                            Err(e)
                        }
                    };
                }
            }
            PeerKind::Outgoing => {
                if !self.outgoing.contains(id) {
                    return Ok(None)
                }

                if set.is_hup() | set.is_error() {
                    let address = *self.outgoing[id].address();

                    debug!("{}: outgoing connection with addr {} closed",
                           self.address(),
                           self.outgoing[id].address());

                    self.remove_outgoing_connection(event_loop, id);
                    if self.reconnects.contains_key(&address) {
                        return Ok(None);
                    }
                    return Ok(Some(Output::Disconnected(address)));
                }

                if set.is_writable() {
                    let address = *self.outgoing[id].address();

                    trace!("{}: Socket is writable {} id: {}",
                           self.address(),
                           address,
                           id.0);

                    let r = {
                        self.outgoing[id].try_write()?;
                        event_loop.reregister(self.outgoing[id].socket(),
                                        id,
                                        self.outgoing[id].interest(),
                                        PollOpt::edge())?;
                        Ok(())
                    };

                    // Write data into socket
                    if let Err(e) = r {
                        self.remove_outgoing_connection(event_loop, id);
                        return Err(e);
                    }
                    return Ok(self.mark_connected(event_loop, id));
                }
            }
        }
        // FIXME: Can we be here?
        Ok(None)
    }

    pub fn tick(&mut self, _: &mut EventLoop) {}

    pub fn send_to(&mut self,
                   event_loop: &mut EventLoop,
                   address: &SocketAddr,
                   message: RawMessage)
                   -> io::Result<()> {
        let r = match self.get_outgoing_peer(address) {
            Ok(id) => {
                self.outgoing[id]
                    .send(message)
                    .and_then(|_| {
                        event_loop.reregister(self.outgoing[id].socket(),
                                        id,
                                        self.outgoing[id].interest(),
                                        PollOpt::edge())?;
                        self.mark_connected(event_loop, id);
                        Ok(())
                    })
                    .or_else(|e| {
                        self.remove_outgoing_connection(event_loop, id);
                        Err(e)
                    })
            }
            Err(e) => Err(e),
        };
        r
    }

    pub fn connect(&mut self, event_loop: &mut EventLoop, address: &SocketAddr) -> io::Result<()> {
        if !self.addresses.contains_key(address) {
            let peer = OutgoingConnection::new(TcpStream::connect(address)?, *address);
            let id = self.add_outgoing_connection(event_loop, peer)?;
            self.try_reconnect_addr(event_loop, *address)?;

            debug!("{}: Establish connection with {}, id: {}",
                   self.address(),
                   address,
                   id.0);
        }
        Ok(())
    }

    pub fn handle_timeout(&mut self, event_loop: &mut EventLoop, timeout: InternalTimeout) {
        match timeout {
            InternalTimeout::Reconnect(addr, delay) => {
                if self.reconnects.contains_key(&addr) {
                    debug!("Try to reconnect with delay {}", delay);

                    if let Err(e) = self.connect(event_loop, &addr) {
                        error!("{}: Unable to create connection to addr {}, error: {:?}",
                               self.address(),
                               addr,
                               e);
                    }

                    let delay = min((delay as f32 * RECONNECT_GROW_FACTOR) as u64,
                                    self.config.tcp_reconnect_timeout_max);

                    if let Err(e) = self.add_reconnect_timeout(event_loop, addr, delay) {
                        error!("{}: Unable to add timeout, error: {:?}", self.address(), e);
                    }
                }
            }
        }
    }

    fn peer_kind(&self, id: PeerId) -> PeerKind {
        if id == SERVER_ID {
            PeerKind::Server
        } else if id.0 >= (2 + self.config.max_incoming_connections) {
            PeerKind::Outgoing
        } else {
            PeerKind::Incoming
        }
    }

    fn get_outgoing_peer(&self, addr: &SocketAddr) -> io::Result<PeerId> {
        if let Some(id) = self.addresses.get(addr) {
            return Ok(*id);
        };
        Err(make_error(format!("{}: Outgoing peer not found {}", self.address(), addr)))
    }

    fn add_incoming_connection(&mut self,
                               event_loop: &mut EventLoop,
                               mut connection: IncomingConnection)
                               -> io::Result<PeerId> {
        self.configure_stream(connection.socket_mut())?;
        let address = *connection.address();
        let id = self.incoming
            .insert(connection)
            .map_err(|_| make_error("Maximum incoming onnections"))?;
        self.addresses.insert(address, id);

        let r = event_loop.register(self.incoming[id].socket(),
                                    id,
                                    self.incoming[id].interest(),
                                    PollOpt::edge());

        if let Err(e) = r {
            self.remove_incoming_connection(event_loop, id);
            return Err(e);
        }
        Ok(id)
    }

    fn add_outgoing_connection(&mut self,
                               event_loop: &mut EventLoop,
                               connection: OutgoingConnection)
                               -> io::Result<PeerId> {
        let address = *connection.address();
        let id = self.outgoing
            .insert(connection)
            .map_err(|_| make_error("Maximum outgoing onnections"))?;
        self.addresses.insert(address, id);

        let r = event_loop.register(self.outgoing[id].socket(),
                                    id,
                                    self.outgoing[id].interest() | EventSet::writable(),
                                    PollOpt::edge());

        if let Err(e) = r {
            self.remove_outgoing_connection(event_loop, id);
            return Err(e);
        }
        Ok(id)
    }

    fn remove_incoming_connection(&mut self, event_loop: &mut EventLoop, id: PeerId) {
        let addr = *self.incoming[id].address();
        self.addresses.remove(&addr);
        if let Some(connection) = self.incoming.remove(id) {
            if let Err(e) = event_loop.deregister(connection.socket()) {
                error!("{}: Unable to deregister incoming connection, id: {}, error: {:?}",
                       self.address(),
                       id.0,
                       e);
            }
        }
    }

    fn remove_outgoing_connection(&mut self, event_loop: &mut EventLoop, id: PeerId) {
        let addr = *self.outgoing[id].address();
        self.addresses.remove(&addr);
        if let Some(connection) = self.outgoing.remove(id) {
            if let Err(e) = event_loop.deregister(connection.socket()) {
                error!("{}: Unable to deregister outgoing connection, id: {}, error: {:?}",
                       self.address(),
                       id.0,
                       e);
            }
        }
    }

    fn configure_stream(&self, stream: &mut TcpStream) -> io::Result<()> {
        stream.set_keepalive(self.config.tcp_keep_alive)?;
        stream.set_nodelay(self.config.tcp_nodelay)?;
        Ok(())
    }

    fn try_reconnect_addr(&mut self,
                          event_loop: &mut EventLoop,
                          address: SocketAddr)
                          -> io::Result<()> {
        if !self.reconnects.contains_key(&address) {
            let delay = self.config.tcp_reconnect_timeout;
            return self.add_reconnect_timeout(event_loop, address, delay);
        }
        Ok(())
    }

    fn add_reconnect_timeout(&mut self,
                             event_loop: &mut EventLoop,
                             address: SocketAddr,
                             delay: u64)
                             -> io::Result<()> {
        let reconnect = Timeout::Internal(InternalTimeout::Reconnect(address, delay));
        let timeout = event_loop.timeout_ms(reconnect, delay)
            .map_err(|e| make_error(format!("A mio error occured {:?}", e)))?;
        self.reconnects.insert(address, timeout);
        Ok(())
    }

    fn mark_connected(&mut self, event_loop: &mut EventLoop, id: Token) -> Option<Output> {
        let address = *self.outgoing[id].address();
        self.clear_reconnect_request(event_loop, &address)
    }

    fn clear_reconnect_request(&mut self,
                               event_loop: &mut EventLoop,
                               addr: &SocketAddr)
                               -> Option<Output> {
        if let Some(timeout) = self.reconnects.remove(addr) {
            event_loop.clear_timeout(timeout);
            return Some(Output::Connected(*addr));
        }
        None
    }
}

#[cfg(test)]
mod tests {}
<commit_msg>Polish code<commit_after>use std::borrow::Borrow;
use std::io;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::cmp::min;

pub use mio::{EventSet, PollOpt, Token};
use mio::Timeout as MioTimeout;
use mio::tcp::{TcpListener, TcpStream};
use mio::util::Slab;

use super::connection::{IncomingConnection, OutgoingConnection};
use super::{Timeout, InternalTimeout, EventLoop};

use super::super::messages::{MessageBuffer, RawMessage};

pub type PeerId = Token;

const SERVER_ID: PeerId = Token(1);
const RECONNECT_GROW_FACTOR: f32 = 2.0;

#[derive(Debug)]
pub enum Output {
    Data(MessageBuffer),
    Connected(SocketAddr),
    Disconnected(SocketAddr),
}

#[derive(Debug, Clone, Copy)]
pub struct NetworkConfiguration {
    // TODO: think more about config parameters
    pub listen_address: SocketAddr,
    pub max_incoming_connections: usize,
    pub max_outgoing_connections: usize,
    pub tcp_nodelay: bool,
    pub tcp_keep_alive: Option<u32>,
    pub tcp_reconnect_timeout: u64,
    pub tcp_reconnect_timeout_max: u64,
}

pub struct Network {
    config: NetworkConfiguration,
    listener: Option<TcpListener>,

    incoming: Slab<IncomingConnection>,
    outgoing: Slab<OutgoingConnection>,
    addresses: HashMap<SocketAddr, PeerId>,

    reconnects: HashMap<SocketAddr, MioTimeout>,
}

enum PeerKind {
    Server,
    Incoming,
    Outgoing,
}

fn make_error<T: Borrow<str>>(s: T) -> io::Error {
    io::Error::new(io::ErrorKind::Other, s.borrow())
}

impl Network {
    pub fn with_config(config: NetworkConfiguration) -> Network {
        Network {
            config: config,
            listener: None,

            incoming: Slab::new_starting_at(Token(2), config.max_incoming_connections),
            outgoing: Slab::new_starting_at(Token(2 + config.max_incoming_connections),
                                            config.max_outgoing_connections),
            addresses: HashMap::new(),

            reconnects: HashMap::new(),
        }
    }

    pub fn address(&self) -> &SocketAddr {
        &self.config.listen_address
    }

    // TODO use error trait
    pub fn bind(&mut self, event_loop: &mut EventLoop) -> io::Result<()> {
        if let Some(_) = self.listener {
            return Err(make_error("Already binded"));
        }
        let listener = TcpListener::bind(&self.config.listen_address)?;
        event_loop.register(&listener, SERVER_ID, EventSet::readable(), PollOpt::edge())?;
        self.listener = Some(listener);
        Ok(())
    }

    // TODO: Use ticks for fast reregistering sockets
    // TODO: Implement Connections collection with (re)registering
    pub fn io(&mut self,
              event_loop: &mut EventLoop,
              id: PeerId,
              set: EventSet)
              -> io::Result<Option<Output>> {

        match self.peer_kind(id) {
            PeerKind::Server => {
                // Accept new connections
                // FIXME: Fail-safe accepting of new connections?
                let pair = match self.listener {
                    Some(ref listener) => listener.accept()?,
                    None => None,
                };
                if let Some((socket, address)) = pair {
                    let peer = IncomingConnection::new(socket, address);
                    self.add_incoming_connection(event_loop, peer)?;

                    debug!("{}: Accepted incoming connection from {} id: {}",
                           self.address(),
                           address,
                           id.0);
                }
                return Ok(None);
            }
            PeerKind::Incoming => {
                if !self.incoming.contains(id) {
                    return Ok(None);
                }

                if set.is_hup() | set.is_error() {
                    debug!("{}: incoming connection with addr {} closed",
                           self.address(),
                           self.incoming[id].address());

                    self.remove_incoming_connection(event_loop, id);
                    return Ok(None);
                }

                if set.is_readable() {
                    let address = *self.incoming[id].address();

                    trace!("{}: Socket is readable {} id: {}",
                           self.address(),
                           address,
                           id.0);

                    return match self.incoming[id].try_read() {
                        Ok(Some(buffer)) => Ok(Some(Output::Data(buffer))),
                        Ok(None) => Ok(None),
                        Err(e) => {
                            self.remove_incoming_connection(event_loop, id);
                            Err(e)
                        }
                    };
                }
            }
            PeerKind::Outgoing => {
                if !self.outgoing.contains(id) {
                    return Ok(None);
                }

                if set.is_hup() | set.is_error() {
                    let address = *self.outgoing[id].address();

                    debug!("{}: outgoing connection with addr {} closed",
                           self.address(),
                           self.outgoing[id].address());

                    self.remove_outgoing_connection(event_loop, id);
                    if self.reconnects.contains_key(&address) {
                        return Ok(None);
                    }
                    return Ok(Some(Output::Disconnected(address)));
                }

                if set.is_writable() {
                    let address = *self.outgoing[id].address();

                    trace!("{}: Socket is writable {} id: {}",
                           self.address(),
                           address,
                           id.0);

                    let r = {
                        self.outgoing[id].try_write()?;
                        event_loop.reregister(self.outgoing[id].socket(),
                                        id,
                                        self.outgoing[id].interest(),
                                        PollOpt::edge())?;
                        Ok(())
                    };

                    // Write data into socket
                    if let Err(e) = r {
                        self.remove_outgoing_connection(event_loop, id);
                        return Err(e);
                    }
                    return Ok(self.mark_connected(event_loop, id));
                }
            }
        }
        // FIXME: Can we be here?
        Ok(None)
    }

    pub fn tick(&mut self, _: &mut EventLoop) {}

    pub fn send_to(&mut self,
                   event_loop: &mut EventLoop,
                   address: &SocketAddr,
                   message: RawMessage)
                   -> io::Result<()> {
        let r = match self.get_outgoing_peer(address) {
            Ok(id) => {
                self.outgoing[id]
                    .send(message)
                    .and_then(|_| {
                        event_loop.reregister(self.outgoing[id].socket(),
                                        id,
                                        self.outgoing[id].interest(),
                                        PollOpt::edge())?;
                        self.mark_connected(event_loop, id);
                        Ok(())
                    })
                    .or_else(|e| {
                        self.remove_outgoing_connection(event_loop, id);
                        Err(e)
                    })
            }
            Err(e) => Err(e),
        };
        r
    }

    pub fn connect(&mut self, event_loop: &mut EventLoop, address: &SocketAddr) -> io::Result<()> {
        if !self.addresses.contains_key(address) {
            let peer = OutgoingConnection::new(TcpStream::connect(address)?, *address);
            let id = self.add_outgoing_connection(event_loop, peer)?;
            self.try_reconnect_addr(event_loop, *address)?;

            debug!("{}: Establish connection with {}, id: {}",
                   self.address(),
                   address,
                   id.0);
        }
        Ok(())
    }

    pub fn handle_timeout(&mut self, event_loop: &mut EventLoop, timeout: InternalTimeout) {
        match timeout {
            InternalTimeout::Reconnect(addr, delay) => {
                if self.reconnects.contains_key(&addr) {
                    debug!("Try to reconnect with delay {}", delay);

                    if let Err(e) = self.connect(event_loop, &addr) {
                        error!("{}: Unable to create connection to addr {}, error: {:?}",
                               self.address(),
                               addr,
                               e);
                    }

                    let delay = min((delay as f32 * RECONNECT_GROW_FACTOR) as u64,
                                    self.config.tcp_reconnect_timeout_max);

                    if let Err(e) = self.add_reconnect_timeout(event_loop, addr, delay) {
                        error!("{}: Unable to add timeout, error: {:?}", self.address(), e);
                    }
                }
            }
        }
    }

    fn peer_kind(&self, id: PeerId) -> PeerKind {
        if id == SERVER_ID {
            PeerKind::Server
        } else if id.0 >= (2 + self.config.max_incoming_connections) {
            PeerKind::Outgoing
        } else {
            PeerKind::Incoming
        }
    }

    fn get_outgoing_peer(&self, addr: &SocketAddr) -> io::Result<PeerId> {
        if let Some(id) = self.addresses.get(addr) {
            return Ok(*id);
        };
        Err(make_error(format!("{}: Outgoing peer not found {}", self.address(), addr)))
    }

    fn add_incoming_connection(&mut self,
                               event_loop: &mut EventLoop,
                               mut connection: IncomingConnection)
                               -> io::Result<PeerId> {
        self.configure_stream(connection.socket_mut())?;
        let address = *connection.address();
        let id = self.incoming
            .insert(connection)
            .map_err(|_| make_error("Maximum incoming onnections"))?;
        self.addresses.insert(address, id);

        let r = event_loop.register(self.incoming[id].socket(),
                                    id,
                                    self.incoming[id].interest(),
                                    PollOpt::edge());

        if let Err(e) = r {
            self.remove_incoming_connection(event_loop, id);
            return Err(e);
        }
        Ok(id)
    }

    fn add_outgoing_connection(&mut self,
                               event_loop: &mut EventLoop,
                               connection: OutgoingConnection)
                               -> io::Result<PeerId> {
        let address = *connection.address();
        let id = self.outgoing
            .insert(connection)
            .map_err(|_| make_error("Maximum outgoing onnections"))?;
        self.addresses.insert(address, id);

        let r = event_loop.register(self.outgoing[id].socket(),
                                    id,
                                    self.outgoing[id].interest() | EventSet::writable(),
                                    PollOpt::edge());

        if let Err(e) = r {
            self.remove_outgoing_connection(event_loop, id);
            return Err(e);
        }
        Ok(id)
    }

    fn remove_incoming_connection(&mut self, event_loop: &mut EventLoop, id: PeerId) {
        let addr = *self.incoming[id].address();
        self.addresses.remove(&addr);
        if let Some(connection) = self.incoming.remove(id) {
            if let Err(e) = event_loop.deregister(connection.socket()) {
                error!("{}: Unable to deregister incoming connection, id: {}, error: {:?}",
                       self.address(),
                       id.0,
                       e);
            }
        }
    }

    fn remove_outgoing_connection(&mut self, event_loop: &mut EventLoop, id: PeerId) {
        let addr = *self.outgoing[id].address();
        self.addresses.remove(&addr);
        if let Some(connection) = self.outgoing.remove(id) {
            if let Err(e) = event_loop.deregister(connection.socket()) {
                error!("{}: Unable to deregister outgoing connection, id: {}, error: {:?}",
                       self.address(),
                       id.0,
                       e);
            }
        }
    }

    fn configure_stream(&self, stream: &mut TcpStream) -> io::Result<()> {
        stream.set_keepalive(self.config.tcp_keep_alive)?;
        stream.set_nodelay(self.config.tcp_nodelay)
    }

    fn try_reconnect_addr(&mut self,
                          event_loop: &mut EventLoop,
                          address: SocketAddr)
                          -> io::Result<()> {
        if !self.reconnects.contains_key(&address) {
            let delay = self.config.tcp_reconnect_timeout;
            return self.add_reconnect_timeout(event_loop, address, delay);
        }
        Ok(())
    }

    fn add_reconnect_timeout(&mut self,
                             event_loop: &mut EventLoop,
                             address: SocketAddr,
                             delay: u64)
                             -> io::Result<()> {
        let reconnect = Timeout::Internal(InternalTimeout::Reconnect(address, delay));
        let timeout = event_loop.timeout_ms(reconnect, delay)
            .map_err(|e| make_error(format!("A mio error occured {:?}", e)))?;
        self.reconnects.insert(address, timeout);
        Ok(())
    }

    fn mark_connected(&mut self, event_loop: &mut EventLoop, id: Token) -> Option<Output> {
        let address = *self.outgoing[id].address();
        self.clear_reconnect_request(event_loop, &address)
    }

    fn clear_reconnect_request(&mut self,
                               event_loop: &mut EventLoop,
                               addr: &SocketAddr)
                               -> Option<Output> {
        if let Some(timeout) = self.reconnects.remove(addr) {
            event_loop.clear_timeout(timeout);
            return Some(Output::Connected(*addr));
        }
        None
    }
}

#[cfg(test)]
mod tests {}
<|endoftext|>


<commit_before>//! Basic http responses
#![allow(non_upper_case_globals)]
use http::StatusCode;

use crate::response::{Response, ResponseBuilder};

macro_rules! STATIC_RESP {
    ($name:ident, $status:expr) => {
        #[allow(non_snake_case, missing_docs)]
        pub fn $name() -> ResponseBuilder {
            ResponseBuilder::new($status)
        }
    };
}

impl Response {
    STATIC_RESP!(Ok, StatusCode::OK);
    STATIC_RESP!(Created, StatusCode::CREATED);
    STATIC_RESP!(Accepted, StatusCode::ACCEPTED);
    STATIC_RESP!(
        NonAuthoritativeInformation,
        StatusCode::NON_AUTHORITATIVE_INFORMATION
    );

    STATIC_RESP!(NoContent, StatusCode::NO_CONTENT);
    STATIC_RESP!(ResetContent, StatusCode::RESET_CONTENT);
    STATIC_RESP!(PartialContent, StatusCode::PARTIAL_CONTENT);
    STATIC_RESP!(MultiStatus, StatusCode::MULTI_STATUS);
    STATIC_RESP!(AlreadyReported, StatusCode::ALREADY_REPORTED);

    STATIC_RESP!(MultipleChoices, StatusCode::MULTIPLE_CHOICES);
    STATIC_RESP!(MovedPermanenty, StatusCode::MOVED_PERMANENTLY);
    STATIC_RESP!(MovedPermanently, StatusCode::MOVED_PERMANENTLY);
    STATIC_RESP!(Found, StatusCode::FOUND);
    STATIC_RESP!(SeeOther, StatusCode::SEE_OTHER);
    STATIC_RESP!(NotModified, StatusCode::NOT_MODIFIED);
    STATIC_RESP!(UseProxy, StatusCode::USE_PROXY);
    STATIC_RESP!(TemporaryRedirect, StatusCode::TEMPORARY_REDIRECT);
    STATIC_RESP!(PermanentRedirect, StatusCode::PERMANENT_REDIRECT);

    STATIC_RESP!(BadRequest, StatusCode::BAD_REQUEST);
    STATIC_RESP!(NotFound, StatusCode::NOT_FOUND);
    STATIC_RESP!(Unauthorized, StatusCode::UNAUTHORIZED);
    STATIC_RESP!(PaymentRequired, StatusCode::PAYMENT_REQUIRED);
    STATIC_RESP!(Forbidden, StatusCode::FORBIDDEN);
    STATIC_RESP!(MethodNotAllowed, StatusCode::METHOD_NOT_ALLOWED);
    STATIC_RESP!(NotAcceptable, StatusCode::NOT_ACCEPTABLE);
    STATIC_RESP!(
        ProxyAuthenticationRequired,
        StatusCode::PROXY_AUTHENTICATION_REQUIRED
    );
    STATIC_RESP!(RequestTimeout, StatusCode::REQUEST_TIMEOUT);
    STATIC_RESP!(Conflict, StatusCode::CONFLICT);
    STATIC_RESP!(Gone, StatusCode::GONE);
    STATIC_RESP!(LengthRequired, StatusCode::LENGTH_REQUIRED);
    STATIC_RESP!(PreconditionFailed, StatusCode::PRECONDITION_FAILED);
    STATIC_RESP!(PreconditionRequired, StatusCode::PRECONDITION_REQUIRED);
    STATIC_RESP!(PayloadTooLarge, StatusCode::PAYLOAD_TOO_LARGE);
    STATIC_RESP!(UriTooLong, StatusCode::URI_TOO_LONG);
    STATIC_RESP!(UnsupportedMediaType, StatusCode::UNSUPPORTED_MEDIA_TYPE);
    STATIC_RESP!(RangeNotSatisfiable, StatusCode::RANGE_NOT_SATISFIABLE);
    STATIC_RESP!(ExpectationFailed, StatusCode::EXPECTATION_FAILED);
    STATIC_RESP!(UnprocessableEntity, StatusCode::UNPROCESSABLE_ENTITY);
    STATIC_RESP!(TooManyRequests, StatusCode::TOO_MANY_REQUESTS);

    STATIC_RESP!(InternalServerError, StatusCode::INTERNAL_SERVER_ERROR);
    STATIC_RESP!(NotImplemented, StatusCode::NOT_IMPLEMENTED);
    STATIC_RESP!(BadGateway, StatusCode::BAD_GATEWAY);
    STATIC_RESP!(ServiceUnavailable, StatusCode::SERVICE_UNAVAILABLE);
    STATIC_RESP!(GatewayTimeout, StatusCode::GATEWAY_TIMEOUT);
    STATIC_RESP!(VersionNotSupported, StatusCode::HTTP_VERSION_NOT_SUPPORTED);
    STATIC_RESP!(VariantAlsoNegotiates, StatusCode::VARIANT_ALSO_NEGOTIATES);
    STATIC_RESP!(InsufficientStorage, StatusCode::INSUFFICIENT_STORAGE);
    STATIC_RESP!(LoopDetected, StatusCode::LOOP_DETECTED);
}

#[cfg(test)]
mod tests {
    use crate::body::Body;
    use crate::response::Response;
    use http::StatusCode;

    #[test]
    fn test_build() {
        let resp = Response::Ok().body(Body::Empty);
        assert_eq!(resp.status(), StatusCode::OK);
    }
}
<commit_msg>Removed httpcode 'MovedPermanenty'. (#1128)<commit_after>//! Basic http responses
#![allow(non_upper_case_globals)]
use http::StatusCode;

use crate::response::{Response, ResponseBuilder};

macro_rules! STATIC_RESP {
    ($name:ident, $status:expr) => {
        #[allow(non_snake_case, missing_docs)]
        pub fn $name() -> ResponseBuilder {
            ResponseBuilder::new($status)
        }
    };
}

impl Response {
    STATIC_RESP!(Ok, StatusCode::OK);
    STATIC_RESP!(Created, StatusCode::CREATED);
    STATIC_RESP!(Accepted, StatusCode::ACCEPTED);
    STATIC_RESP!(
        NonAuthoritativeInformation,
        StatusCode::NON_AUTHORITATIVE_INFORMATION
    );

    STATIC_RESP!(NoContent, StatusCode::NO_CONTENT);
    STATIC_RESP!(ResetContent, StatusCode::RESET_CONTENT);
    STATIC_RESP!(PartialContent, StatusCode::PARTIAL_CONTENT);
    STATIC_RESP!(MultiStatus, StatusCode::MULTI_STATUS);
    STATIC_RESP!(AlreadyReported, StatusCode::ALREADY_REPORTED);

    STATIC_RESP!(MultipleChoices, StatusCode::MULTIPLE_CHOICES);
    STATIC_RESP!(MovedPermanently, StatusCode::MOVED_PERMANENTLY);
    STATIC_RESP!(Found, StatusCode::FOUND);
    STATIC_RESP!(SeeOther, StatusCode::SEE_OTHER);
    STATIC_RESP!(NotModified, StatusCode::NOT_MODIFIED);
    STATIC_RESP!(UseProxy, StatusCode::USE_PROXY);
    STATIC_RESP!(TemporaryRedirect, StatusCode::TEMPORARY_REDIRECT);
    STATIC_RESP!(PermanentRedirect, StatusCode::PERMANENT_REDIRECT);

    STATIC_RESP!(BadRequest, StatusCode::BAD_REQUEST);
    STATIC_RESP!(NotFound, StatusCode::NOT_FOUND);
    STATIC_RESP!(Unauthorized, StatusCode::UNAUTHORIZED);
    STATIC_RESP!(PaymentRequired, StatusCode::PAYMENT_REQUIRED);
    STATIC_RESP!(Forbidden, StatusCode::FORBIDDEN);
    STATIC_RESP!(MethodNotAllowed, StatusCode::METHOD_NOT_ALLOWED);
    STATIC_RESP!(NotAcceptable, StatusCode::NOT_ACCEPTABLE);
    STATIC_RESP!(
        ProxyAuthenticationRequired,
        StatusCode::PROXY_AUTHENTICATION_REQUIRED
    );
    STATIC_RESP!(RequestTimeout, StatusCode::REQUEST_TIMEOUT);
    STATIC_RESP!(Conflict, StatusCode::CONFLICT);
    STATIC_RESP!(Gone, StatusCode::GONE);
    STATIC_RESP!(LengthRequired, StatusCode::LENGTH_REQUIRED);
    STATIC_RESP!(PreconditionFailed, StatusCode::PRECONDITION_FAILED);
    STATIC_RESP!(PreconditionRequired, StatusCode::PRECONDITION_REQUIRED);
    STATIC_RESP!(PayloadTooLarge, StatusCode::PAYLOAD_TOO_LARGE);
    STATIC_RESP!(UriTooLong, StatusCode::URI_TOO_LONG);
    STATIC_RESP!(UnsupportedMediaType, StatusCode::UNSUPPORTED_MEDIA_TYPE);
    STATIC_RESP!(RangeNotSatisfiable, StatusCode::RANGE_NOT_SATISFIABLE);
    STATIC_RESP!(ExpectationFailed, StatusCode::EXPECTATION_FAILED);
    STATIC_RESP!(UnprocessableEntity, StatusCode::UNPROCESSABLE_ENTITY);
    STATIC_RESP!(TooManyRequests, StatusCode::TOO_MANY_REQUESTS);

    STATIC_RESP!(InternalServerError, StatusCode::INTERNAL_SERVER_ERROR);
    STATIC_RESP!(NotImplemented, StatusCode::NOT_IMPLEMENTED);
    STATIC_RESP!(BadGateway, StatusCode::BAD_GATEWAY);
    STATIC_RESP!(ServiceUnavailable, StatusCode::SERVICE_UNAVAILABLE);
    STATIC_RESP!(GatewayTimeout, StatusCode::GATEWAY_TIMEOUT);
    STATIC_RESP!(VersionNotSupported, StatusCode::HTTP_VERSION_NOT_SUPPORTED);
    STATIC_RESP!(VariantAlsoNegotiates, StatusCode::VARIANT_ALSO_NEGOTIATES);
    STATIC_RESP!(InsufficientStorage, StatusCode::INSUFFICIENT_STORAGE);
    STATIC_RESP!(LoopDetected, StatusCode::LOOP_DETECTED);
}

#[cfg(test)]
mod tests {
    use crate::body::Body;
    use crate::response::Response;
    use http::StatusCode;

    #[test]
    fn test_build() {
        let resp = Response::Ok().body(Body::Empty);
        assert_eq!(resp.status(), StatusCode::OK);
    }
}
<|endoftext|>


<commit_before>const SK5  : u32 = 0x55555555;
const SK3  : u32 = 0x33333333;
const SKF0 : u32 = 0xF0F0F0F;
const SKFF : u32 = 0xFF00FF;

/**
 * Count the Population of an unsigned integer. Returns how many bits are
 * set to 1.
 *
 * Currently designed for a 32-bit unsigned integer.
 *
 * Many chips have a CTPOP instruction available and would be an order
 * of magnitude speed improvement.
 */
pure fn ctpop32(map : u32) -> u32 {
  let mut Map = copy map;

  Map-=((Map>>1)&SK5);
  Map=(Map&SK3)+((Map>>2)&SK3);
  Map=(Map&SKF0)+((Map>>4)&SKF0);
  Map+=Map>>8;

  return (Map+(Map>>16))&0x3F;
}

#[test]
fn test_ctpop32() {
  assert(ctpop32(0x0) == 0);
  assert(ctpop32(0x1) == 1);
  assert(ctpop32(0x3) == 2);
  assert(ctpop32(0x7) == 3);
  assert(ctpop32(0xF) == 4);
  assert(ctpop32(0x10) == 1);
  assert(ctpop32(0xFF) == 8);
  assert(ctpop32(0xAD) == 5);
  assert(ctpop32(0x2FADBFF) == 21);
  assert(ctpop32(0x82FFFFFF) == 26);
  assert(ctpop32(0x8FFFFFFF) == 29);
  assert(ctpop32(0xFFFFFFFF) == 32);
}<commit_msg>fixing the name of the function in the comment<commit_after>const SK5  : u32 = 0x55555555;
const SK3  : u32 = 0x33333333;
const SKF0 : u32 = 0xF0F0F0F;
const SKFF : u32 = 0xFF00FF;

/**
 * Count the Population of an unsigned integer. Returns how many bits are
 * set to 1.
 *
 * Currently designed for a 32-bit unsigned integer.
 *
 * Many chips have a POPCNT instruction available and would be an order
 * of magnitude speed improvement.
 */
pure fn ctpop32(map : u32) -> u32 {
  let mut Map = copy map;

  Map-=((Map>>1)&SK5);
  Map=(Map&SK3)+((Map>>2)&SK3);
  Map=(Map&SKF0)+((Map>>4)&SKF0);
  Map+=Map>>8;

  return (Map+(Map>>16))&0x3F;
}

#[test]
fn test_ctpop32() {
  assert(ctpop32(0x0) == 0);
  assert(ctpop32(0x1) == 1);
  assert(ctpop32(0x3) == 2);
  assert(ctpop32(0x7) == 3);
  assert(ctpop32(0xF) == 4);
  assert(ctpop32(0x10) == 1);
  assert(ctpop32(0xFF) == 8);
  assert(ctpop32(0xAD) == 5);
  assert(ctpop32(0x2FADBFF) == 21);
  assert(ctpop32(0x82FFFFFF) == 26);
  assert(ctpop32(0x8FFFFFFF) == 29);
  assert(ctpop32(0xFFFFFFFF) == 32);
}<|endoftext|>


<commit_before><commit_msg>Use flatten() to iterate serde meta items<commit_after><|endoftext|>


<commit_before>use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, subst::GenericArgKind};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
use rustc_span::symbol::Ident;
use std::iter;

declare_clippy_lint! {
    /// ### What it does
    /// Detects uses of `Vec::sort_by` passing in a closure
    /// which compares the two arguments, either directly or indirectly.
    ///
    /// ### Why is this bad?
    /// It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if
    /// possible) than to use `Vec::sort_by` and a more complicated
    /// closure.
    ///
    /// ### Known problems
    /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't already
    /// imported by a use statement, then it will need to be added manually.
    ///
    /// ### Example
    /// ```rust
    /// # struct A;
    /// # impl A { fn foo(&self) {} }
    /// # let mut vec: Vec<A> = Vec::new();
    /// vec.sort_by(|a, b| a.foo().cmp(&b.foo()));
    /// ```
    /// Use instead:
    /// ```rust
    /// # struct A;
    /// # impl A { fn foo(&self) {} }
    /// # let mut vec: Vec<A> = Vec::new();
    /// vec.sort_by_key(|a| a.foo());
    /// ```
    pub UNNECESSARY_SORT_BY,
    complexity,
    "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer"
}

declare_lint_pass!(UnnecessarySortBy => [UNNECESSARY_SORT_BY]);

enum LintTrigger {
    Sort(SortDetection),
    SortByKey(SortByKeyDetection),
}

struct SortDetection {
    vec_name: String,
    unstable: bool,
}

struct SortByKeyDetection {
    vec_name: String,
    closure_arg: String,
    closure_body: String,
    reverse: bool,
    unstable: bool,
}

/// Detect if the two expressions are mirrored (identical, except one
/// contains a and the other replaces it with b)
fn mirrored_exprs(
    cx: &LateContext<'_>,
    a_expr: &Expr<'_>,
    a_ident: &Ident,
    b_expr: &Expr<'_>,
    b_ident: &Ident,
) -> bool {
    match (&a_expr.kind, &b_expr.kind) {
        // Two boxes with mirrored contents
        (ExprKind::Box(left_expr), ExprKind::Box(right_expr)) => {
            mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident)
        },
        // Two arrays with mirrored contents
        (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => {
            iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident))
        },
        // The two exprs are function calls.
        // Check to see that the function itself and its arguments are mirrored
        (ExprKind::Call(left_expr, left_args), ExprKind::Call(right_expr, right_args)) => {
            mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident)
                && iter::zip(*left_args, *right_args)
                    .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident))
        },
        // The two exprs are method calls.
        // Check to see that the function is the same and the arguments are mirrored
        // This is enough because the receiver of the method is listed in the arguments
        (
            ExprKind::MethodCall(left_segment, _, left_args, _),
            ExprKind::MethodCall(right_segment, _, right_args, _),
        ) => {
            left_segment.ident == right_segment.ident
                && iter::zip(*left_args, *right_args)
                    .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident))
        },
        // Two tuples with mirrored contents
        (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => {
            iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident))
        },
        // Two binary ops, which are the same operation and which have mirrored arguments
        (ExprKind::Binary(left_op, left_left, left_right), ExprKind::Binary(right_op, right_left, right_right)) => {
            left_op.node == right_op.node
                && mirrored_exprs(cx, left_left, a_ident, right_left, b_ident)
                && mirrored_exprs(cx, left_right, a_ident, right_right, b_ident)
        },
        // Two unary ops, which are the same operation and which have the same argument
        (ExprKind::Unary(left_op, left_expr), ExprKind::Unary(right_op, right_expr)) => {
            left_op == right_op && mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident)
        },
        // The two exprs are literals of some kind
        (ExprKind::Lit(left_lit), ExprKind::Lit(right_lit)) => left_lit.node == right_lit.node,
        (ExprKind::Cast(left, _), ExprKind::Cast(right, _)) => mirrored_exprs(cx, left, a_ident, right, b_ident),
        (ExprKind::DropTemps(left_block), ExprKind::DropTemps(right_block)) => {
            mirrored_exprs(cx, left_block, a_ident, right_block, b_ident)
        },
        (ExprKind::Field(left_expr, left_ident), ExprKind::Field(right_expr, right_ident)) => {
            left_ident.name == right_ident.name && mirrored_exprs(cx, left_expr, a_ident, right_expr, right_ident)
        },
        // Two paths: either one is a and the other is b, or they're identical to each other
        (
            ExprKind::Path(QPath::Resolved(
                _,
                Path {
                    segments: left_segments,
                    ..
                },
            )),
            ExprKind::Path(QPath::Resolved(
                _,
                Path {
                    segments: right_segments,
                    ..
                },
            )),
        ) => {
            (iter::zip(*left_segments, *right_segments).all(|(left, right)| left.ident == right.ident)
                && left_segments
                    .iter()
                    .all(|seg| &seg.ident != a_ident && &seg.ident != b_ident))
                || (left_segments.len() == 1
                    && &left_segments[0].ident == a_ident
                    && right_segments.len() == 1
                    && &right_segments[0].ident == b_ident)
        },
        // Matching expressions, but one or both is borrowed
        (
            ExprKind::AddrOf(left_kind, Mutability::Not, left_expr),
            ExprKind::AddrOf(right_kind, Mutability::Not, right_expr),
        ) => left_kind == right_kind && mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident),
        (_, ExprKind::AddrOf(_, Mutability::Not, right_expr)) => {
            mirrored_exprs(cx, a_expr, a_ident, right_expr, b_ident)
        },
        (ExprKind::AddrOf(_, Mutability::Not, left_expr), _) => mirrored_exprs(cx, left_expr, a_ident, b_expr, b_ident),
        _ => false,
    }
}

fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
    if_chain! {
        if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind;
        if let name = name_ident.ident.name.to_ident_string();
        if name == "sort_by" || name == "sort_unstable_by";
        if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args;
        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym::Vec);
        if let closure_body = cx.tcx.hir().body(*closure_body_id);
        if let &[
            Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
            Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. }
        ] = &closure_body.params;
        if let ExprKind::MethodCall(method_path, _, [ref left_expr, ref right_expr], _) = &closure_body.value.kind;
        if method_path.ident.name == sym::cmp;
        then {
            let (closure_body, closure_arg, reverse) = if mirrored_exprs(
                cx,
                left_expr,
                left_ident,
                right_expr,
                right_ident
            ) {
                (Sugg::hir(cx, left_expr, "..").to_string(), left_ident.name.to_string(), false)
            } else if mirrored_exprs(cx, left_expr, right_ident, right_expr, left_ident) {
                (Sugg::hir(cx, left_expr, "..").to_string(), right_ident.name.to_string(), true)
            } else {
                return None;
            };
            let vec_name = Sugg::hir(cx, &args[0], "..").to_string();
            let unstable = name == "sort_unstable_by";

            if let ExprKind::Path(QPath::Resolved(_, Path {
                segments: [PathSegment { ident: left_name, .. }], ..
            })) = &left_expr.kind {
                if left_name == left_ident {
                    return Some(LintTrigger::Sort(SortDetection { vec_name, unstable }));
                }
            }

            if !expr_borrows(cx, left_expr) {
                return Some(LintTrigger::SortByKey(SortByKeyDetection {
                    vec_name,
                    closure_arg,
                    closure_body,
                    reverse,
                    unstable,
                }));
            }
        }
    }

    None
}

fn expr_borrows(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
    let ty = cx.typeck_results().expr_ty(expr);
    matches!(ty.kind(), ty::Ref(..))
        || ty
            .walk(cx.tcx)
            .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)))
}

impl LateLintPass<'_> for UnnecessarySortBy {
    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
        match detect_lint(cx, expr) {
            Some(LintTrigger::SortByKey(trigger)) => span_lint_and_sugg(
                cx,
                UNNECESSARY_SORT_BY,
                expr.span,
                "use Vec::sort_by_key here instead",
                "try",
                format!(
                    "{}.sort{}_by_key(|{}| {})",
                    trigger.vec_name,
                    if trigger.unstable { "_unstable" } else { "" },
                    trigger.closure_arg,
                    if trigger.reverse {
                        format!("Reverse({})", trigger.closure_body)
                    } else {
                        trigger.closure_body.to_string()
                    },
                ),
                if trigger.reverse {
                    Applicability::MaybeIncorrect
                } else {
                    Applicability::MachineApplicable
                },
            ),
            Some(LintTrigger::Sort(trigger)) => span_lint_and_sugg(
                cx,
                UNNECESSARY_SORT_BY,
                expr.span,
                "use Vec::sort here instead",
                "try",
                format!(
                    "{}.sort{}()",
                    trigger.vec_name,
                    if trigger.unstable { "_unstable" } else { "" },
                ),
                Applicability::MachineApplicable,
            ),
            None => {},
        }
    }
}
<commit_msg>`unnecessary_sort_by` only warns if argument impl `Ord` trait<commit_after>use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, subst::GenericArgKind};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
use rustc_span::symbol::Ident;
use std::iter;

declare_clippy_lint! {
    /// ### What it does
    /// Detects uses of `Vec::sort_by` passing in a closure
    /// which compares the two arguments, either directly or indirectly.
    ///
    /// ### Why is this bad?
    /// It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if
    /// possible) than to use `Vec::sort_by` and a more complicated
    /// closure.
    ///
    /// ### Known problems
    /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't already
    /// imported by a use statement, then it will need to be added manually.
    ///
    /// ### Example
    /// ```rust
    /// # struct A;
    /// # impl A { fn foo(&self) {} }
    /// # let mut vec: Vec<A> = Vec::new();
    /// vec.sort_by(|a, b| a.foo().cmp(&b.foo()));
    /// ```
    /// Use instead:
    /// ```rust
    /// # struct A;
    /// # impl A { fn foo(&self) {} }
    /// # let mut vec: Vec<A> = Vec::new();
    /// vec.sort_by_key(|a| a.foo());
    /// ```
    pub UNNECESSARY_SORT_BY,
    complexity,
    "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer"
}

declare_lint_pass!(UnnecessarySortBy => [UNNECESSARY_SORT_BY]);

enum LintTrigger {
    Sort(SortDetection),
    SortByKey(SortByKeyDetection),
}

struct SortDetection {
    vec_name: String,
    unstable: bool,
}

struct SortByKeyDetection {
    vec_name: String,
    closure_arg: String,
    closure_body: String,
    reverse: bool,
    unstable: bool,
}

/// Detect if the two expressions are mirrored (identical, except one
/// contains a and the other replaces it with b)
fn mirrored_exprs(
    cx: &LateContext<'_>,
    a_expr: &Expr<'_>,
    a_ident: &Ident,
    b_expr: &Expr<'_>,
    b_ident: &Ident,
) -> bool {
    match (&a_expr.kind, &b_expr.kind) {
        // Two boxes with mirrored contents
        (ExprKind::Box(left_expr), ExprKind::Box(right_expr)) => {
            mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident)
        },
        // Two arrays with mirrored contents
        (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => {
            iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident))
        },
        // The two exprs are function calls.
        // Check to see that the function itself and its arguments are mirrored
        (ExprKind::Call(left_expr, left_args), ExprKind::Call(right_expr, right_args)) => {
            mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident)
                && iter::zip(*left_args, *right_args)
                    .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident))
        },
        // The two exprs are method calls.
        // Check to see that the function is the same and the arguments are mirrored
        // This is enough because the receiver of the method is listed in the arguments
        (
            ExprKind::MethodCall(left_segment, _, left_args, _),
            ExprKind::MethodCall(right_segment, _, right_args, _),
        ) => {
            left_segment.ident == right_segment.ident
                && iter::zip(*left_args, *right_args)
                    .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident))
        },
        // Two tuples with mirrored contents
        (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => {
            iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident))
        },
        // Two binary ops, which are the same operation and which have mirrored arguments
        (ExprKind::Binary(left_op, left_left, left_right), ExprKind::Binary(right_op, right_left, right_right)) => {
            left_op.node == right_op.node
                && mirrored_exprs(cx, left_left, a_ident, right_left, b_ident)
                && mirrored_exprs(cx, left_right, a_ident, right_right, b_ident)
        },
        // Two unary ops, which are the same operation and which have the same argument
        (ExprKind::Unary(left_op, left_expr), ExprKind::Unary(right_op, right_expr)) => {
            left_op == right_op && mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident)
        },
        // The two exprs are literals of some kind
        (ExprKind::Lit(left_lit), ExprKind::Lit(right_lit)) => left_lit.node == right_lit.node,
        (ExprKind::Cast(left, _), ExprKind::Cast(right, _)) => mirrored_exprs(cx, left, a_ident, right, b_ident),
        (ExprKind::DropTemps(left_block), ExprKind::DropTemps(right_block)) => {
            mirrored_exprs(cx, left_block, a_ident, right_block, b_ident)
        },
        (ExprKind::Field(left_expr, left_ident), ExprKind::Field(right_expr, right_ident)) => {
            left_ident.name == right_ident.name && mirrored_exprs(cx, left_expr, a_ident, right_expr, right_ident)
        },
        // Two paths: either one is a and the other is b, or they're identical to each other
        (
            ExprKind::Path(QPath::Resolved(
                _,
                Path {
                    segments: left_segments,
                    ..
                },
            )),
            ExprKind::Path(QPath::Resolved(
                _,
                Path {
                    segments: right_segments,
                    ..
                },
            )),
        ) => {
            (iter::zip(*left_segments, *right_segments).all(|(left, right)| left.ident == right.ident)
                && left_segments
                    .iter()
                    .all(|seg| &seg.ident != a_ident && &seg.ident != b_ident))
                || (left_segments.len() == 1
                    && &left_segments[0].ident == a_ident
                    && right_segments.len() == 1
                    && &right_segments[0].ident == b_ident)
        },
        // Matching expressions, but one or both is borrowed
        (
            ExprKind::AddrOf(left_kind, Mutability::Not, left_expr),
            ExprKind::AddrOf(right_kind, Mutability::Not, right_expr),
        ) => left_kind == right_kind && mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident),
        (_, ExprKind::AddrOf(_, Mutability::Not, right_expr)) => {
            mirrored_exprs(cx, a_expr, a_ident, right_expr, b_ident)
        },
        (ExprKind::AddrOf(_, Mutability::Not, left_expr), _) => mirrored_exprs(cx, left_expr, a_ident, b_expr, b_ident),
        _ => false,
    }
}

fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
    if_chain! {
        if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind;
        if let name = name_ident.ident.name.to_ident_string();
        if name == "sort_by" || name == "sort_unstable_by";
        if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args;
        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym::Vec);
        if let closure_body = cx.tcx.hir().body(*closure_body_id);
        if let &[
            Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
            Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. }
        ] = &closure_body.params;
        if let ExprKind::MethodCall(method_path, _, [ref left_expr, ref right_expr], _) = &closure_body.value.kind;
        if method_path.ident.name == sym::cmp;
        then {
            let (closure_body, closure_arg, reverse) = if mirrored_exprs(
                cx,
                left_expr,
                left_ident,
                right_expr,
                right_ident
            ) {
                (Sugg::hir(cx, left_expr, "..").to_string(), left_ident.name.to_string(), false)
            } else if mirrored_exprs(cx, left_expr, right_ident, right_expr, left_ident) {
                (Sugg::hir(cx, left_expr, "..").to_string(), right_ident.name.to_string(), true)
            } else {
                return None;
            };
            let vec_name = Sugg::hir(cx, &args[0], "..").to_string();
            let unstable = name == "sort_unstable_by";

            if_chain! {
            if let ExprKind::Path(QPath::Resolved(_, Path {
                segments: [PathSegment { ident: left_name, .. }], ..
            })) = &left_expr.kind;
            if left_name == left_ident;
            if cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| {
                implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[])
            });
                then {
                    return Some(LintTrigger::Sort(SortDetection { vec_name, unstable }));
                }
            }

            if !expr_borrows(cx, left_expr) {
                return Some(LintTrigger::SortByKey(SortByKeyDetection {
                    vec_name,
                    closure_arg,
                    closure_body,
                    reverse,
                    unstable,
                }));
            }
        }
    }

    None
}

fn expr_borrows(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
    let ty = cx.typeck_results().expr_ty(expr);
    matches!(ty.kind(), ty::Ref(..))
        || ty
            .walk(cx.tcx)
            .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)))
}

impl LateLintPass<'_> for UnnecessarySortBy {
    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
        match detect_lint(cx, expr) {
            Some(LintTrigger::SortByKey(trigger)) => span_lint_and_sugg(
                cx,
                UNNECESSARY_SORT_BY,
                expr.span,
                "use Vec::sort_by_key here instead",
                "try",
                format!(
                    "{}.sort{}_by_key(|{}| {})",
                    trigger.vec_name,
                    if trigger.unstable { "_unstable" } else { "" },
                    trigger.closure_arg,
                    if trigger.reverse {
                        format!("Reverse({})", trigger.closure_body)
                    } else {
                        trigger.closure_body.to_string()
                    },
                ),
                if trigger.reverse {
                    Applicability::MaybeIncorrect
                } else {
                    Applicability::MachineApplicable
                },
            ),
            Some(LintTrigger::Sort(trigger)) => span_lint_and_sugg(
                cx,
                UNNECESSARY_SORT_BY,
                expr.span,
                "use Vec::sort here instead",
                "try",
                format!(
                    "{}.sort{}()",
                    trigger.vec_name,
                    if trigger.unstable { "_unstable" } else { "" },
                ),
                Applicability::MachineApplicable,
            ),
            None => {},
        }
    }
}
<|endoftext|>


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

use std::sync::atomic::spin_loop_hint;
use thread_parker;

// Wastes some CPU time for the given number of iterations,
// using a hint to indicate to the CPU that we are spinning.
#[inline]
fn cpu_relax(iterations: u32) {
    for _ in 0..iterations {
        spin_loop_hint()
    }
}

/// A counter used to perform exponential backoff in spin loops.
pub struct SpinWait {
    counter: u32,
}

impl SpinWait {
    /// Creates a new `SpinWait`.
    #[inline]
    pub fn new() -> SpinWait {
        SpinWait { counter: 0 }
    }

    /// Resets a `SpinWait` to its initial state.
    #[inline]
    pub fn reset(&mut self) {
        self.counter = 0;
    }

    /// Spins until the sleep threshold has been reached.
    ///
    /// This function returns whether the sleep threshold has been reached, at
    /// which point further spinning has diminishing returns and the thread
    /// should be parked instead.
    ///
    /// The spin strategy will initially use a CPU-bound loop but will fall back
    /// to yielding the CPU to the OS after a few iterations.
    #[inline]
    pub fn spin(&mut self) -> bool {
        if self.counter >= 10 {
            return false;
        }
        self.counter += 1;
        if self.counter <= 3 {
            cpu_relax(1 << self.counter);
        } else {
            thread_parker::thread_yield();
        }
        true
    }

    /// Spins without yielding the thread to the OS.
    ///
    /// Instead, the backoff is simply capped at a maximum value. This can be
    /// used to improve throughput in `compare_exchange` loops that have high
    /// contention.
    #[inline]
    pub fn spin_no_yield(&mut self) {
        self.counter += 1;
        if self.counter > 10 {
            self.counter = 10;
        }
        cpu_relax(1 << self.counter);
    }
}

impl Default for SpinWait {
    #[inline]
    fn default() -> SpinWait {
        SpinWait::new()
    }
}
<commit_msg>Use #[derive(Default)] on SpinWait<commit_after>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use std::sync::atomic::spin_loop_hint;
use thread_parker;

// Wastes some CPU time for the given number of iterations,
// using a hint to indicate to the CPU that we are spinning.
#[inline]
fn cpu_relax(iterations: u32) {
    for _ in 0..iterations {
        spin_loop_hint()
    }
}

/// A counter used to perform exponential backoff in spin loops.
#[derive(Default)]
pub struct SpinWait {
    counter: u32,
}

impl SpinWait {
    /// Creates a new `SpinWait`.
    #[inline]
    pub fn new() -> Self {
        Self::default()
    }

    /// Resets a `SpinWait` to its initial state.
    #[inline]
    pub fn reset(&mut self) {
        self.counter = 0;
    }

    /// Spins until the sleep threshold has been reached.
    ///
    /// This function returns whether the sleep threshold has been reached, at
    /// which point further spinning has diminishing returns and the thread
    /// should be parked instead.
    ///
    /// The spin strategy will initially use a CPU-bound loop but will fall back
    /// to yielding the CPU to the OS after a few iterations.
    #[inline]
    pub fn spin(&mut self) -> bool {
        if self.counter >= 10 {
            return false;
        }
        self.counter += 1;
        if self.counter <= 3 {
            cpu_relax(1 << self.counter);
        } else {
            thread_parker::thread_yield();
        }
        true
    }

    /// Spins without yielding the thread to the OS.
    ///
    /// Instead, the backoff is simply capped at a maximum value. This can be
    /// used to improve throughput in `compare_exchange` loops that have high
    /// contention.
    #[inline]
    pub fn spin_no_yield(&mut self) {
        self.counter += 1;
        if self.counter > 10 {
            self.counter = 10;
        }
        cpu_relax(1 << self.counter);
    }
}
<|endoftext|>


<commit_before>use rustc_hir::def_id::{CrateNum, LocalDefId, LOCAL_CRATE};

use crate::TyCtxt;
use super::wfcheck;
use crate::check::CheckItemTypesVisitor;

pub fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
    tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx });
}

pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
    wfcheck::check_item_well_formed(tcx, def_id);
}

pub fn check_trait_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
    wfcheck::check_trait_item(tcx, def_id);
}

pub fn check_impl_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
    wfcheck::check_impl_item(tcx, def_id);
}

pub fn typeck_item_bodies(tcx: TyCtxt<'_>, crate_num: CrateNum) {
    debug_assert!(crate_num == LOCAL_CRATE);
    tcx.par_body_owners(|body_owner_def_id| {
        tcx.ensure().typeck(body_owner_def_id);
    });
}
<commit_msg>Formatter moved one use statement<commit_after>use rustc_hir::def_id::{CrateNum, LocalDefId, LOCAL_CRATE};

use super::wfcheck;
use crate::check::CheckItemTypesVisitor;
use crate::TyCtxt;

pub fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
    tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx });
}

pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
    wfcheck::check_item_well_formed(tcx, def_id);
}

pub fn check_trait_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
    wfcheck::check_trait_item(tcx, def_id);
}

pub fn check_impl_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
    wfcheck::check_impl_item(tcx, def_id);
}

pub fn typeck_item_bodies(tcx: TyCtxt<'_>, crate_num: CrateNum) {
    debug_assert!(crate_num == LOCAL_CRATE);
    tcx.par_body_owners(|body_owner_def_id| {
        tcx.ensure().typeck(body_owner_def_id);
    });
}
<|endoftext|>