<commit_before>use model::*;
use serde::de::{Deserialize, Error as DeError, MapAccess, Visitor};
use std::error::Error as StdError;
use std::fmt::{Display, Formatter, Result as FmtResult, Write as FmtWrite};
use std::str::FromStr;
use internal::prelude::*;

#[cfg(all(feature = "cache", feature = "model"))]
use CACHE;
#[cfg(feature = "model")]
use http;

/// An emoji reaction to a message.
#[derive(Clone, Debug, Deserialize)]
pub struct Reaction {
    /// The [`Channel`] of the associated [`Message`].
    ///
    /// [`Channel`]: enum.Channel.html
    /// [`Message`]: struct.Message.html
    pub channel_id: ChannelId,
    /// The reactive emoji used.
    pub emoji: ReactionType,
    /// The Id of the [`Message`] that was reacted to.
    ///
    /// [`Message`]: struct.Message.html
    pub message_id: MessageId,
    /// The Id of the [`User`] that sent the reaction.
    ///
    /// [`User`]: struct.User.html
    pub user_id: UserId,
}

#[cfg(feature = "model")]
impl Reaction {
    /// Deletes the reaction, but only if the current user is the user who made
    /// the reaction or has permission to.
    ///
    /// Requires the [Manage Messages] permission, _if_ the current
    /// user did not perform the reaction.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, then returns a
    /// [`ModelError::InvalidPermissions`] if the current user does not have
    /// the required [permissions].
    ///
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
    /// [permissions]: permissions
    pub fn delete(&self) -> Result<()> {
        let user_id = feature_cache! {
            {
                let user = if self.user_id == CACHE.read().user.id {
                    None
                } else {
                    Some(self.user_id.0)
                };

                // If the reaction is one _not_ made by the current user, then ensure
                // that the current user has permission* to delete the reaction.
                //
                // Normally, users can only delete their own reactions.
                //
                // * The `Manage Messages` permission.
                if user.is_some() {
                    let req = Permissions::MANAGE_MESSAGES;

                    if !utils::user_has_perms(self.channel_id, req).unwrap_or(true) {
                        return Err(Error::Model(ModelError::InvalidPermissions(req)));
                    }
                }

                user
            } else {
                Some(self.user_id.0)
            }
        };

        http::delete_reaction(self.channel_id.0, self.message_id.0, user_id, &self.emoji)
    }

    /// Retrieves the list of [`User`]s who have reacted to a [`Message`] with a
    /// certain [`Emoji`].
    ///
    /// The default `limit` is `50` - specify otherwise to receive a different
    /// maximum number of users. The maximum that may be retrieve at a time is
    /// `100`, if a greater number is provided then it is automatically reduced.
    ///
    /// The optional `after` attribute is to retrieve the users after a certain
    /// user. This is useful for pagination.
    ///
    /// Requires the [Read Message History] permission.
    ///
    /// **Note**: This will send a request to the REST API.
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::InvalidPermissions`] if the current user does
    /// not have the required [permissions].
    ///
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [`Emoji`]: struct.Emoji.html
    /// [`Message`]: struct.Message.html
    /// [`User`]: struct.User.html
    /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
    /// [permissions]: permissions
    pub fn users<R, U>(&self,
                       reaction_type: R,
                       limit: Option<u8>,
                       after: Option<U>)
                       -> Result<Vec<User>>
        where R: Into<ReactionType>, U: Into<UserId> {
        http::get_reaction_users(
            self.channel_id.0,
            self.message_id.0,
            &reaction_type.into(),
            limit.unwrap_or(50),
            after.map(|u| u.into().0),
        )
    }

    /// Retrieves the [`Message`] associated with this reaction.
    ///
    /// Requires the [Read Message History] permission.
    ///
    /// **Note**: This will send a request to the REST API. Prefer maintaining
    /// your own message cache or otherwise having the message available if
    /// possible.
    ///
    /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
    /// [`Message`]: struct.Message.html
    pub fn message(&self) -> Result<Message> {
        self.channel_id.message(self.message_id)
    }
}

/// The type of a [`Reaction`] sent.
///
/// [`Reaction`]: struct.Reaction.html
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum ReactionType {
    /// A reaction with a [`Guild`]s custom [`Emoji`], which is unique to the
    /// guild.
    ///
    /// [`Emoji`]: struct.Emoji.html
    /// [`Guild`]: struct.Guild.html
    Custom {
        /// The Id of the custom [`Emoji`].
        ///
        /// [`Emoji`]: struct.Emoji.html
        id: EmojiId,
        /// The name of the custom emoji. This is primarily used for decoration
        /// and distinguishing the emoji client-side.
        name: Option<String>,
    },
    /// A reaction with a twemoji.
    Unicode(String),
}

impl<'de> Deserialize<'de> for ReactionType {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
        #[derive(Deserialize)]
        #[serde(field_identifier, rename_all = "snake_case")]
        enum Field {
            Id,
            Name,
        }

        struct ReactionTypeVisitor;

        impl<'de> Visitor<'de> for ReactionTypeVisitor {
            type Value = ReactionType;

            fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
                formatter.write_str("enum ReactionType")
            }

            fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> StdResult<Self::Value, V::Error> {
                let mut id = None;
                let mut name = None;

                while let Some(key) = map.next_key()? {
                    match key {
                        Field::Id => {
                            if id.is_some() {
                                return Err(DeError::duplicate_field("id"));
                            }

                            if let Ok(emoji_id) = map.next_value::<EmojiId>() {
                                id = Some(emoji_id)
                            }
                        },
                        Field::Name => {
                            if name.is_some() {
                                return Err(DeError::duplicate_field("name"));
                            }

                            name = Some(map.next_value()?);
                        },
                    }
                }

                let name = name.ok_or_else(|| DeError::missing_field("name"))?;

                Ok(if let Some(id) = id {
                    ReactionType::Custom {
                        id: id,
                        name: name,
                    }
                } else {
                    ReactionType::Unicode(name.unwrap())
                })
            }
        }

        deserializer.deserialize_map(ReactionTypeVisitor)
    }
}

#[cfg(any(feature = "model", feature = "http"))]
impl ReactionType {
    /// Creates a data-esque display of the type. This is not very useful for
    /// displaying, as the primary client can not render it, but can be useful
    /// for debugging.
    ///
    /// **Note**: This is mainly for use internally. There is otherwise most
    /// likely little use for it.
    pub fn as_data(&self) -> String {
        match *self {
            ReactionType::Custom {
                id,
                ref name,
            } => format!("{}:{}", name.as_ref().map_or("", |s| s.as_str()), id),
            ReactionType::Unicode(ref unicode) => unicode.clone(),
        }
    }
}

#[cfg(feature = "model")]
impl From<char> for ReactionType {
    /// Creates a `ReactionType` from a `char`.
    ///
    /// # Examples
    ///
    /// Reacting to a message with an apple:
    ///
    /// ```rust,no_run
    /// # use serenity::model::ChannelId;
    /// # use std::error::Error;
    /// #
    /// # fn try_main() -> Result<(), Box<Error>> {
    /// #     let message = ChannelId(0).message(0)?;
    /// #
    /// message.react('🍎')?;
    /// #     Ok(())
    /// # }
    /// #
    /// # fn main() {
    /// #     try_main().unwrap();
    /// # }
    /// ```
    fn from(ch: char) -> ReactionType { ReactionType::Unicode(ch.to_string()) }
}

impl From<Emoji> for ReactionType {
    fn from(emoji: Emoji) -> ReactionType {
        ReactionType::Custom {
            id: emoji.id,
            name: Some(emoji.name),
        }
    }
}

impl From<EmojiId> for ReactionType {
    fn from(emoji_id: EmojiId) -> ReactionType {
        ReactionType::Custom {
            id: emoji_id,
            name: None
        }
    }
}

impl From<EmojiIdentifier> for ReactionType {
    fn from(emoji_id: EmojiIdentifier) -> ReactionType {
        ReactionType::Custom {
            id: emoji_id.id,
            name: Some(emoji_id.name)
        }
    }
}

impl From<String> for ReactionType {
    fn from(unicode: String) -> ReactionType { ReactionType::Unicode(unicode) }
}

impl<'a> From<&'a str> for ReactionType {
    /// Creates a `ReactionType` from a string slice.
    ///
    /// # Examples
    ///
    /// Creating a `ReactionType` from a `🍎`, modeling a similar API as the
    /// rest of the library:
    ///
    /// ```rust
    /// use serenity::model::ReactionType;
    ///
    /// fn foo<R: Into<ReactionType>>(bar: R) {
    ///     println!("{:?}", bar.into());
    /// }
    ///
    /// foo("🍎");
    /// ```
    fn from(unicode: &str) -> ReactionType { ReactionType::Unicode(unicode.to_string()) }
}

// TODO: Change this to `!` once it becomes stable.

#[derive(Debug)]
pub enum NeverFails {}

impl Display for NeverFails {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "never fails")
    }
}

impl StdError for NeverFails {
    fn description(&self) -> &str {
        "never fails"
    }
}

impl FromStr for ReactionType {
    type Err = NeverFails;

    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
        Ok(ReactionType::from(s))
    }
}

impl Display for ReactionType {
    /// Formats the reaction type, displaying the associated emoji in a
    /// way that clients can understand.
    ///
    /// If the type is a [custom][`ReactionType::Custom`] emoji, then refer to
    /// the documentation for [emoji's formatter][`Emoji::fmt`] on how this is
    /// displayed. Otherwise, if the type is a
    /// [unicode][`ReactionType::Unicode`], then the inner unicode is displayed.
    ///
    /// [`Emoji::fmt`]: struct.Emoji.html#method.fmt
    /// [`ReactionType::Custom`]: enum.ReactionType.html#variant.Custom
    /// [`ReactionType::Unicode`]: enum.ReactionType.html#variant.Unicode
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match *self {
            ReactionType::Custom {
                id,
                ref name,
            } => {
                f.write_char('<')?;
                f.write_char(':')?;
                f.write_str(name.as_ref().map_or("", |s| s.as_str()))?;
                f.write_char(':')?;
                Display::fmt(&id, f)?;
                f.write_char('>')
            },
            ReactionType::Unicode(ref unicode) => f.write_str(unicode),
        }
    }
}
<commit_msg>Alphabetize Reaction methods<commit_after>use model::*;
use serde::de::{Deserialize, Error as DeError, MapAccess, Visitor};
use std::error::Error as StdError;
use std::fmt::{Display, Formatter, Result as FmtResult, Write as FmtWrite};
use std::str::FromStr;
use internal::prelude::*;

#[cfg(all(feature = "cache", feature = "model"))]
use CACHE;
#[cfg(feature = "model")]
use http;

/// An emoji reaction to a message.
#[derive(Clone, Debug, Deserialize)]
pub struct Reaction {
    /// The [`Channel`] of the associated [`Message`].
    ///
    /// [`Channel`]: enum.Channel.html
    /// [`Message`]: struct.Message.html
    pub channel_id: ChannelId,
    /// The reactive emoji used.
    pub emoji: ReactionType,
    /// The Id of the [`Message`] that was reacted to.
    ///
    /// [`Message`]: struct.Message.html
    pub message_id: MessageId,
    /// The Id of the [`User`] that sent the reaction.
    ///
    /// [`User`]: struct.User.html
    pub user_id: UserId,
}

#[cfg(feature = "model")]
impl Reaction {
    /// Deletes the reaction, but only if the current user is the user who made
    /// the reaction or has permission to.
    ///
    /// Requires the [Manage Messages] permission, _if_ the current
    /// user did not perform the reaction.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, then returns a
    /// [`ModelError::InvalidPermissions`] if the current user does not have
    /// the required [permissions].
    ///
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
    /// [permissions]: permissions
    pub fn delete(&self) -> Result<()> {
        let user_id = feature_cache! {
            {
                let user = if self.user_id == CACHE.read().user.id {
                    None
                } else {
                    Some(self.user_id.0)
                };

                // If the reaction is one _not_ made by the current user, then ensure
                // that the current user has permission* to delete the reaction.
                //
                // Normally, users can only delete their own reactions.
                //
                // * The `Manage Messages` permission.
                if user.is_some() {
                    let req = Permissions::MANAGE_MESSAGES;

                    if !utils::user_has_perms(self.channel_id, req).unwrap_or(true) {
                        return Err(Error::Model(ModelError::InvalidPermissions(req)));
                    }
                }

                user
            } else {
                Some(self.user_id.0)
            }
        };

        http::delete_reaction(self.channel_id.0, self.message_id.0, user_id, &self.emoji)
    }

    /// Retrieves the [`Message`] associated with this reaction.
    ///
    /// Requires the [Read Message History] permission.
    ///
    /// **Note**: This will send a request to the REST API. Prefer maintaining
    /// your own message cache or otherwise having the message available if
    /// possible.
    ///
    /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
    /// [`Message`]: struct.Message.html
    pub fn message(&self) -> Result<Message> {
        self.channel_id.message(self.message_id)
    }

    /// Retrieves the list of [`User`]s who have reacted to a [`Message`] with a
    /// certain [`Emoji`].
    ///
    /// The default `limit` is `50` - specify otherwise to receive a different
    /// maximum number of users. The maximum that may be retrieve at a time is
    /// `100`, if a greater number is provided then it is automatically reduced.
    ///
    /// The optional `after` attribute is to retrieve the users after a certain
    /// user. This is useful for pagination.
    ///
    /// Requires the [Read Message History] permission.
    ///
    /// **Note**: This will send a request to the REST API.
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::InvalidPermissions`] if the current user does
    /// not have the required [permissions].
    ///
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [`Emoji`]: struct.Emoji.html
    /// [`Message`]: struct.Message.html
    /// [`User`]: struct.User.html
    /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
    /// [permissions]: permissions
    pub fn users<R, U>(&self,
                       reaction_type: R,
                       limit: Option<u8>,
                       after: Option<U>)
                       -> Result<Vec<User>>
        where R: Into<ReactionType>, U: Into<UserId> {
        http::get_reaction_users(
            self.channel_id.0,
            self.message_id.0,
            &reaction_type.into(),
            limit.unwrap_or(50),
            after.map(|u| u.into().0),
        )
    }
}

/// The type of a [`Reaction`] sent.
///
/// [`Reaction`]: struct.Reaction.html
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum ReactionType {
    /// A reaction with a [`Guild`]s custom [`Emoji`], which is unique to the
    /// guild.
    ///
    /// [`Emoji`]: struct.Emoji.html
    /// [`Guild`]: struct.Guild.html
    Custom {
        /// The Id of the custom [`Emoji`].
        ///
        /// [`Emoji`]: struct.Emoji.html
        id: EmojiId,
        /// The name of the custom emoji. This is primarily used for decoration
        /// and distinguishing the emoji client-side.
        name: Option<String>,
    },
    /// A reaction with a twemoji.
    Unicode(String),
}

impl<'de> Deserialize<'de> for ReactionType {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
        #[derive(Deserialize)]
        #[serde(field_identifier, rename_all = "snake_case")]
        enum Field {
            Id,
            Name,
        }

        struct ReactionTypeVisitor;

        impl<'de> Visitor<'de> for ReactionTypeVisitor {
            type Value = ReactionType;

            fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
                formatter.write_str("enum ReactionType")
            }

            fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> StdResult<Self::Value, V::Error> {
                let mut id = None;
                let mut name = None;

                while let Some(key) = map.next_key()? {
                    match key {
                        Field::Id => {
                            if id.is_some() {
                                return Err(DeError::duplicate_field("id"));
                            }

                            if let Ok(emoji_id) = map.next_value::<EmojiId>() {
                                id = Some(emoji_id)
                            }
                        },
                        Field::Name => {
                            if name.is_some() {
                                return Err(DeError::duplicate_field("name"));
                            }

                            name = Some(map.next_value()?);
                        },
                    }
                }

                let name = name.ok_or_else(|| DeError::missing_field("name"))?;

                Ok(if let Some(id) = id {
                    ReactionType::Custom {
                        id: id,
                        name: name,
                    }
                } else {
                    ReactionType::Unicode(name.unwrap())
                })
            }
        }

        deserializer.deserialize_map(ReactionTypeVisitor)
    }
}

#[cfg(any(feature = "model", feature = "http"))]
impl ReactionType {
    /// Creates a data-esque display of the type. This is not very useful for
    /// displaying, as the primary client can not render it, but can be useful
    /// for debugging.
    ///
    /// **Note**: This is mainly for use internally. There is otherwise most
    /// likely little use for it.
    pub fn as_data(&self) -> String {
        match *self {
            ReactionType::Custom {
                id,
                ref name,
            } => format!("{}:{}", name.as_ref().map_or("", |s| s.as_str()), id),
            ReactionType::Unicode(ref unicode) => unicode.clone(),
        }
    }
}

#[cfg(feature = "model")]
impl From<char> for ReactionType {
    /// Creates a `ReactionType` from a `char`.
    ///
    /// # Examples
    ///
    /// Reacting to a message with an apple:
    ///
    /// ```rust,no_run
    /// # use serenity::model::ChannelId;
    /// # use std::error::Error;
    /// #
    /// # fn try_main() -> Result<(), Box<Error>> {
    /// #     let message = ChannelId(0).message(0)?;
    /// #
    /// message.react('🍎')?;
    /// #     Ok(())
    /// # }
    /// #
    /// # fn main() {
    /// #     try_main().unwrap();
    /// # }
    /// ```
    fn from(ch: char) -> ReactionType { ReactionType::Unicode(ch.to_string()) }
}

impl From<Emoji> for ReactionType {
    fn from(emoji: Emoji) -> ReactionType {
        ReactionType::Custom {
            id: emoji.id,
            name: Some(emoji.name),
        }
    }
}

impl From<EmojiId> for ReactionType {
    fn from(emoji_id: EmojiId) -> ReactionType {
        ReactionType::Custom {
            id: emoji_id,
            name: None
        }
    }
}

impl From<EmojiIdentifier> for ReactionType {
    fn from(emoji_id: EmojiIdentifier) -> ReactionType {
        ReactionType::Custom {
            id: emoji_id.id,
            name: Some(emoji_id.name)
        }
    }
}

impl From<String> for ReactionType {
    fn from(unicode: String) -> ReactionType { ReactionType::Unicode(unicode) }
}

impl<'a> From<&'a str> for ReactionType {
    /// Creates a `ReactionType` from a string slice.
    ///
    /// # Examples
    ///
    /// Creating a `ReactionType` from a `🍎`, modeling a similar API as the
    /// rest of the library:
    ///
    /// ```rust
    /// use serenity::model::ReactionType;
    ///
    /// fn foo<R: Into<ReactionType>>(bar: R) {
    ///     println!("{:?}", bar.into());
    /// }
    ///
    /// foo("🍎");
    /// ```
    fn from(unicode: &str) -> ReactionType { ReactionType::Unicode(unicode.to_string()) }
}

// TODO: Change this to `!` once it becomes stable.

#[derive(Debug)]
pub enum NeverFails {}

impl Display for NeverFails {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "never fails")
    }
}

impl StdError for NeverFails {
    fn description(&self) -> &str {
        "never fails"
    }
}

impl FromStr for ReactionType {
    type Err = NeverFails;

    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
        Ok(ReactionType::from(s))
    }
}

impl Display for ReactionType {
    /// Formats the reaction type, displaying the associated emoji in a
    /// way that clients can understand.
    ///
    /// If the type is a [custom][`ReactionType::Custom`] emoji, then refer to
    /// the documentation for [emoji's formatter][`Emoji::fmt`] on how this is
    /// displayed. Otherwise, if the type is a
    /// [unicode][`ReactionType::Unicode`], then the inner unicode is displayed.
    ///
    /// [`Emoji::fmt`]: struct.Emoji.html#method.fmt
    /// [`ReactionType::Custom`]: enum.ReactionType.html#variant.Custom
    /// [`ReactionType::Unicode`]: enum.ReactionType.html#variant.Unicode
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match *self {
            ReactionType::Custom {
                id,
                ref name,
            } => {
                f.write_char('<')?;
                f.write_char(':')?;
                f.write_str(name.as_ref().map_or("", |s| s.as_str()))?;
                f.write_char(':')?;
                Display::fmt(&id, f)?;
                f.write_char('>')
            },
            ReactionType::Unicode(ref unicode) => f.write_str(unicode),
        }
    }
}
<|endoftext|>


<commit_before>//! This module provides the [CommentWriter] which makes it possible
//! to add comments to the written cranelift ir.
//!
//! # Example
//!
//! ```clif
//! test compile
//! target x86_64
//!
//! function u0:0(i64, i64, i64) system_v {
//! ; symbol _ZN119_$LT$example..IsNotEmpty$u20$as$u20$mini_core..FnOnce$LT$$LP$$RF$$u27$a$u20$$RF$$u27$b$u20$$u5b$u16$u5d$$C$$RP$$GT$$GT$9call_once17he85059d5e6a760a0E
//! ; instance Instance { def: Item(DefId(0/0:29 ~ example[8787]::{{impl}}[0]::call_once[0])), substs: [ReErased, ReErased] }
//! ; sig ([IsNotEmpty, (&&[u16],)]; c_variadic: false)->(u8, u8)
//!
//! ; ssa {_2: NOT_SSA, _4: NOT_SSA, _0: NOT_SSA, _3: (empty), _1: NOT_SSA}
//! ; msg   loc.idx    param    pass mode            ssa flags  ty
//! ; ret    _0      = v0       ByRef                NOT_SSA    (u8, u8)
//! ; arg    _1      = v1       ByRef                NOT_SSA    IsNotEmpty
//! ; arg    _2.0    = v2       ByVal(types::I64)    NOT_SSA    &&[u16]
//!
//!     ss0 = explicit_slot 0 ; _1: IsNotEmpty size=0 align=1,8
//!     ss1 = explicit_slot 8 ; _2: (&&[u16],) size=8 align=8,8
//!     ss2 = explicit_slot 8 ; _4: (&&[u16],) size=8 align=8,8
//!     sig0 = (i64, i64, i64) system_v
//!     sig1 = (i64, i64, i64) system_v
//!     fn0 = colocated u0:6 sig1 ; Instance { def: Item(DefId(0/0:31 ~ example[8787]::{{impl}}[1]::call_mut[0])), substs: [ReErased, ReErased] }
//!
//! block0(v0: i64, v1: i64, v2: i64):
//!     v3 = stack_addr.i64 ss0
//!     v4 = stack_addr.i64 ss1
//!     store v2, v4
//!     v5 = stack_addr.i64 ss2
//!     jump block1
//!
//! block1:
//!     nop
//! ; _3 = &mut _1
//! ; _4 = _2
//!     v6 = load.i64 v4
//!     store v6, v5
//! ;
//! ; _0 = const mini_core::FnMut::call_mut(move _3, move _4)
//!     v7 = load.i64 v5
//!     call fn0(v0, v3, v7)
//!     jump block2
//!
//! block2:
//!     nop
//! ;
//! ; return
//!     return
//! }
//! ```

use std::fmt;
use std::io::Write;

use cranelift_codegen::{
    entity::SecondaryMap,
    ir::{entities::AnyEntity, function::DisplayFunctionAnnotations},
    write::{FuncWriter, PlainWriter},
};

use rustc_middle::ty::layout::FnAbiExt;
use rustc_session::config::OutputType;
use rustc_target::abi::call::FnAbi;

use crate::prelude::*;

#[derive(Debug)]
pub(crate) struct CommentWriter {
    enabled: bool,
    global_comments: Vec<String>,
    entity_comments: FxHashMap<AnyEntity, String>,
}

impl CommentWriter {
    pub(crate) fn new<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self {
        let enabled = should_write_ir(tcx);
        let global_comments = if enabled {
            vec![
                format!("symbol {}", tcx.symbol_name(instance).name),
                format!("instance {:?}", instance),
                format!("abi {:?}", FnAbi::of_instance(&RevealAllLayoutCx(tcx), instance, &[])),
                String::new(),
            ]
        } else {
            vec![]
        };

        CommentWriter { enabled, global_comments, entity_comments: FxHashMap::default() }
    }
}

impl CommentWriter {
    pub(crate) fn enabled(&self) -> bool {
        self.enabled
    }

    pub(crate) fn add_global_comment<S: Into<String>>(&mut self, comment: S) {
        debug_assert!(self.enabled);
        self.global_comments.push(comment.into());
    }

    pub(crate) fn add_comment<S: Into<String> + AsRef<str>, E: Into<AnyEntity>>(
        &mut self,
        entity: E,
        comment: S,
    ) {
        debug_assert!(self.enabled);

        use std::collections::hash_map::Entry;
        match self.entity_comments.entry(entity.into()) {
            Entry::Occupied(mut occ) => {
                occ.get_mut().push('\n');
                occ.get_mut().push_str(comment.as_ref());
            }
            Entry::Vacant(vac) => {
                vac.insert(comment.into());
            }
        }
    }
}

impl FuncWriter for &'_ CommentWriter {
    fn write_preamble(
        &mut self,
        w: &mut dyn fmt::Write,
        func: &Function,
        reg_info: Option<&isa::RegInfo>,
    ) -> Result<bool, fmt::Error> {
        for comment in &self.global_comments {
            if !comment.is_empty() {
                writeln!(w, "; {}", comment)?;
            } else {
                writeln!(w)?;
            }
        }
        if !self.global_comments.is_empty() {
            writeln!(w)?;
        }

        self.super_preamble(w, func, reg_info)
    }

    fn write_entity_definition(
        &mut self,
        w: &mut dyn fmt::Write,
        _func: &Function,
        entity: AnyEntity,
        value: &dyn fmt::Display,
    ) -> fmt::Result {
        write!(w, "    {} = {}", entity, value)?;

        if let Some(comment) = self.entity_comments.get(&entity) {
            writeln!(w, " ; {}", comment.replace('\n', "\n; "))
        } else {
            writeln!(w)
        }
    }

    fn write_block_header(
        &mut self,
        w: &mut dyn fmt::Write,
        func: &Function,
        isa: Option<&dyn isa::TargetIsa>,
        block: Block,
        indent: usize,
    ) -> fmt::Result {
        PlainWriter.write_block_header(w, func, isa, block, indent)
    }

    fn write_instruction(
        &mut self,
        w: &mut dyn fmt::Write,
        func: &Function,
        aliases: &SecondaryMap<Value, Vec<Value>>,
        isa: Option<&dyn isa::TargetIsa>,
        inst: Inst,
        indent: usize,
    ) -> fmt::Result {
        PlainWriter.write_instruction(w, func, aliases, isa, inst, indent)?;
        if let Some(comment) = self.entity_comments.get(&inst.into()) {
            writeln!(w, "; {}", comment.replace('\n', "\n; "))?;
        }
        Ok(())
    }
}

impl FunctionCx<'_, '_, '_> {
    pub(crate) fn add_global_comment<S: Into<String>>(&mut self, comment: S) {
        self.clif_comments.add_global_comment(comment);
    }

    pub(crate) fn add_comment<S: Into<String> + AsRef<str>, E: Into<AnyEntity>>(
        &mut self,
        entity: E,
        comment: S,
    ) {
        self.clif_comments.add_comment(entity, comment);
    }
}

pub(crate) fn should_write_ir(tcx: TyCtxt<'_>) -> bool {
    tcx.sess.opts.output_types.contains_key(&OutputType::LlvmAssembly)
}

pub(crate) fn write_ir_file(
    tcx: TyCtxt<'_>,
    name: impl FnOnce() -> String,
    write: impl FnOnce(&mut dyn Write) -> std::io::Result<()>,
) {
    if !should_write_ir(tcx) {
        return;
    }

    let clif_output_dir = tcx.output_filenames(()).with_extension("clif");

    match std::fs::create_dir(&clif_output_dir) {
        Ok(()) => {}
        Err(err) if err.kind() == std::io::ErrorKind::AlreadyExists => {}
        res @ Err(_) => res.unwrap(),
    }

    let clif_file_name = clif_output_dir.join(name());

    let res = std::fs::File::create(clif_file_name).and_then(|mut file| write(&mut file));
    if let Err(err) = res {
        tcx.sess.warn(&format!("error writing ir file: {}", err));
    }
}

pub(crate) fn write_clif_file<'tcx>(
    tcx: TyCtxt<'tcx>,
    postfix: &str,
    isa: &dyn cranelift_codegen::isa::TargetIsa,
    instance: Instance<'tcx>,
    context: &cranelift_codegen::Context,
    mut clif_comments: &CommentWriter,
) {
    write_ir_file(
        tcx,
        || format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix),
        |file| {
            let mut clif = String::new();
            cranelift_codegen::write::decorate_function(
                &mut clif_comments,
                &mut clif,
                &context.func,
                &DisplayFunctionAnnotations { isa: Some(isa), value_ranges: None },
            )
            .unwrap();

            writeln!(file, "test compile")?;
            writeln!(file, "set is_pic")?;
            writeln!(file, "set enable_simd")?;
            writeln!(file, "target {} nehalem", crate::target_triple(tcx.sess))?;
            writeln!(file)?;
            file.write_all(clif.as_bytes())?;
            Ok(())
        },
    );
}

impl fmt::Debug for FunctionCx<'_, '_, '_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        writeln!(f, "{:?}", self.instance.substs)?;
        writeln!(f, "{:?}", self.local_map)?;

        let mut clif = String::new();
        ::cranelift_codegen::write::decorate_function(
            &mut &self.clif_comments,
            &mut clif,
            &self.bcx.func,
            &DisplayFunctionAnnotations::default(),
        )
        .unwrap();
        writeln!(f, "\n{}", clif)
    }
}
<commit_msg>Write better clif ir header<commit_after>//! This module provides the [CommentWriter] which makes it possible
//! to add comments to the written cranelift ir.
//!
//! # Example
//!
//! ```clif
//! test compile
//! target x86_64
//!
//! function u0:0(i64, i64, i64) system_v {
//! ; symbol _ZN119_$LT$example..IsNotEmpty$u20$as$u20$mini_core..FnOnce$LT$$LP$$RF$$u27$a$u20$$RF$$u27$b$u20$$u5b$u16$u5d$$C$$RP$$GT$$GT$9call_once17he85059d5e6a760a0E
//! ; instance Instance { def: Item(DefId(0/0:29 ~ example[8787]::{{impl}}[0]::call_once[0])), substs: [ReErased, ReErased] }
//! ; sig ([IsNotEmpty, (&&[u16],)]; c_variadic: false)->(u8, u8)
//!
//! ; ssa {_2: NOT_SSA, _4: NOT_SSA, _0: NOT_SSA, _3: (empty), _1: NOT_SSA}
//! ; msg   loc.idx    param    pass mode            ssa flags  ty
//! ; ret    _0      = v0       ByRef                NOT_SSA    (u8, u8)
//! ; arg    _1      = v1       ByRef                NOT_SSA    IsNotEmpty
//! ; arg    _2.0    = v2       ByVal(types::I64)    NOT_SSA    &&[u16]
//!
//!     ss0 = explicit_slot 0 ; _1: IsNotEmpty size=0 align=1,8
//!     ss1 = explicit_slot 8 ; _2: (&&[u16],) size=8 align=8,8
//!     ss2 = explicit_slot 8 ; _4: (&&[u16],) size=8 align=8,8
//!     sig0 = (i64, i64, i64) system_v
//!     sig1 = (i64, i64, i64) system_v
//!     fn0 = colocated u0:6 sig1 ; Instance { def: Item(DefId(0/0:31 ~ example[8787]::{{impl}}[1]::call_mut[0])), substs: [ReErased, ReErased] }
//!
//! block0(v0: i64, v1: i64, v2: i64):
//!     v3 = stack_addr.i64 ss0
//!     v4 = stack_addr.i64 ss1
//!     store v2, v4
//!     v5 = stack_addr.i64 ss2
//!     jump block1
//!
//! block1:
//!     nop
//! ; _3 = &mut _1
//! ; _4 = _2
//!     v6 = load.i64 v4
//!     store v6, v5
//! ;
//! ; _0 = const mini_core::FnMut::call_mut(move _3, move _4)
//!     v7 = load.i64 v5
//!     call fn0(v0, v3, v7)
//!     jump block2
//!
//! block2:
//!     nop
//! ;
//! ; return
//!     return
//! }
//! ```

use std::fmt;
use std::io::Write;

use cranelift_codegen::{
    entity::SecondaryMap,
    ir::{entities::AnyEntity, function::DisplayFunctionAnnotations},
    write::{FuncWriter, PlainWriter},
};

use rustc_middle::ty::layout::FnAbiExt;
use rustc_session::config::OutputType;
use rustc_target::abi::call::FnAbi;

use crate::prelude::*;

#[derive(Debug)]
pub(crate) struct CommentWriter {
    enabled: bool,
    global_comments: Vec<String>,
    entity_comments: FxHashMap<AnyEntity, String>,
}

impl CommentWriter {
    pub(crate) fn new<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self {
        let enabled = should_write_ir(tcx);
        let global_comments = if enabled {
            vec![
                format!("symbol {}", tcx.symbol_name(instance).name),
                format!("instance {:?}", instance),
                format!("abi {:?}", FnAbi::of_instance(&RevealAllLayoutCx(tcx), instance, &[])),
                String::new(),
            ]
        } else {
            vec![]
        };

        CommentWriter { enabled, global_comments, entity_comments: FxHashMap::default() }
    }
}

impl CommentWriter {
    pub(crate) fn enabled(&self) -> bool {
        self.enabled
    }

    pub(crate) fn add_global_comment<S: Into<String>>(&mut self, comment: S) {
        debug_assert!(self.enabled);
        self.global_comments.push(comment.into());
    }

    pub(crate) fn add_comment<S: Into<String> + AsRef<str>, E: Into<AnyEntity>>(
        &mut self,
        entity: E,
        comment: S,
    ) {
        debug_assert!(self.enabled);

        use std::collections::hash_map::Entry;
        match self.entity_comments.entry(entity.into()) {
            Entry::Occupied(mut occ) => {
                occ.get_mut().push('\n');
                occ.get_mut().push_str(comment.as_ref());
            }
            Entry::Vacant(vac) => {
                vac.insert(comment.into());
            }
        }
    }
}

impl FuncWriter for &'_ CommentWriter {
    fn write_preamble(
        &mut self,
        w: &mut dyn fmt::Write,
        func: &Function,
        reg_info: Option<&isa::RegInfo>,
    ) -> Result<bool, fmt::Error> {
        for comment in &self.global_comments {
            if !comment.is_empty() {
                writeln!(w, "; {}", comment)?;
            } else {
                writeln!(w)?;
            }
        }
        if !self.global_comments.is_empty() {
            writeln!(w)?;
        }

        self.super_preamble(w, func, reg_info)
    }

    fn write_entity_definition(
        &mut self,
        w: &mut dyn fmt::Write,
        _func: &Function,
        entity: AnyEntity,
        value: &dyn fmt::Display,
    ) -> fmt::Result {
        write!(w, "    {} = {}", entity, value)?;

        if let Some(comment) = self.entity_comments.get(&entity) {
            writeln!(w, " ; {}", comment.replace('\n', "\n; "))
        } else {
            writeln!(w)
        }
    }

    fn write_block_header(
        &mut self,
        w: &mut dyn fmt::Write,
        func: &Function,
        isa: Option<&dyn isa::TargetIsa>,
        block: Block,
        indent: usize,
    ) -> fmt::Result {
        PlainWriter.write_block_header(w, func, isa, block, indent)
    }

    fn write_instruction(
        &mut self,
        w: &mut dyn fmt::Write,
        func: &Function,
        aliases: &SecondaryMap<Value, Vec<Value>>,
        isa: Option<&dyn isa::TargetIsa>,
        inst: Inst,
        indent: usize,
    ) -> fmt::Result {
        PlainWriter.write_instruction(w, func, aliases, isa, inst, indent)?;
        if let Some(comment) = self.entity_comments.get(&inst.into()) {
            writeln!(w, "; {}", comment.replace('\n', "\n; "))?;
        }
        Ok(())
    }
}

impl FunctionCx<'_, '_, '_> {
    pub(crate) fn add_global_comment<S: Into<String>>(&mut self, comment: S) {
        self.clif_comments.add_global_comment(comment);
    }

    pub(crate) fn add_comment<S: Into<String> + AsRef<str>, E: Into<AnyEntity>>(
        &mut self,
        entity: E,
        comment: S,
    ) {
        self.clif_comments.add_comment(entity, comment);
    }
}

pub(crate) fn should_write_ir(tcx: TyCtxt<'_>) -> bool {
    tcx.sess.opts.output_types.contains_key(&OutputType::LlvmAssembly)
}

pub(crate) fn write_ir_file(
    tcx: TyCtxt<'_>,
    name: impl FnOnce() -> String,
    write: impl FnOnce(&mut dyn Write) -> std::io::Result<()>,
) {
    if !should_write_ir(tcx) {
        return;
    }

    let clif_output_dir = tcx.output_filenames(()).with_extension("clif");

    match std::fs::create_dir(&clif_output_dir) {
        Ok(()) => {}
        Err(err) if err.kind() == std::io::ErrorKind::AlreadyExists => {}
        res @ Err(_) => res.unwrap(),
    }

    let clif_file_name = clif_output_dir.join(name());

    let res = std::fs::File::create(clif_file_name).and_then(|mut file| write(&mut file));
    if let Err(err) = res {
        tcx.sess.warn(&format!("error writing ir file: {}", err));
    }
}

pub(crate) fn write_clif_file<'tcx>(
    tcx: TyCtxt<'tcx>,
    postfix: &str,
    isa: &dyn cranelift_codegen::isa::TargetIsa,
    instance: Instance<'tcx>,
    context: &cranelift_codegen::Context,
    mut clif_comments: &CommentWriter,
) {
    write_ir_file(
        tcx,
        || format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix),
        |file| {
            let mut clif = String::new();
            cranelift_codegen::write::decorate_function(
                &mut clif_comments,
                &mut clif,
                &context.func,
                &DisplayFunctionAnnotations { isa: Some(isa), value_ranges: None },
            )
            .unwrap();

            for flag in isa.flags().iter() {
                writeln!(file, "set {}", flag)?;
            }
            write!(file, "target {}", isa.triple().architecture.to_string())?;
            for isa_flag in isa.isa_flags().iter() {
                write!(file, " {}", isa_flag)?;
            }
            writeln!(file, "\n")?;
            writeln!(file)?;
            file.write_all(clif.as_bytes())?;
            Ok(())
        },
    );
}

impl fmt::Debug for FunctionCx<'_, '_, '_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        writeln!(f, "{:?}", self.instance.substs)?;
        writeln!(f, "{:?}", self.local_map)?;

        let mut clif = String::new();
        ::cranelift_codegen::write::decorate_function(
            &mut &self.clif_comments,
            &mut clif,
            &self.bcx.func,
            &DisplayFunctionAnnotations::default(),
        )
        .unwrap();
        writeln!(f, "\n{}", clif)
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;

use chrono::{Duration, NaiveDate, NaiveDateTime, UTC};
use diesel::expression::dsl::*;
use diesel::pg::PgConnection;
use diesel::prelude::*;
use diesel::types::{BigInt, Date, Double, Text};
use domain::schema::pullrequest::dsl::*;

use DB_POOL;
use error::DashResult;

#[derive(Clone, Debug)]
pub struct DashSummary {
    prs_opened_per_day: BTreeMap<NaiveDate, i64>,
    prs_closed_per_day: BTreeMap<NaiveDate, i64>,
    prs_merged_per_day: BTreeMap<NaiveDate, i64>,
    prs_num_closed_per_week: BTreeMap<NaiveDate, i64>,
    prs_days_open_before_close: BTreeMap<NaiveDate, f64>,
    prs_current_open_age_days: f64,
}

pub fn summary() -> DashResult<DashSummary> {
    let conn = try!(DB_POOL.get());

    let until = UTC::now().naive_utc();
    let since = until - Duration::days(90);

    let pr_open_time = try!(prs_open_time_before_close(since, until, &conn));

    Ok(DashSummary {
        prs_opened_per_day: try!(prs_opened_per_day(since, until, &conn)),
        prs_closed_per_day: try!(prs_closed_per_day(since, until, &conn)),
        prs_merged_per_day: try!(prs_merged_per_day(since, until, &conn)),
        prs_num_closed_per_week: pr_open_time.0,
        prs_days_open_before_close: pr_open_time.1,
        prs_current_open_age_days: try!(open_prs_avg_days_old(&conn)),
    })
}

fn prs_opened_per_day(since: NaiveDateTime,
                      until: NaiveDateTime,
                      conn: &PgConnection)
                      -> DashResult<BTreeMap<NaiveDate, i64>> {
    // TODO (adam) waiting on multiple aggregates in diesel
    let d = sql::<Date>("d");
    Ok(try!(pullrequest.select(sql::<(Date, BigInt)>("created_at::date as d, COUNT(*)"))
                       .filter(created_at.ge(since).and(created_at.le(until)))
                       .group_by(d)
                       .get_results(conn))
           .into_iter()
           .collect())
}

fn prs_closed_per_day(since: NaiveDateTime,
                      until: NaiveDateTime,
                      conn: &PgConnection)
                      -> DashResult<BTreeMap<NaiveDate, i64>> {
    // TODO (adam) waiting on multiple aggregates in diesel
    let d = sql::<Date>("d");
    Ok(try!(pullrequest.select(sql::<(Date, BigInt)>("closed_at::date as d, COUNT(*)"))
                       .filter(closed_at.is_not_null()
                                        .and(closed_at.ge(since).and(closed_at.le(until))))
                       .group_by(d)
                       .get_results(conn))
           .into_iter()
           .collect())
}

fn prs_merged_per_day(since: NaiveDateTime,
                      until: NaiveDateTime,
                      conn: &PgConnection)
                      -> DashResult<BTreeMap<NaiveDate, i64>> {
    // TODO (adam) waiting on multiple aggregates in diesel
    let d = sql::<Date>("d");
    Ok(try!(pullrequest.select(sql::<(Date, BigInt)>("merged_at::date as d, COUNT(*)"))
                       .filter(merged_at.is_not_null()
                                        .and(merged_at.ge(since).and(merged_at.le(until))))
                       .group_by(d)
                       .get_results(conn))
           .into_iter()
           .collect())
}

fn prs_open_time_before_close
    (since: NaiveDateTime,
     until: NaiveDateTime,
     conn: &PgConnection)
     -> DashResult<(BTreeMap<NaiveDate, i64>, BTreeMap<NaiveDate, f64>)> {

    let w = sql::<Text>("iso_closed_week");
    let triples = try!(pullrequest.select(sql::<(BigInt, Double, Text)>("\
        COUNT(*), \
        \
        AVG(EXTRACT(EPOCH FROM closed_at) - \
          EXTRACT(EPOCH FROM created_at)) \
          / (60 * 60 * 24), \
        \
        EXTRACT(ISOYEAR FROM closed_at)::text || '-' || \
          EXTRACT(WEEK FROM closed_at)::text || '-6' AS iso_closed_week"))
                                  .filter(closed_at.is_not_null()
                                                   .and(closed_at.ge(since))
                                                   .and(closed_at.le(until)))
                                  .group_by(w)
                                  .get_results::<(i64, f64, String)>(conn));

    let mut num_closed_map = BTreeMap::new();
    let mut days_open_map = BTreeMap::new();

    for (num_closed, days_open, week_str) in triples {
        // this will give us the beginning of the week we're describing (I think)
        // unwrapping this parsing is fine since we dictate above what format is acceptable
        let d = NaiveDate::parse_from_str(&week_str, "%G-%V-%w").unwrap();
        num_closed_map.insert(d, num_closed);
        days_open_map.insert(d, days_open);
    }

    Ok((num_closed_map, days_open_map))
}

fn open_prs_avg_days_old(conn: &PgConnection) -> DashResult<f64> {
    Ok(try!(pullrequest.select(sql::<Double>("AVG(EXTRACT(EPOCH FROM (now() - created_at))) / \
                                              (60 * 60 * 24)"))
                       .filter(closed_at.is_null())
                       .first(conn)))
}
<commit_msg>Adding bors retries report and cleaning up some of the other queries.<commit_after>use std::collections::BTreeMap;

use chrono::{Duration, NaiveDate, NaiveDateTime, UTC};
use diesel::expression::dsl::*;
use diesel::prelude::*;
use diesel::types::{BigInt, Date, Double, Integer, Text, Timestamp};

use DB_POOL;
use error::DashResult;

#[derive(Clone, Debug)]
pub struct DashSummary {
    prs_opened_per_day: BTreeMap<NaiveDate, i64>,
    prs_closed_per_day: BTreeMap<NaiveDate, i64>,
    prs_merged_per_day: BTreeMap<NaiveDate, i64>,
    prs_num_closed_per_week: BTreeMap<NaiveDate, i64>,
    prs_days_open_before_close: BTreeMap<NaiveDate, f64>,
    prs_current_open_age_days: f64,
    prs_bors_retries: BTreeMap<i32, i64>,
}

pub fn summary() -> DashResult<DashSummary> {
    let until = UTC::now().naive_utc();
    let since = until - Duration::days(90);

    let pr_open_time = try!(prs_open_time_before_close(since, until));

    Ok(DashSummary {
        prs_opened_per_day: try!(prs_opened_per_day(since, until)),
        prs_closed_per_day: try!(prs_closed_per_day(since, until)),
        prs_merged_per_day: try!(prs_merged_per_day(since, until)),
        prs_num_closed_per_week: pr_open_time.0,
        prs_days_open_before_close: pr_open_time.1,
        prs_current_open_age_days: try!(open_prs_avg_days_old()),
        prs_bors_retries: try!(bors_retries_per_pr(since, until)),
    })
}

pub fn prs_opened_per_day(since: NaiveDateTime,
                      until: NaiveDateTime)
                      -> DashResult<BTreeMap<NaiveDate, i64>> {
    use domain::schema::pullrequest::dsl::*;

    let conn = try!(DB_POOL.get());
    let d = sql::<Date>("d");
    Ok(try!(pullrequest.select(sql::<(Date, BigInt)>("created_at::date as d, COUNT(*)"))
                       .filter(created_at.ge(since))
                       .filter(created_at.le(until))
                       .group_by(d)
                       .get_results(&*conn))
           .into_iter()
           .collect())
}

pub fn prs_closed_per_day(since: NaiveDateTime,
                      until: NaiveDateTime)
                      -> DashResult<BTreeMap<NaiveDate, i64>> {
    use domain::schema::pullrequest::dsl::*;

    let conn = try!(DB_POOL.get());
    let d = sql::<Date>("d");
    Ok(try!(pullrequest.select(sql::<(Date, BigInt)>("closed_at::date as d, COUNT(*)"))
                       .filter(closed_at.is_not_null())
                       .filter(closed_at.ge(since))
                       .filter(closed_at.le(until))
                       .group_by(d)
                       .get_results(&*conn))
           .into_iter()
           .collect())
}

pub fn prs_merged_per_day(since: NaiveDateTime,
                      until: NaiveDateTime)
                      -> DashResult<BTreeMap<NaiveDate, i64>> {
    use domain::schema::pullrequest::dsl::*;

    let conn = try!(DB_POOL.get());
    let d = sql::<Date>("d");
    Ok(try!(pullrequest.select(sql::<(Date, BigInt)>("merged_at::date as d, COUNT(*)"))
                       .filter(merged_at.is_not_null())
                       .filter(merged_at.ge(since))
                       .filter(merged_at.le(until))
                       .group_by(d)
                       .get_results(&*conn))
           .into_iter()
           .collect())
}

pub fn prs_open_time_before_close
    (since: NaiveDateTime,
     until: NaiveDateTime)
     -> DashResult<(BTreeMap<NaiveDate, i64>, BTreeMap<NaiveDate, f64>)> {
    use domain::schema::pullrequest::dsl::*;

    let conn = try!(DB_POOL.get());

    let w = sql::<Text>("iso_closed_week");
    let triples = try!(pullrequest.select(sql::<(BigInt, Double, Text)>("\
        COUNT(*), \
        \
        AVG(EXTRACT(EPOCH FROM closed_at) - \
          EXTRACT(EPOCH FROM created_at)) \
          / (60 * 60 * 24), \
        \
        EXTRACT(ISOYEAR FROM closed_at)::text || '-' || \
          EXTRACT(WEEK FROM closed_at)::text || '-6' AS iso_closed_week"))
                                  .filter(closed_at.is_not_null())
                                  .filter(closed_at.ge(since))
                                  .filter(closed_at.le(until))
                                  .group_by(w)
                                  .get_results::<(i64, f64, String)>(&*conn));

    let mut num_closed_map = BTreeMap::new();
    let mut days_open_map = BTreeMap::new();

    for (num_closed, days_open, week_str) in triples {
        // this will give us the end of each week we're describing
        // unwrapping this parsing is fine since we dictate above what format is acceptable
        let d = NaiveDate::parse_from_str(&week_str, "%G-%V-%w").unwrap();
        num_closed_map.insert(d, num_closed);
        days_open_map.insert(d, days_open);
    }

    Ok((num_closed_map, days_open_map))
}

sql_function!(date_part, date_part_t, (part: Text, date: Timestamp) -> Double);

pub fn open_prs_avg_days_old() -> DashResult<f64> {
    use domain::schema::pullrequest::dsl::*;
    let conn = try!(DB_POOL.get());
    Ok(try!(pullrequest.select(sql::<Double>("AVG(EXTRACT(EPOCH FROM (now() - created_at))) / \
                                              (60 * 60 * 24)"))
                       .filter(closed_at.is_null())
                       .first(&*conn)))
}

pub fn bors_retries_per_pr(since: NaiveDateTime,
                       until: NaiveDateTime)
                       -> DashResult<BTreeMap<i32, i64>> {

    use domain::schema::issuecomment::dsl::*;
    let conn = try!(DB_POOL.get());

    Ok(try!(issuecomment.select(sql::<(Integer, BigInt)>("fk_issue, COUNT(*)"))
                        .filter(body.like("%@bors%retry%"))
                        .filter(created_at.ge(since))
                        .filter(created_at.le(until))
                        .group_by(fk_issue)
                        .load(&*conn))
           .into_iter()
           .collect())
}
<|endoftext|>


<commit_before>use if_chain::if_chain;
use rustc::hir::*;
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::ty::{self, Ty};
use rustc::{declare_tool_lint, lint_array};
use rustc_errors::Applicability;

use crate::utils::{is_adjusted, iter_input_pats, snippet_opt, span_lint_and_then, type_is_unsafe_function};

pub struct EtaPass;

declare_clippy_lint! {
    /// **What it does:** Checks for closures which just call another function where
    /// the function can be called directly. `unsafe` functions or calls where types
    /// get adjusted are ignored.
    ///
    /// **Why is this bad?** Needlessly creating a closure adds code for no benefit
    /// and gives the optimizer more work.
    ///
    /// **Known problems:** If creating the closure inside the closure has a side-
    /// effect then moving the closure creation out will change when that side-
    /// effect runs.
    /// See rust-lang/rust-clippy#1439 for more details.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// xs.map(|x| foo(x))
    /// ```
    /// where `foo(_)` is a plain function that takes the exact argument type of
    /// `x`.
    pub REDUNDANT_CLOSURE,
    style,
    "redundant closures, i.e., `|a| foo(a)` (which can be written as just `foo`)"
}

impl LintPass for EtaPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(REDUNDANT_CLOSURE)
    }

    fn name(&self) -> &'static str {
        "EtaReduction"
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EtaPass {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if in_external_macro(cx.sess(), expr.span) {
            return;
        }

        match expr.node {
            ExprKind::Call(_, ref args) | ExprKind::MethodCall(_, _, ref args) => {
                for arg in args {
                    check_closure(cx, arg)
                }
            },
            _ => (),
        }
    }
}

fn check_closure(cx: &LateContext<'_, '_>, expr: &Expr) {
    if let ExprKind::Closure(_, ref decl, eid, _, _) = expr.node {
        let body = cx.tcx.hir().body(eid);
        let ex = &body.value;

        if_chain!(
            if let ExprKind::Call(ref caller, ref args) = ex.node;

            // Not the same number of arguments, there is no way the closure is the same as the function return;
            if args.len() == decl.inputs.len();

            // Are the expression or the arguments type-adjusted? Then we need the closure
            if !(is_adjusted(cx, ex) || args.iter().any(|arg| is_adjusted(cx, arg)));

            let fn_ty = cx.tables.expr_ty(caller);
            if !type_is_unsafe_function(cx, fn_ty);

            if compare_inputs(&mut iter_input_pats(decl, body), &mut args.into_iter());

            then {
                span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure found", |db| {
                    if let Some(snippet) = snippet_opt(cx, caller.span) {
                        db.span_suggestion(
                            expr.span,
                            "remove closure as shown",
                            snippet,
                            Applicability::MachineApplicable,
                        );
                    }
                });
            }
        );

        if_chain!(
            if let ExprKind::MethodCall(ref path, _, ref args) = ex.node;

            // Not the same number of arguments, there is no way the closure is the same as the function return;
            if args.len() == decl.inputs.len();

            // Are the expression or the arguments type-adjusted? Then we need the closure
            if !(is_adjusted(cx, ex) || args.iter().skip(1).any(|arg| is_adjusted(cx, arg)));

            let method_def_id = cx.tables.type_dependent_defs()[ex.hir_id].def_id();
            if !type_is_unsafe_function(cx, cx.tcx.type_of(method_def_id));

            if compare_inputs(&mut iter_input_pats(decl, body), &mut args.into_iter());

            if let Some(name) = get_ufcs_type_name(cx, method_def_id, &args[0]);

            then {
                span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure found", |db| {
                    db.span_suggestion(
                        expr.span,
                        "remove closure as shown",
                        format!("{}::{}", name, path.ident.name),
                        Applicability::MachineApplicable,
                    );
                });
            }
        );
    }
}

/// Tries to determine the type for universal function call to be used instead of the closure
fn get_ufcs_type_name(
    cx: &LateContext<'_, '_>,
    method_def_id: def_id::DefId,
    self_arg: &Expr,
) -> std::option::Option<String> {
    let expected_type_of_self = &cx.tcx.fn_sig(method_def_id).inputs_and_output().skip_binder()[0];
    let actual_type_of_self = &cx.tables.node_type(self_arg.hir_id);

    if let Some(trait_id) = cx.tcx.trait_of_item(method_def_id) {
        if match_borrow_depth(expected_type_of_self, &actual_type_of_self) {
            return Some(cx.tcx.def_path_str(trait_id));
        }
    }

    cx.tcx.impl_of_method(method_def_id).and_then(|_| {
        //a type may implicitly implement other type's methods (e.g. Deref)
        if match_types(expected_type_of_self, &actual_type_of_self) {
            return Some(get_type_name(cx, &actual_type_of_self));
        }
        None
    })
}

fn match_borrow_depth(lhs: Ty<'_>, rhs: Ty<'_>) -> bool {
    match (&lhs.sty, &rhs.sty) {
        (ty::Ref(_, t1, _), ty::Ref(_, t2, _)) => match_borrow_depth(&t1, &t2),
        (l, r) => match (l, r) {
            (ty::Ref(_, _, _), _) | (_, ty::Ref(_, _, _)) => false,
            (_, _) => true,
        },
    }
}

fn match_types(lhs: Ty<'_>, rhs: Ty<'_>) -> bool {
    match (&lhs.sty, &rhs.sty) {
        (ty::Bool, ty::Bool)
        | (ty::Char, ty::Char)
        | (ty::Int(_), ty::Int(_))
        | (ty::Uint(_), ty::Uint(_))
        | (ty::Str, ty::Str) => true,
        (ty::Ref(_, t1, _), ty::Ref(_, t2, _))
        | (ty::Array(t1, _), ty::Array(t2, _))
        | (ty::Slice(t1), ty::Slice(t2)) => match_types(&t1, &t2),
        (ty::Adt(def1, _), ty::Adt(def2, _)) => def1 == def2,
        (_, _) => false,
    }
}

fn get_type_name(cx: &LateContext<'_, '_>, ty: Ty<'_>) -> String {
    match ty.sty {
        ty::Adt(t, _) => cx.tcx.def_path_str(t.did),
        ty::Ref(_, r, _) => get_type_name(cx, &r),
        _ => ty.to_string(),
    }
}

fn compare_inputs(closure_inputs: &mut dyn Iterator<Item = &Arg>, call_args: &mut dyn Iterator<Item = &Expr>) -> bool {
    for (closure_input, function_arg) in closure_inputs.zip(call_args) {
        if let PatKind::Binding(_, _, ident, _) = closure_input.pat.node {
            // XXXManishearth Should I be checking the binding mode here?
            if let ExprKind::Path(QPath::Resolved(None, ref p)) = function_arg.node {
                if p.segments.len() != 1 {
                    // If it's a proper path, it can't be a local variable
                    return false;
                }
                if p.segments[0].ident.name != ident.name {
                    // The two idents should be the same
                    return false;
                }
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
    true
}
<commit_msg>Drop redundant &<commit_after>use if_chain::if_chain;
use rustc::hir::*;
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::ty::{self, Ty};
use rustc::{declare_tool_lint, lint_array};
use rustc_errors::Applicability;

use crate::utils::{is_adjusted, iter_input_pats, snippet_opt, span_lint_and_then, type_is_unsafe_function};

pub struct EtaPass;

declare_clippy_lint! {
    /// **What it does:** Checks for closures which just call another function where
    /// the function can be called directly. `unsafe` functions or calls where types
    /// get adjusted are ignored.
    ///
    /// **Why is this bad?** Needlessly creating a closure adds code for no benefit
    /// and gives the optimizer more work.
    ///
    /// **Known problems:** If creating the closure inside the closure has a side-
    /// effect then moving the closure creation out will change when that side-
    /// effect runs.
    /// See rust-lang/rust-clippy#1439 for more details.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// xs.map(|x| foo(x))
    /// ```
    /// where `foo(_)` is a plain function that takes the exact argument type of
    /// `x`.
    pub REDUNDANT_CLOSURE,
    style,
    "redundant closures, i.e., `|a| foo(a)` (which can be written as just `foo`)"
}

impl LintPass for EtaPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(REDUNDANT_CLOSURE)
    }

    fn name(&self) -> &'static str {
        "EtaReduction"
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EtaPass {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if in_external_macro(cx.sess(), expr.span) {
            return;
        }

        match expr.node {
            ExprKind::Call(_, ref args) | ExprKind::MethodCall(_, _, ref args) => {
                for arg in args {
                    check_closure(cx, arg)
                }
            },
            _ => (),
        }
    }
}

fn check_closure(cx: &LateContext<'_, '_>, expr: &Expr) {
    if let ExprKind::Closure(_, ref decl, eid, _, _) = expr.node {
        let body = cx.tcx.hir().body(eid);
        let ex = &body.value;

        if_chain!(
            if let ExprKind::Call(ref caller, ref args) = ex.node;

            // Not the same number of arguments, there is no way the closure is the same as the function return;
            if args.len() == decl.inputs.len();

            // Are the expression or the arguments type-adjusted? Then we need the closure
            if !(is_adjusted(cx, ex) || args.iter().any(|arg| is_adjusted(cx, arg)));

            let fn_ty = cx.tables.expr_ty(caller);
            if !type_is_unsafe_function(cx, fn_ty);

            if compare_inputs(&mut iter_input_pats(decl, body), &mut args.into_iter());

            then {
                span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure found", |db| {
                    if let Some(snippet) = snippet_opt(cx, caller.span) {
                        db.span_suggestion(
                            expr.span,
                            "remove closure as shown",
                            snippet,
                            Applicability::MachineApplicable,
                        );
                    }
                });
            }
        );

        if_chain!(
            if let ExprKind::MethodCall(ref path, _, ref args) = ex.node;

            // Not the same number of arguments, there is no way the closure is the same as the function return;
            if args.len() == decl.inputs.len();

            // Are the expression or the arguments type-adjusted? Then we need the closure
            if !(is_adjusted(cx, ex) || args.iter().skip(1).any(|arg| is_adjusted(cx, arg)));

            let method_def_id = cx.tables.type_dependent_defs()[ex.hir_id].def_id();
            if !type_is_unsafe_function(cx, cx.tcx.type_of(method_def_id));

            if compare_inputs(&mut iter_input_pats(decl, body), &mut args.into_iter());

            if let Some(name) = get_ufcs_type_name(cx, method_def_id, &args[0]);

            then {
                span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure found", |db| {
                    db.span_suggestion(
                        expr.span,
                        "remove closure as shown",
                        format!("{}::{}", name, path.ident.name),
                        Applicability::MachineApplicable,
                    );
                });
            }
        );
    }
}

/// Tries to determine the type for universal function call to be used instead of the closure
fn get_ufcs_type_name(
    cx: &LateContext<'_, '_>,
    method_def_id: def_id::DefId,
    self_arg: &Expr,
) -> std::option::Option<String> {
    let expected_type_of_self = &cx.tcx.fn_sig(method_def_id).inputs_and_output().skip_binder()[0];
    let actual_type_of_self = &cx.tables.node_type(self_arg.hir_id);

    if let Some(trait_id) = cx.tcx.trait_of_item(method_def_id) {
        if match_borrow_depth(expected_type_of_self, &actual_type_of_self) {
            return Some(cx.tcx.def_path_str(trait_id));
        }
    }

    cx.tcx.impl_of_method(method_def_id).and_then(|_| {
        //a type may implicitly implement other type's methods (e.g. Deref)
        if match_types(expected_type_of_self, &actual_type_of_self) {
            return Some(get_type_name(cx, &actual_type_of_self));
        }
        None
    })
}

fn match_borrow_depth(lhs: Ty<'_>, rhs: Ty<'_>) -> bool {
    match (&lhs.sty, &rhs.sty) {
        (ty::Ref(_, t1, _), ty::Ref(_, t2, _)) => match_borrow_depth(&t1, &t2),
        (l, r) => match (l, r) {
            (ty::Ref(_, _, _), _) | (_, ty::Ref(_, _, _)) => false,
            (_, _) => true,
        },
    }
}

fn match_types(lhs: Ty<'_>, rhs: Ty<'_>) -> bool {
    match (&lhs.sty, &rhs.sty) {
        (ty::Bool, ty::Bool)
        | (ty::Char, ty::Char)
        | (ty::Int(_), ty::Int(_))
        | (ty::Uint(_), ty::Uint(_))
        | (ty::Str, ty::Str) => true,
        (ty::Ref(_, t1, _), ty::Ref(_, t2, _))
        | (ty::Array(t1, _), ty::Array(t2, _))
        | (ty::Slice(t1), ty::Slice(t2)) => match_types(t1, t2),
        (ty::Adt(def1, _), ty::Adt(def2, _)) => def1 == def2,
        (_, _) => false,
    }
}

fn get_type_name(cx: &LateContext<'_, '_>, ty: Ty<'_>) -> String {
    match ty.sty {
        ty::Adt(t, _) => cx.tcx.def_path_str(t.did),
        ty::Ref(_, r, _) => get_type_name(cx, &r),
        _ => ty.to_string(),
    }
}

fn compare_inputs(closure_inputs: &mut dyn Iterator<Item = &Arg>, call_args: &mut dyn Iterator<Item = &Expr>) -> bool {
    for (closure_input, function_arg) in closure_inputs.zip(call_args) {
        if let PatKind::Binding(_, _, ident, _) = closure_input.pat.node {
            // XXXManishearth Should I be checking the binding mode here?
            if let ExprKind::Path(QPath::Resolved(None, ref p)) = function_arg.node {
                if p.segments.len() != 1 {
                    // If it's a proper path, it can't be a local variable
                    return false;
                }
                if p.segments[0].ident.name != ident.name {
                    // The two idents should be the same
                    return false;
                }
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
    true
}
<|endoftext|>


<commit_before>//! Velocity (base unit meter per second, m · s⁻¹).

quantity! {
    /// Velocity (base unit meter per second, m · s⁻¹).
    quantity: Velocity; "velocity";
    /// Dimension of velocity, LT⁻¹ (base unit meter per second, m · s⁻¹).
    dimension: ISQ<
        P1,     // length
        Z0,     // mass
        N1,     // time
        Z0,     // electric current
        Z0,     // thermodynamic temperature
        Z0,     // amount of substance
        Z0>;    // luminous intensity
    units {
        @yottameter_per_second: prefix!(yotta); "Ym/s", "yottameter per second",
            "yottameters per second";
        @zettameter_per_second: prefix!(zetta); "Zm/s", "zettameter per second",
            "zettameters per second";
        @exameter_per_second: prefix!(exa); "Em/s", "exameter per second",
            "exameters per second";
        @petameter_per_second: prefix!(peta); "Pm/s", "petameter per second",
            "petameters per second";
        @terameter_per_second: prefix!(tera); "Tm/s", "terameter per second",
            "terameters per second";
        @gigameter_per_second: prefix!(giga); "Gm/s", "gigameter per second",
            "gigameters per second";
        @megameter_per_second: prefix!(mega); "Mm/s", "megameter per second",
            "megameters per second";
        @kilometer_per_second: prefix!(kilo); "km/s", "kilometer per second",
            "kilometers per second";
        @hectometer_per_second: prefix!(hecto); "hm/s", "hectometer per second",
            "hectometers per second";
        @decameter_per_second: prefix!(deca); "dam/s", "decameter per second",
            "decameters per second";
        @meter_per_second: prefix!(none); "m/s", "meter per second", "meters per second";
        @decimeter_per_second: prefix!(deci); "dm/s", "decimeter per second",
            "decimeters per second";
        @centimeter_per_second: prefix!(centi); "cm/s", "centimeter per second",
            "centimeters per second";
        @millimeter_per_second: prefix!(milli); "mm/s", "millimeter per second",
            "millimeters per second";
        @micrometer_per_second: prefix!(micro); "µm/s", "micrometer per second",
            "micrometers per second";
        @nanometer_per_second: prefix!(nano); "nm/s", "nanometer per second",
            "nanometers per second";
        @picometer_per_second: prefix!(pico); "pm/s", "picometer per second",
            "picometers per second";
        @femtometer_per_second: prefix!(femto); "fm/s", "femtometer per second",
            "femtometers per second";
        @attometer_per_second: prefix!(atto); "am/s", "attometer per second",
            "attometers per second";
        @zeptometer_per_second: prefix!(zepto); "zm/s", "zeptometer per second",
            "zeptometers per second";
        @yoctometer_per_second: prefix!(yocto); "ym/s", "yoctometer per second",
            "yoctometers per second";

        @foot_per_hour: 8.466_666_666_666_667_E-5; "ft/h", "foot per hour", "feet per hour";
        @foot_per_minute: 5.08_E-3; "ft/min", "foot per minute", "feet per minute";
        @foot_per_second: 3.048_E-1; "ft/s", "foot per second", "feet per second";
        @inch_per_second: 2.54_E-2; "in/s", "inch per second", "inches per second";
        @kilometer_per_hour: 2.777_777_777_777_778_E-1; "km/h", "kilometer per hour",
            "kilometers per hour";
        @knot: 5.144_444_444_444_445_E-1; "kn", "knot", "knots";
        @mile_per_hour: 4.470_4_E-1; "mi/h", "mile per hour", "miles per hour";
        @mile_per_minute: 2.682_24_E1; "mi/min", "mile per minute", "miles per minute";
        @mile_per_second: 1.609_344_E3; "mi/s", "mile per second", "miles per second";
        @millimeter_per_minute: 1.666_666_666_666_666_667_E-5; "mm/min", "millimeter per minute",
            "millimeters per minute";
    }
}

#[cfg(test)]
mod test {
    storage_types! {
        use crate::num::One;
        use crate::si::length as l;
        use crate::si::quantities::*;
        use crate::si::time as t;
        use crate::si::velocity as v;
        use crate::tests::Test;

        #[test]
        fn check_dimension() {
            let _: Velocity<V> = Length::new::<l::meter>(V::one())
                / Time::new::<t::second>(V::one());
        }

        #[test]
        fn check_units() {
            test::<l::yottameter, t::second, v::yottameter_per_second>();
            test::<l::zettameter, t::second, v::zettameter_per_second>();
            test::<l::exameter, t::second, v::exameter_per_second>();
            test::<l::petameter, t::second, v::petameter_per_second>();
            test::<l::terameter, t::second, v::terameter_per_second>();
            test::<l::gigameter, t::second, v::gigameter_per_second>();
            test::<l::megameter, t::second, v::megameter_per_second>();
            test::<l::kilometer, t::second, v::kilometer_per_second>();
            test::<l::hectometer, t::second, v::hectometer_per_second>();
            test::<l::decameter, t::second, v::decameter_per_second>();
            test::<l::meter, t::second, v::meter_per_second>();
            test::<l::decimeter, t::second, v::decimeter_per_second>();
            test::<l::centimeter, t::second, v::centimeter_per_second>();
            test::<l::millimeter, t::second, v::millimeter_per_second>();
            test::<l::micrometer, t::second, v::micrometer_per_second>();
            test::<l::nanometer, t::second, v::nanometer_per_second>();
            test::<l::picometer, t::second, v::picometer_per_second>();
            test::<l::femtometer, t::second, v::femtometer_per_second>();
            test::<l::attometer, t::second, v::attometer_per_second>();
            test::<l::zeptometer, t::second, v::zeptometer_per_second>();
            test::<l::yoctometer, t::second, v::yoctometer_per_second>();

            test::<l::foot, t::hour, v::foot_per_hour>();
            test::<l::foot, t::minute, v::foot_per_minute>();
            test::<l::foot, t::second, v::foot_per_second>();
            test::<l::inch, t::second, v::inch_per_second>();
            test::<l::kilometer, t::hour, v::kilometer_per_hour>();
            test::<l::nautical_mile, t::hour, v::knot>();
            test::<l::mile, t::hour, v::mile_per_hour>();
            test::<l::mile, t::second, v::mile_per_second>();
            test::<l::millimeter, t::minute, v::millimeter_per_minute>();

            fn test<L: l::Conversion<V>, T: t::Conversion<V>, E: v::Conversion<V>>() {
                Test::assert_eq(&Velocity::new::<E>(V::one()),
                    &(Length::new::<L>(V::one()) / Time::new::<T>(V::one())));
            }
        }
    }
}
<commit_msg>Add speed of light and Hartree atomic unit of velocity as velocity units.<commit_after>//! Velocity (base unit meter per second, m · s⁻¹).

quantity! {
    /// Velocity (base unit meter per second, m · s⁻¹).
    quantity: Velocity; "velocity";
    /// Dimension of velocity, LT⁻¹ (base unit meter per second, m · s⁻¹).
    dimension: ISQ<
        P1,     // length
        Z0,     // mass
        N1,     // time
        Z0,     // electric current
        Z0,     // thermodynamic temperature
        Z0,     // amount of substance
        Z0>;    // luminous intensity
    units {
        @yottameter_per_second: prefix!(yotta); "Ym/s", "yottameter per second",
            "yottameters per second";
        @zettameter_per_second: prefix!(zetta); "Zm/s", "zettameter per second",
            "zettameters per second";
        @exameter_per_second: prefix!(exa); "Em/s", "exameter per second",
            "exameters per second";
        @petameter_per_second: prefix!(peta); "Pm/s", "petameter per second",
            "petameters per second";
        @terameter_per_second: prefix!(tera); "Tm/s", "terameter per second",
            "terameters per second";
        @gigameter_per_second: prefix!(giga); "Gm/s", "gigameter per second",
            "gigameters per second";
        @megameter_per_second: prefix!(mega); "Mm/s", "megameter per second",
            "megameters per second";
        @kilometer_per_second: prefix!(kilo); "km/s", "kilometer per second",
            "kilometers per second";
        @hectometer_per_second: prefix!(hecto); "hm/s", "hectometer per second",
            "hectometers per second";
        @decameter_per_second: prefix!(deca); "dam/s", "decameter per second",
            "decameters per second";
        @meter_per_second: prefix!(none); "m/s", "meter per second", "meters per second";
        @decimeter_per_second: prefix!(deci); "dm/s", "decimeter per second",
            "decimeters per second";
        @centimeter_per_second: prefix!(centi); "cm/s", "centimeter per second",
            "centimeters per second";
        @millimeter_per_second: prefix!(milli); "mm/s", "millimeter per second",
            "millimeters per second";
        @micrometer_per_second: prefix!(micro); "µm/s", "micrometer per second",
            "micrometers per second";
        @nanometer_per_second: prefix!(nano); "nm/s", "nanometer per second",
            "nanometers per second";
        @picometer_per_second: prefix!(pico); "pm/s", "picometer per second",
            "picometers per second";
        @femtometer_per_second: prefix!(femto); "fm/s", "femtometer per second",
            "femtometers per second";
        @attometer_per_second: prefix!(atto); "am/s", "attometer per second",
            "attometers per second";
        @zeptometer_per_second: prefix!(zepto); "zm/s", "zeptometer per second",
            "zeptometers per second";
        @yoctometer_per_second: prefix!(yocto); "ym/s", "yoctometer per second",
            "yoctometers per second";

        @foot_per_hour: 8.466_666_666_666_667_E-5; "ft/h", "foot per hour", "feet per hour";
        @foot_per_minute: 5.08_E-3; "ft/min", "foot per minute", "feet per minute";
        @foot_per_second: 3.048_E-1; "ft/s", "foot per second", "feet per second";
        @inch_per_second: 2.54_E-2; "in/s", "inch per second", "inches per second";
        @kilometer_per_hour: 2.777_777_777_777_778_E-1; "km/h", "kilometer per hour",
            "kilometers per hour";
        @knot: 5.144_444_444_444_445_E-1; "kn", "knot", "knots";
        @mile_per_hour: 4.470_4_E-1; "mi/h", "mile per hour", "miles per hour";
        @mile_per_minute: 2.682_24_E1; "mi/min", "mile per minute", "miles per minute";
        @mile_per_second: 1.609_344_E3; "mi/s", "mile per second", "miles per second";
        @millimeter_per_minute: 1.666_666_666_666_666_667_E-5; "mm/min", "millimeter per minute",
            "millimeters per minute";

        /// Hartree atomic unit of velocity a₀ · Eₕ/ħ, where a₀ is Bohr radius, Eₕ is Hartree energy,
        /// and ħ is reduced Planck constant
        @atomic_unit_of_velocity: 2.187_691_263_64_E6; "a₀ · Eₕ/ħ", "atomic unit of velocity",
            "atomic units of velocity";
        /// Speed of light in vacuum, CODATA 2018
        @natural_unit_of_velocity: 299_792_458.0; "c", "natural unit of velocity",
            "natural units of velocity";
        /// Speed of light in vacuum, CODATA 2018
        @speed_of_light_in_vacuum: 299_792_458.0; "c", "speed of light in vacuum",
            "speeds of light in vacuum";
    }
}

#[cfg(test)]
mod test {
    storage_types! {
        use crate::num::One;
        use crate::si::length as l;
        use crate::si::quantities::*;
        use crate::si::time as t;
        use crate::si::velocity as v;
        use crate::tests::Test;

        #[test]
        fn check_dimension() {
            let _: Velocity<V> = Length::new::<l::meter>(V::one())
                / Time::new::<t::second>(V::one());
        }

        #[test]
        fn check_units() {
            test::<l::yottameter, t::second, v::yottameter_per_second>();
            test::<l::zettameter, t::second, v::zettameter_per_second>();
            test::<l::exameter, t::second, v::exameter_per_second>();
            test::<l::petameter, t::second, v::petameter_per_second>();
            test::<l::terameter, t::second, v::terameter_per_second>();
            test::<l::gigameter, t::second, v::gigameter_per_second>();
            test::<l::megameter, t::second, v::megameter_per_second>();
            test::<l::kilometer, t::second, v::kilometer_per_second>();
            test::<l::hectometer, t::second, v::hectometer_per_second>();
            test::<l::decameter, t::second, v::decameter_per_second>();
            test::<l::meter, t::second, v::meter_per_second>();
            test::<l::decimeter, t::second, v::decimeter_per_second>();
            test::<l::centimeter, t::second, v::centimeter_per_second>();
            test::<l::millimeter, t::second, v::millimeter_per_second>();
            test::<l::micrometer, t::second, v::micrometer_per_second>();
            test::<l::nanometer, t::second, v::nanometer_per_second>();
            test::<l::picometer, t::second, v::picometer_per_second>();
            test::<l::femtometer, t::second, v::femtometer_per_second>();
            test::<l::attometer, t::second, v::attometer_per_second>();
            test::<l::zeptometer, t::second, v::zeptometer_per_second>();
            test::<l::yoctometer, t::second, v::yoctometer_per_second>();

            test::<l::foot, t::hour, v::foot_per_hour>();
            test::<l::foot, t::minute, v::foot_per_minute>();
            test::<l::foot, t::second, v::foot_per_second>();
            test::<l::inch, t::second, v::inch_per_second>();
            test::<l::kilometer, t::hour, v::kilometer_per_hour>();
            test::<l::nautical_mile, t::hour, v::knot>();
            test::<l::mile, t::hour, v::mile_per_hour>();
            test::<l::mile, t::second, v::mile_per_second>();
            test::<l::millimeter, t::minute, v::millimeter_per_minute>();

            fn test<L: l::Conversion<V>, T: t::Conversion<V>, E: v::Conversion<V>>() {
                Test::assert_eq(&Velocity::new::<E>(V::one()),
                    &(Length::new::<L>(V::one()) / Time::new::<T>(V::one())));
            }
        }
    }
}
<|endoftext|>


<commit_before>mod crc;
#[macro_use]
mod macros;

pub use self::crc::{crc8, crc16};

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

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

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }
}
<commit_msg>Use `debug_assert!` instead of `assert!`<commit_after>mod crc;
#[macro_use]
mod macros;

pub use self::crc::{crc8, crc16};

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

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

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }
}
<|endoftext|>


<commit_before>use std::sync::RwLock;
use std::cmp::min;
use std::time::SystemTime;
use board::*;
use search_executor::*;
use pv::*;
use search_node::SearchNode;
use time_manager::TimeManager;
use uci::{SetOption, OptionDescription};

/// Decides when the search must be terminated.
pub struct StdTimeManager {
    started_at: SystemTime,
    move_time_millis: u64, // move time in milliseconds
    must_play: bool,
}

impl<S> TimeManager<S> for StdTimeManager
    where S: SearchExecutor<ReportData = Vec<Variation>>
{
    /// Creates a new instance.
    ///
    /// `position` gives the current position. `pondering_is_allowed`
    /// tells if the engine is allowed to use opponent's time for
    /// thinking. `wtime_millis`, `btime_millis`, `winc_millis`, and
    /// `binc_millis` specify the remaining time in milliseconds, and
    /// the number of milliseconds with which the remaining time will
    /// be incremented on each move (for black and white). `movestogo`
    /// specifies the number of moves to the next time control.
    #[allow(unused_variables)]
    fn new(position: &S::SearchNode,
           wtime_millis: Option<u64>,
           btime_millis: Option<u64>,
           winc_millis: Option<u64>,
           binc_millis: Option<u64>,
           movestogo: Option<u64>)
           -> StdTimeManager {
        // TODO: We ignore "PONDER".

        let (time, inc) = if position.board().to_move == WHITE {
            (wtime_millis, winc_millis.unwrap_or(0))
        } else {
            (btime_millis, binc_millis.unwrap_or(0))
        };
        let time = time.unwrap_or(0);
        let movestogo = movestogo.unwrap_or(40);
        let movetime = (time + inc * movestogo) / movestogo;
        StdTimeManager {
            started_at: SystemTime::now(),
            move_time_millis: min(movetime, time / 2),
            must_play: false,
        }
    }

    /// Registers the current search status with the time manager.
    #[allow(unused_variables)]
    fn update(&mut self, report: &SearchReport<Vec<Variation>>) {
        // TODO: Implement smarter time management.
        let duration = self.started_at.elapsed().unwrap();
        let duration_millis = 1000 * duration.as_secs() + duration.subsec_nanos() as u64 / 1000000;
        self.must_play = duration_millis >= self.move_time_millis;
    }

    /// Decides if the search must be terminated.
    #[allow(unused_variables)]
    fn must_play(&self, search: &S) -> bool {
        self.must_play
    }
}

impl SetOption for StdTimeManager {
    fn options() -> Vec<(String, OptionDescription)> {
        vec![("Ponder".to_string(), OptionDescription::Check { default: false })]
    }

    fn set_option(name: &str, value: &str) {
        if name == "Ponder" {
            match value {
                "true" => *PONDER.write().unwrap() = true,
                "false" => *PONDER.write().unwrap() = false,
                _ => (),
            }
        }
    }
}

lazy_static! {
    static ref PONDER: RwLock<bool> = RwLock::new(false);
}
<commit_msg>kill redundant docs<commit_after>use std::sync::RwLock;
use std::cmp::min;
use std::time::SystemTime;
use board::*;
use search_executor::*;
use pv::*;
use search_node::SearchNode;
use time_manager::TimeManager;
use uci::{SetOption, OptionDescription};

/// Decides when the search must be terminated.
pub struct StdTimeManager {
    started_at: SystemTime,
    move_time_millis: u64, // move time in milliseconds
    must_play: bool,
}

impl<S> TimeManager<S> for StdTimeManager
    where S: SearchExecutor<ReportData = Vec<Variation>>
{
    #[allow(unused_variables)]
    fn new(position: &S::SearchNode,
           wtime_millis: Option<u64>,
           btime_millis: Option<u64>,
           winc_millis: Option<u64>,
           binc_millis: Option<u64>,
           movestogo: Option<u64>)
           -> StdTimeManager {
        // TODO: We ignore "PONDER".

        let (time, inc) = if position.board().to_move == WHITE {
            (wtime_millis, winc_millis.unwrap_or(0))
        } else {
            (btime_millis, binc_millis.unwrap_or(0))
        };
        let time = time.unwrap_or(0);
        let movestogo = movestogo.unwrap_or(40);
        let movetime = (time + inc * movestogo) / movestogo;
        StdTimeManager {
            started_at: SystemTime::now(),
            move_time_millis: min(movetime, time / 2),
            must_play: false,
        }
    }

    #[allow(unused_variables)]
    fn update(&mut self, report: &SearchReport<Vec<Variation>>) {
        // TODO: Implement smarter time management.
        let duration = self.started_at.elapsed().unwrap();
        let duration_millis = 1000 * duration.as_secs() + duration.subsec_nanos() as u64 / 1000000;
        self.must_play = duration_millis >= self.move_time_millis;
    }

    #[allow(unused_variables)]
    fn must_play(&self, search: &S) -> bool {
        self.must_play
    }
}

impl SetOption for StdTimeManager {
    fn options() -> Vec<(String, OptionDescription)> {
        vec![("Ponder".to_string(), OptionDescription::Check { default: false })]
    }

    fn set_option(name: &str, value: &str) {
        if name == "Ponder" {
            match value {
                "true" => *PONDER.write().unwrap() = true,
                "false" => *PONDER.write().unwrap() = false,
                _ => (),
            }
        }
    }
}

lazy_static! {
    static ref PONDER: RwLock<bool> = RwLock::new(false);
}
<|endoftext|>