<commit_before>// Copyright 2017 TiKV Project Authors. Licensed under Apache-2.0.

use std::cmp::Ordering;
use std::f64;

use super::super::Result;
use super::constants::*;
use super::{Json, JsonRef, JsonType, ERR_CONVERT_FAILED};

impl<'a> JsonRef<'a> {
    fn get_precedence(&self) -> i32 {
        match self.get_type() {
            JsonType::Object => PRECEDENCE_OBJECT,
            JsonType::Array => PRECEDENCE_ARRAY,
            JsonType::Literal => self
                .get_literal()
                .map_or(PRECEDENCE_NULL, |_| PRECEDENCE_BOOLEAN),
            JsonType::I64 | JsonType::U64 | JsonType::Double => PRECEDENCE_NUMBER,
            JsonType::String => PRECEDENCE_STRING,
        }
    }

    fn as_f64(&self) -> Result<f64> {
        match self.get_type() {
            JsonType::I64 => Ok(self.get_i64() as f64),
            JsonType::U64 => Ok(self.get_u64() as f64),
            JsonType::Double => Ok(self.get_double()),
            JsonType::Literal => {
                let v = self.as_literal().unwrap();
                Ok(v.into())
            }
            _ => Err(invalid_type!(
                "{} from {} to f64",
                ERR_CONVERT_FAILED,
                self.to_string()
            )),
        }
    }
}

impl<'a> Eq for JsonRef<'a> {}

impl<'a> Ord for JsonRef<'a> {
    fn cmp(&self, right: &JsonRef<'_>) -> Ordering {
        self.partial_cmp(right).unwrap()
    }
}

impl<'a> PartialEq for JsonRef<'a> {
    fn eq(&self, right: &JsonRef<'_>) -> bool {
        self.partial_cmp(right)
            .map_or(false, |r| r == Ordering::Equal)
    }
}
impl<'a> PartialOrd for JsonRef<'a> {
    // See `CompareBinary` in TiDB `types/json/binary_functions.go`
    fn partial_cmp(&self, right: &JsonRef<'_>) -> Option<Ordering> {
        let precedence_diff = self.get_precedence() - right.get_precedence();
        if precedence_diff == 0 {
            if self.get_precedence() == PRECEDENCE_NULL {
                // for JSON null.
                return Some(Ordering::Equal);
            }

            return match self.get_type() {
                JsonType::I64 | JsonType::U64 | JsonType::Double => {
                    let left_data = self.as_f64().unwrap();
                    let right_data = right.as_f64().unwrap();
                    if (left_data - right_data).abs() < f64::EPSILON {
                        Some(Ordering::Equal)
                    } else {
                        left_data.partial_cmp(&right_data)
                    }
                }
                JsonType::Literal => {
                    // false is less than true.
                    self.get_literal().partial_cmp(&right.get_literal())
                }
                JsonType::Object => {
                    // only equal is defined on two json objects.
                    // larger and smaller are not defined.
                    self.value().partial_cmp(right.value())
                }
                JsonType::String => {
                    if let (Ok(left), Ok(right)) = (self.get_str_bytes(), right.get_str_bytes()) {
                        left.partial_cmp(right)
                    } else {
                        return None;
                    }
                }
                JsonType::Array => {
                    let left_count = self.get_elem_count();
                    let right_count = right.get_elem_count();
                    let mut i = 0;
                    while i < left_count && i < right_count {
                        if let (Ok(left_ele), Ok(right_ele)) =
                            (self.array_get_elem(i), right.array_get_elem(i))
                        {
                            match left_ele.partial_cmp(&right_ele) {
                                order @ None
                                | order @ Some(Ordering::Greater)
                                | order @ Some(Ordering::Less) => return order,
                                Some(Ordering::Equal) => i += 1,
                            }
                        } else {
                            return None;
                        }
                    }
                    Some(left_count.cmp(&right_count))
                }
            };
        }

        let left_data = self.as_f64();
        let right_data = right.as_f64();
        // tidb treats boolean as integer, but boolean is different from integer in JSON.
        // so we need convert them to same type and then compare.
        if let (Ok(left), Ok(right)) = (left_data, right_data) {
            return left.partial_cmp(&right);
        }

        if precedence_diff > 0 {
            Some(Ordering::Greater)
        } else {
            Some(Ordering::Less)
        }
    }
}

impl Eq for Json {}
impl Ord for Json {
    fn cmp(&self, right: &Json) -> Ordering {
        self.as_ref().partial_cmp(&right.as_ref()).unwrap()
    }
}

impl PartialEq for Json {
    fn eq(&self, right: &Json) -> bool {
        self.as_ref().partial_cmp(&right.as_ref()).unwrap() == Ordering::Equal
    }
}

impl PartialOrd for Json {
    fn partial_cmp(&self, right: &Json) -> Option<Ordering> {
        self.as_ref().partial_cmp(&right.as_ref())
    }
}

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

    #[test]
    fn test_cmp_json_between_same_type() {
        let test_cases = vec![
            ("false", "true"),
            ("-3", "3"),
            ("3", "5"),
            ("3.0", "4.9"),
            (r#""hello""#, r#""hello, world""#),
            (r#"["a", "b"]"#, r#"["a", "c"]"#),
            (r#"{"a": "b"}"#, r#"{"a": "c"}"#),
        ];
        for (left_str, right_str) in test_cases {
            let left: Json = left_str.parse().unwrap();
            let right: Json = right_str.parse().unwrap();
            assert!(left < right);
            assert_eq!(left, left);
        }
        assert_eq!(Json::none().unwrap(), Json::none().unwrap());
    }

    #[test]
    fn test_cmp_json_between_diff_type() {
        let test_cases = vec![
            ("1.5", "2"),
            ("1.5", "false"),
            ("true", "1.5"),
            ("true", "2"),
            ("null", r#"{"a": "b"}"#),
            ("2", r#""hello, world""#),
            (r#""hello, world""#, r#"{"a": "b"}"#),
            (r#"{"a": "b"}"#, r#"["a", "b"]"#),
            (r#"["a", "b"]"#, "false"),
        ];

        for (left_str, right_str) in test_cases {
            let left: Json = left_str.parse().unwrap();
            let right: Json = right_str.parse().unwrap();
            assert!(left < right);
        }

        assert_eq!(Json::from_i64(2).unwrap(), Json::from_bool(false).unwrap());
    }
}
<commit_msg>copr: fix precision lost in json numeric comparsion (#8068)<commit_after>// Copyright 2017 TiKV Project Authors. Licensed under Apache-2.0.

use std::cmp::{Ord, Ordering};
use std::f64;

use super::super::Result;
use super::constants::*;
use super::{Json, JsonRef, JsonType, ERR_CONVERT_FAILED};

fn compare<T: Ord>(x: T, y: T) -> Ordering {
    x.cmp(&y)
}

fn compare_i64_u64(x: i64, y: u64) -> Ordering {
    if x < 0 {
        Ordering::Less
    } else {
        compare::<u64>(x as u64, y)
    }
}

fn compare_f64_with_epsilon(x: f64, y: f64) -> Option<Ordering> {
    if (x - y).abs() < f64::EPSILON {
        Some(Ordering::Equal)
    } else {
        x.partial_cmp(&y)
    }
}

impl<'a> JsonRef<'a> {
    fn get_precedence(&self) -> i32 {
        match self.get_type() {
            JsonType::Object => PRECEDENCE_OBJECT,
            JsonType::Array => PRECEDENCE_ARRAY,
            JsonType::Literal => self
                .get_literal()
                .map_or(PRECEDENCE_NULL, |_| PRECEDENCE_BOOLEAN),
            JsonType::I64 | JsonType::U64 | JsonType::Double => PRECEDENCE_NUMBER,
            JsonType::String => PRECEDENCE_STRING,
        }
    }

    fn as_f64(&self) -> Result<f64> {
        match self.get_type() {
            JsonType::I64 => Ok(self.get_i64() as f64),
            JsonType::U64 => Ok(self.get_u64() as f64),
            JsonType::Double => Ok(self.get_double()),
            JsonType::Literal => {
                let v = self.as_literal().unwrap();
                Ok(v.into())
            }
            _ => Err(invalid_type!(
                "{} from {} to f64",
                ERR_CONVERT_FAILED,
                self.to_string()
            )),
        }
    }
}

impl<'a> Eq for JsonRef<'a> {}

impl<'a> Ord for JsonRef<'a> {
    fn cmp(&self, right: &JsonRef<'_>) -> Ordering {
        self.partial_cmp(right).unwrap()
    }
}

impl<'a> PartialEq for JsonRef<'a> {
    fn eq(&self, right: &JsonRef<'_>) -> bool {
        self.partial_cmp(right)
            .map_or(false, |r| r == Ordering::Equal)
    }
}
impl<'a> PartialOrd for JsonRef<'a> {
    // See `CompareBinary` in TiDB `types/json/binary_functions.go`
    fn partial_cmp(&self, right: &JsonRef<'_>) -> Option<Ordering> {
        let precedence_diff = self.get_precedence() - right.get_precedence();
        if precedence_diff == 0 {
            if self.get_precedence() == PRECEDENCE_NULL {
                // for JSON null.
                return Some(Ordering::Equal);
            }

            return match self.get_type() {
                JsonType::I64 => match right.get_type() {
                    JsonType::I64 => Some(compare(self.get_i64(), right.get_i64())),
                    JsonType::U64 => Some(compare_i64_u64(self.get_i64(), right.get_u64())),
                    JsonType::Double => {
                        compare_f64_with_epsilon(self.get_i64() as f64, right.as_f64().unwrap())
                    }
                    _ => unreachable!(),
                },
                JsonType::U64 => match right.get_type() {
                    JsonType::I64 => {
                        Some(compare_i64_u64(right.get_i64(), self.get_u64()).reverse())
                    }
                    JsonType::U64 => Some(compare(self.get_u64(), right.get_u64())),
                    JsonType::Double => {
                        compare_f64_with_epsilon(self.get_u64() as f64, right.as_f64().unwrap())
                    }
                    _ => unreachable!(),
                },
                JsonType::Double => {
                    compare_f64_with_epsilon(self.as_f64().unwrap(), right.as_f64().unwrap())
                }
                JsonType::Literal => {
                    // false is less than true.
                    self.get_literal().partial_cmp(&right.get_literal())
                }
                JsonType::Object => {
                    // only equal is defined on two json objects.
                    // larger and smaller are not defined.
                    self.value().partial_cmp(right.value())
                }
                JsonType::String => {
                    if let (Ok(left), Ok(right)) = (self.get_str_bytes(), right.get_str_bytes()) {
                        left.partial_cmp(right)
                    } else {
                        return None;
                    }
                }
                JsonType::Array => {
                    let left_count = self.get_elem_count();
                    let right_count = right.get_elem_count();
                    let mut i = 0;
                    while i < left_count && i < right_count {
                        if let (Ok(left_ele), Ok(right_ele)) =
                            (self.array_get_elem(i), right.array_get_elem(i))
                        {
                            match left_ele.partial_cmp(&right_ele) {
                                order @ None
                                | order @ Some(Ordering::Greater)
                                | order @ Some(Ordering::Less) => return order,
                                Some(Ordering::Equal) => i += 1,
                            }
                        } else {
                            return None;
                        }
                    }
                    Some(left_count.cmp(&right_count))
                }
            };
        }

        let left_data = self.as_f64();
        let right_data = right.as_f64();
        // tidb treats boolean as integer, but boolean is different from integer in JSON.
        // so we need convert them to same type and then compare.
        if let (Ok(left), Ok(right)) = (left_data, right_data) {
            return left.partial_cmp(&right);
        }

        if precedence_diff > 0 {
            Some(Ordering::Greater)
        } else {
            Some(Ordering::Less)
        }
    }
}

impl Eq for Json {}
impl Ord for Json {
    fn cmp(&self, right: &Json) -> Ordering {
        self.as_ref().partial_cmp(&right.as_ref()).unwrap()
    }
}

impl PartialEq for Json {
    fn eq(&self, right: &Json) -> bool {
        self.as_ref().partial_cmp(&right.as_ref()).unwrap() == Ordering::Equal
    }
}

impl PartialOrd for Json {
    fn partial_cmp(&self, right: &Json) -> Option<Ordering> {
        self.as_ref().partial_cmp(&right.as_ref())
    }
}

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

    #[test]
    fn test_cmp_json_numberic_type() {
        let cases = vec![
            (
                Json::from_i64(922337203685477581),
                Json::from_i64(922337203685477580),
                Ordering::Greater,
            ),
            (
                Json::from_i64(-1),
                Json::from_u64(18446744073709551615),
                Ordering::Less,
            ),
            (
                Json::from_i64(922337203685477580),
                Json::from_u64(922337203685477581),
                Ordering::Less,
            ),
            (Json::from_i64(2), Json::from_u64(1), Ordering::Greater),
            (
                Json::from_i64(std::i64::MAX),
                Json::from_u64(std::i64::MAX as u64),
                Ordering::Equal,
            ),
            (
                Json::from_u64(18446744073709551615),
                Json::from_i64(-1),
                Ordering::Greater,
            ),
            (
                Json::from_u64(922337203685477581),
                Json::from_i64(922337203685477580),
                Ordering::Greater,
            ),
            (Json::from_u64(1), Json::from_i64(2), Ordering::Less),
            (
                Json::from_u64(std::i64::MAX as u64),
                Json::from_i64(std::i64::MAX),
                Ordering::Equal,
            ),
            (Json::from_f64(9.0), Json::from_i64(9), Ordering::Equal),
            (Json::from_f64(8.9), Json::from_i64(9), Ordering::Less),
            (Json::from_f64(9.1), Json::from_i64(9), Ordering::Greater),
            (Json::from_f64(9.0), Json::from_u64(9), Ordering::Equal),
            (Json::from_f64(8.9), Json::from_u64(9), Ordering::Less),
            (Json::from_f64(9.1), Json::from_u64(9), Ordering::Greater),
            (Json::from_i64(9), Json::from_f64(9.0), Ordering::Equal),
            (Json::from_i64(9), Json::from_f64(8.9), Ordering::Greater),
            (Json::from_i64(9), Json::from_f64(9.1), Ordering::Less),
            (Json::from_u64(9), Json::from_f64(9.0), Ordering::Equal),
            (Json::from_u64(9), Json::from_f64(8.9), Ordering::Greater),
            (Json::from_u64(9), Json::from_f64(9.1), Ordering::Less),
        ];

        for (left, right, expected) in cases {
            let left = left.unwrap();
            let right = right.unwrap();
            assert_eq!(expected, left.partial_cmp(&right).unwrap());
        }
    }

    #[test]
    fn test_cmp_json_between_same_type() {
        let test_cases = vec![
            ("false", "true"),
            ("-3", "3"),
            ("3", "5"),
            ("3.0", "4.9"),
            (r#""hello""#, r#""hello, world""#),
            (r#"["a", "b"]"#, r#"["a", "c"]"#),
            (r#"{"a": "b"}"#, r#"{"a": "c"}"#),
        ];
        for (left_str, right_str) in test_cases {
            let left: Json = left_str.parse().unwrap();
            let right: Json = right_str.parse().unwrap();
            assert!(left < right);
            assert_eq!(left, left);
        }
        assert_eq!(Json::none().unwrap(), Json::none().unwrap());
    }

    #[test]
    fn test_cmp_json_between_diff_type() {
        let test_cases = vec![
            ("1.5", "2"),
            ("1.5", "false"),
            ("true", "1.5"),
            ("true", "2"),
            ("null", r#"{"a": "b"}"#),
            ("2", r#""hello, world""#),
            (r#""hello, world""#, r#"{"a": "b"}"#),
            (r#"{"a": "b"}"#, r#"["a", "b"]"#),
            (r#"["a", "b"]"#, "false"),
        ];

        for (left_str, right_str) in test_cases {
            let left: Json = left_str.parse().unwrap();
            let right: Json = right_str.parse().unwrap();
            assert!(left < right);
        }

        assert_eq!(Json::from_i64(2).unwrap(), Json::from_bool(false).unwrap());
    }
}
<|endoftext|>


<commit_before>use crate::gateway::InterMessage;
use crate::model::prelude::*;
use super::{ShardClientMessage, ShardRunnerMessage};
use futures::channel::mpsc::{UnboundedSender as Sender, TrySendError};
use async_tungstenite::tungstenite::Message;
#[cfg(feature = "collector")]
use crate::collector::{ReactionFilter, MessageFilter};

/// A lightweight wrapper around an mpsc sender.
///
/// This is used to cleanly communicate with a shard's respective
/// [`ShardRunner`]. This can be used for actions such as setting the activity
/// via [`set_activity`] or shutting down via [`shutdown`].
///
/// [`ShardRunner`]: struct.ShardRunner.html
/// [`set_activity`]: #method.set_activity
/// [`shutdown`]: #method.shutdown
#[derive(Clone, Debug)]
pub struct ShardMessenger {
    pub(crate) tx: Sender<InterMessage>,
}

impl ShardMessenger {
    /// Creates a new shard messenger.
    ///
    /// If you are using the [`Client`], you do not need to do this.
    ///
    /// [`Client`]: ../../struct.Client.html
    #[inline]
    pub fn new(tx: Sender<InterMessage>) -> Self {
        Self {
            tx,
        }
    }

    /// Requests that one or multiple [`Guild`]s be chunked.
    ///
    /// This will ask the gateway to start sending member chunks for large
    /// guilds (250 members+). If a guild is over 250 members, then a full
    /// member list will not be downloaded, and must instead be requested to be
    /// sent in "chunks" containing members.
    ///
    /// Member chunks are sent as the [`Event::GuildMembersChunk`] event. Each
    /// chunk only contains a partial amount of the total members.
    ///
    /// If the `cache` feature is enabled, the cache will automatically be
    /// updated with member chunks.
    ///
    /// # Examples
    ///
    /// Chunk a single guild by Id, limiting to 2000 [`Member`]s, and not
    /// specifying a query parameter:
    ///
    /// ```rust,no_run
    /// # use tokio::sync::Mutex;
    /// # use serenity::gateway::Shard;
    /// # use std::sync::Arc;
    /// #
    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
    /// #     let mutex = Arc::new(Mutex::new("".to_string()));
    /// #
    /// #     let mut shard = Shard::new(mutex.clone(), "", [0u64, 1u64], true, None).await?;
    /// #
    /// use serenity::model::id::GuildId;
    ///
    /// let guild_ids = vec![GuildId(81384788765712384)];
    ///
    /// shard.chunk_guilds(guild_ids, Some(2000), None);
    /// #     Ok(())
    /// # }
    /// ```
    ///
    /// Chunk a single guild by Id, limiting to 20 members, and specifying a
    /// query parameter of `"do"`:
    ///
    /// ```rust,no_run
    /// # use tokio::sync::Mutex;
    /// # use serenity::gateway::Shard;
    /// # use std::sync::Arc;
    /// #
    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
    /// #     let mutex = Arc::new(Mutex::new("".to_string()));
    /// #
    /// #     let mut shard = Shard::new(mutex.clone(), "", [0u64, 1u64], true, None).await?;
    /// #
    /// use serenity::model::id::GuildId;
    ///
    /// let guild_ids = vec![GuildId(81384788765712384)];
    ///
    /// shard.chunk_guilds(guild_ids, Some(20), Some("do"));
    /// #     Ok(())
    /// # }
    /// ```
    ///
    /// [`Event::GuildMembersChunk`]: ../../../model/event/enum.Event.html#variant.GuildMembersChunk
    /// [`Guild`]: ../../../model/guild/struct.Guild.html
    /// [`Member`]: ../../../model/guild/struct.Member.html
    pub fn chunk_guilds<It>(
        &self,
        guild_ids: It,
        limit: Option<u16>,
        query: Option<String>,
    ) where It: IntoIterator<Item=GuildId> {
        let guilds = guild_ids.into_iter().collect::<Vec<GuildId>>();

        let _ = self.send_to_shard(ShardRunnerMessage::ChunkGuilds {
            guild_ids: guilds,
            limit,
            query,
        });
    }

    /// Sets the user's current activity, if any.
    ///
    /// Other presence settings are maintained.
    ///
    /// # Examples
    ///
    /// Setting the current activity to playing `"Heroes of the Storm"`:
    ///
    /// ```rust,no_run
    /// # use tokio::sync::Mutex;
    /// # use serenity::gateway::Shard;
    /// # use std::sync::Arc;
    /// #
    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
    /// #     let mutex = Arc::new(Mutex::new("".to_string()));
    /// #
    /// #     let mut shard = Shard::new(mutex.clone(), "", [0u64, 1u64], true, None).await?;
    /// use serenity::model::gateway::Activity;
    ///
    /// shard.set_activity(Some(Activity::playing("Heroes of the Storm")));
    /// #     Ok(())
    /// # }
    /// ```
    pub fn set_activity(&self, activity: Option<Activity>) {
        let _ = self.send_to_shard(ShardRunnerMessage::SetActivity(activity));
    }

    /// Sets the user's full presence information.
    ///
    /// Consider using the individual setters if you only need to modify one of
    /// these.
    ///
    /// # Examples
    ///
    /// Set the current user as playing `"Heroes of the Storm"` and being
    /// online:
    ///
    /// ```rust,ignore
    /// # use tokio::sync::Mutex;
    /// # use serenity::gateway::Shard;
    /// # use std::sync::Arc;
    /// #
    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
    /// #     let mutex = Arc::new(Mutex::new("".to_string()));
    /// #
    /// #     let mut shard = Shard::new(mutex.clone(), "", [0u64, 1u64], true, None).await?;
    /// #
    /// use serenity::model::gateway::Activity;
    /// use serenity::model::user::OnlineStatus;
    ///
    /// let activity = Activity::playing("Heroes of the Storm");
    /// shard.set_presence(Some(activity), OnlineStatus::Online);
    /// #     Ok(())
    /// # }
    /// ```
    pub fn set_presence(&self, activity: Option<Activity>, mut status: OnlineStatus) {
        if status == OnlineStatus::Offline {
            status = OnlineStatus::Invisible;
        }

        let _ = self.send_to_shard(ShardRunnerMessage::SetPresence(status, activity));
    }

    /// Sets the user's current online status.
    ///
    /// Note that [`Offline`] is not a valid online status, so it is
    /// automatically converted to [`Invisible`].
    ///
    /// Other presence settings are maintained.
    ///
    /// # Examples
    ///
    /// Setting the current online status for the shard to [`DoNotDisturb`].
    ///
    /// ```rust,no_run
    /// # use tokio::sync::Mutex;
    /// # use serenity::gateway::Shard;
    /// # use std::sync::Arc;
    /// #
    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
    /// #     let mutex = Arc::new(Mutex::new("".to_string()));
    /// #
    /// #     let mut shard = Shard::new(mutex.clone(), "", [0u64, 1u64], true, None).await?;
    /// #
    /// use serenity::model::user::OnlineStatus;
    ///
    /// shard.set_status(OnlineStatus::DoNotDisturb);
    /// #     Ok(())
    /// # }
    /// ```
    ///
    /// [`DoNotDisturb`]: ../../../model/user/enum.OnlineStatus.html#variant.DoNotDisturb
    /// [`Invisible`]: ../../../model/user/enum.OnlineStatus.html#variant.Invisible
    /// [`Offline`]: ../../../model/user/enum.OnlineStatus.html#variant.Offline
    pub fn set_status(&self, mut online_status: OnlineStatus) {
        if online_status == OnlineStatus::Offline {
            online_status = OnlineStatus::Invisible;
        }

        let _ = self.send_to_shard(ShardRunnerMessage::SetStatus(online_status));
    }

    /// Shuts down the websocket by attempting to cleanly close the
    /// connection.
    pub fn shutdown_clean(&self) {
        let _ = self.send_to_shard(ShardRunnerMessage::Close(1000, None));
    }

    /// Sends a raw message over the WebSocket.
    ///
    /// The given message is not mutated in any way, and is sent as-is.
    ///
    /// You should only use this if you know what you're doing. If you're
    /// wanting to, for example, send a presence update, prefer the usage of
    /// the [`set_presence`] method.
    ///
    /// [`set_presence`]: #method.set_presence
    pub fn websocket_message(&self, message: Message) {
        let _ = self.send_to_shard(ShardRunnerMessage::Message(message));
    }

    /// Sends a message to the shard.
    #[inline]
    pub fn send_to_shard(&self, msg: ShardRunnerMessage)
        -> Result<(), TrySendError<InterMessage>> {
        self.tx.unbounded_send(InterMessage::Client(Box::new(ShardClientMessage::Runner(msg))))
    }

    /// Sets a new filter for a message collector.
    #[inline]
    #[cfg(feature = "collector")]
    pub fn set_message_filter(&self, collector: MessageFilter) {
        let _ = self.send_to_shard(ShardRunnerMessage::SetMessageFilter(collector));
    }

    /// Sets a new filter for a message collector.
    #[cfg(feature = "collector")]
    pub fn set_reaction_filter(&self, collector: ReactionFilter) {
        let _ = self.send_to_shard(ShardRunnerMessage::SetReactionFilter(collector));
    }
}
<commit_msg>Implement AsRef<ShardMessenger> for ShardMessenger (#936)<commit_after>use crate::gateway::InterMessage;
use crate::model::prelude::*;
use super::{ShardClientMessage, ShardRunnerMessage};
use futures::channel::mpsc::{UnboundedSender as Sender, TrySendError};
use async_tungstenite::tungstenite::Message;
#[cfg(feature = "collector")]
use crate::collector::{ReactionFilter, MessageFilter};

/// A lightweight wrapper around an mpsc sender.
///
/// This is used to cleanly communicate with a shard's respective
/// [`ShardRunner`]. This can be used for actions such as setting the activity
/// via [`set_activity`] or shutting down via [`shutdown`].
///
/// [`ShardRunner`]: struct.ShardRunner.html
/// [`set_activity`]: #method.set_activity
/// [`shutdown`]: #method.shutdown
#[derive(Clone, Debug)]
pub struct ShardMessenger {
    pub(crate) tx: Sender<InterMessage>,
}

impl ShardMessenger {
    /// Creates a new shard messenger.
    ///
    /// If you are using the [`Client`], you do not need to do this.
    ///
    /// [`Client`]: ../../struct.Client.html
    #[inline]
    pub fn new(tx: Sender<InterMessage>) -> Self {
        Self {
            tx,
        }
    }

    /// Requests that one or multiple [`Guild`]s be chunked.
    ///
    /// This will ask the gateway to start sending member chunks for large
    /// guilds (250 members+). If a guild is over 250 members, then a full
    /// member list will not be downloaded, and must instead be requested to be
    /// sent in "chunks" containing members.
    ///
    /// Member chunks are sent as the [`Event::GuildMembersChunk`] event. Each
    /// chunk only contains a partial amount of the total members.
    ///
    /// If the `cache` feature is enabled, the cache will automatically be
    /// updated with member chunks.
    ///
    /// # Examples
    ///
    /// Chunk a single guild by Id, limiting to 2000 [`Member`]s, and not
    /// specifying a query parameter:
    ///
    /// ```rust,no_run
    /// # use tokio::sync::Mutex;
    /// # use serenity::gateway::Shard;
    /// # use std::sync::Arc;
    /// #
    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
    /// #     let mutex = Arc::new(Mutex::new("".to_string()));
    /// #
    /// #     let mut shard = Shard::new(mutex.clone(), "", [0u64, 1u64], true, None).await?;
    /// #
    /// use serenity::model::id::GuildId;
    ///
    /// let guild_ids = vec![GuildId(81384788765712384)];
    ///
    /// shard.chunk_guilds(guild_ids, Some(2000), None);
    /// #     Ok(())
    /// # }
    /// ```
    ///
    /// Chunk a single guild by Id, limiting to 20 members, and specifying a
    /// query parameter of `"do"`:
    ///
    /// ```rust,no_run
    /// # use tokio::sync::Mutex;
    /// # use serenity::gateway::Shard;
    /// # use std::sync::Arc;
    /// #
    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
    /// #     let mutex = Arc::new(Mutex::new("".to_string()));
    /// #
    /// #     let mut shard = Shard::new(mutex.clone(), "", [0u64, 1u64], true, None).await?;
    /// #
    /// use serenity::model::id::GuildId;
    ///
    /// let guild_ids = vec![GuildId(81384788765712384)];
    ///
    /// shard.chunk_guilds(guild_ids, Some(20), Some("do"));
    /// #     Ok(())
    /// # }
    /// ```
    ///
    /// [`Event::GuildMembersChunk`]: ../../../model/event/enum.Event.html#variant.GuildMembersChunk
    /// [`Guild`]: ../../../model/guild/struct.Guild.html
    /// [`Member`]: ../../../model/guild/struct.Member.html
    pub fn chunk_guilds<It>(
        &self,
        guild_ids: It,
        limit: Option<u16>,
        query: Option<String>,
    ) where It: IntoIterator<Item=GuildId> {
        let guilds = guild_ids.into_iter().collect::<Vec<GuildId>>();

        let _ = self.send_to_shard(ShardRunnerMessage::ChunkGuilds {
            guild_ids: guilds,
            limit,
            query,
        });
    }

    /// Sets the user's current activity, if any.
    ///
    /// Other presence settings are maintained.
    ///
    /// # Examples
    ///
    /// Setting the current activity to playing `"Heroes of the Storm"`:
    ///
    /// ```rust,no_run
    /// # use tokio::sync::Mutex;
    /// # use serenity::gateway::Shard;
    /// # use std::sync::Arc;
    /// #
    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
    /// #     let mutex = Arc::new(Mutex::new("".to_string()));
    /// #
    /// #     let mut shard = Shard::new(mutex.clone(), "", [0u64, 1u64], true, None).await?;
    /// use serenity::model::gateway::Activity;
    ///
    /// shard.set_activity(Some(Activity::playing("Heroes of the Storm")));
    /// #     Ok(())
    /// # }
    /// ```
    pub fn set_activity(&self, activity: Option<Activity>) {
        let _ = self.send_to_shard(ShardRunnerMessage::SetActivity(activity));
    }

    /// Sets the user's full presence information.
    ///
    /// Consider using the individual setters if you only need to modify one of
    /// these.
    ///
    /// # Examples
    ///
    /// Set the current user as playing `"Heroes of the Storm"` and being
    /// online:
    ///
    /// ```rust,ignore
    /// # use tokio::sync::Mutex;
    /// # use serenity::gateway::Shard;
    /// # use std::sync::Arc;
    /// #
    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
    /// #     let mutex = Arc::new(Mutex::new("".to_string()));
    /// #
    /// #     let mut shard = Shard::new(mutex.clone(), "", [0u64, 1u64], true, None).await?;
    /// #
    /// use serenity::model::gateway::Activity;
    /// use serenity::model::user::OnlineStatus;
    ///
    /// let activity = Activity::playing("Heroes of the Storm");
    /// shard.set_presence(Some(activity), OnlineStatus::Online);
    /// #     Ok(())
    /// # }
    /// ```
    pub fn set_presence(&self, activity: Option<Activity>, mut status: OnlineStatus) {
        if status == OnlineStatus::Offline {
            status = OnlineStatus::Invisible;
        }

        let _ = self.send_to_shard(ShardRunnerMessage::SetPresence(status, activity));
    }

    /// Sets the user's current online status.
    ///
    /// Note that [`Offline`] is not a valid online status, so it is
    /// automatically converted to [`Invisible`].
    ///
    /// Other presence settings are maintained.
    ///
    /// # Examples
    ///
    /// Setting the current online status for the shard to [`DoNotDisturb`].
    ///
    /// ```rust,no_run
    /// # use tokio::sync::Mutex;
    /// # use serenity::gateway::Shard;
    /// # use std::sync::Arc;
    /// #
    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
    /// #     let mutex = Arc::new(Mutex::new("".to_string()));
    /// #
    /// #     let mut shard = Shard::new(mutex.clone(), "", [0u64, 1u64], true, None).await?;
    /// #
    /// use serenity::model::user::OnlineStatus;
    ///
    /// shard.set_status(OnlineStatus::DoNotDisturb);
    /// #     Ok(())
    /// # }
    /// ```
    ///
    /// [`DoNotDisturb`]: ../../../model/user/enum.OnlineStatus.html#variant.DoNotDisturb
    /// [`Invisible`]: ../../../model/user/enum.OnlineStatus.html#variant.Invisible
    /// [`Offline`]: ../../../model/user/enum.OnlineStatus.html#variant.Offline
    pub fn set_status(&self, mut online_status: OnlineStatus) {
        if online_status == OnlineStatus::Offline {
            online_status = OnlineStatus::Invisible;
        }

        let _ = self.send_to_shard(ShardRunnerMessage::SetStatus(online_status));
    }

    /// Shuts down the websocket by attempting to cleanly close the
    /// connection.
    pub fn shutdown_clean(&self) {
        let _ = self.send_to_shard(ShardRunnerMessage::Close(1000, None));
    }

    /// Sends a raw message over the WebSocket.
    ///
    /// The given message is not mutated in any way, and is sent as-is.
    ///
    /// You should only use this if you know what you're doing. If you're
    /// wanting to, for example, send a presence update, prefer the usage of
    /// the [`set_presence`] method.
    ///
    /// [`set_presence`]: #method.set_presence
    pub fn websocket_message(&self, message: Message) {
        let _ = self.send_to_shard(ShardRunnerMessage::Message(message));
    }

    /// Sends a message to the shard.
    #[inline]
    pub fn send_to_shard(&self, msg: ShardRunnerMessage)
        -> Result<(), TrySendError<InterMessage>> {
        self.tx.unbounded_send(InterMessage::Client(Box::new(ShardClientMessage::Runner(msg))))
    }

    /// Sets a new filter for a message collector.
    #[inline]
    #[cfg(feature = "collector")]
    pub fn set_message_filter(&self, collector: MessageFilter) {
        let _ = self.send_to_shard(ShardRunnerMessage::SetMessageFilter(collector));
    }

    /// Sets a new filter for a message collector.
    #[cfg(feature = "collector")]
    pub fn set_reaction_filter(&self, collector: ReactionFilter) {
        let _ = self.send_to_shard(ShardRunnerMessage::SetReactionFilter(collector));
    }
}

impl AsRef<ShardMessenger> for ShardMessenger {
    fn as_ref(&self) -> &ShardMessenger {
        self
    }
}
<|endoftext|>


<commit_before>use std::collections::VecDeque;
use std::fmt;
use std::time::Instant;

use cpupool::CpuPool;
use futures::{
    Async,
    AsyncSink,
    Future,
    Poll,
    Sink,
    Stream,
};
use futures::sync::{mpsc, oneshot};
use itertools::Itertools;
use prost::Message;
use tokio::reactor::{
    Handle,
    Remote,
};

use Call;
use Error;
use HostPort;
use Options;
use Rpc;
use RpcFuture;
use connection::Connection;
use connector::Connector;

#[derive(Clone)]
pub struct Proxy {
    sender: mpsc::Sender<Rpc>,
}

impl Proxy {

    pub fn spawn(hostports: Box<[HostPort]>,
                 options: Options,
                 threadpool: CpuPool,
                 remote: &Remote)
                 -> Proxy {
        let (sender, receiver) = mpsc::channel(options.max_rpcs_in_flight as usize);
        remote.spawn(move |handle| ProxyTask {
            hostports,
            options,
            threadpool,
            handle: handle.clone(),
            receiver,
            connection_state: ConnectionState::Quiesced,
            buffer: VecDeque::new(),
        });
        Proxy { sender }
    }

    /// Polls the proxy to determine if there is guaranteed to be capacity to send at least one
    /// RPC without waiting.
    ///
    /// Returns `Async::Ready(_)` if there is sufficient capacity, or returns `Async::NotReady` if
    /// the proxy is not guaranteed to have capacity.
    ///
    /// This method may only be called from inside the context of a task or future.
    pub fn poll_ready(&mut self) -> Async<()> {
        match self.sender.poll_ready() {
            Ok(async) => async,
            Err(_) => unreachable!(),
        }
    }

    /// Call a remote method asynchronously.
    ///
    /// Typically users will not call this directly, but rather through a generated service trait
    /// implemented by `Proxy`.
    pub fn send<Req, Resp>(&mut self, call: Call<Req, Resp>) -> RpcFuture<Resp>
    where Req: Message + 'static,
          Resp: Message + Default {

        let (completer, receiver) = oneshot::channel();
        let rpc = Rpc {
            service: call.service,
            method: call.method,
            required_feature_flags: call.required_feature_flags,
            timestamp: Instant::now(),
            deadline: call.deadline,
            request: call.request,
            completer,
        };

        match self.sender.start_send(rpc) {
            Ok(AsyncSink::Ready) => (),
            Ok(AsyncSink::NotReady(_)) => panic!("Proxy not ready"),
            Err(..) => unreachable!(),
        }

        RpcFuture::new(receiver)
    }
}

enum ConnectionState {
    Quiesced,
    Connecting(Connector),
    Connected(Connection),
}

impl fmt::Debug for ConnectionState {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ConnectionState::Quiesced => write!(f, "Quiesced"),
            ConnectionState::Connecting(_) => write!(f, "Connecting"),
            ConnectionState::Connected(ref connection) => connection.fmt(f),
        }
    }
}

struct ProxyTask {
    hostports: Box<[HostPort]>,
    options: Options,
    threadpool: CpuPool,
    handle: Handle,
    receiver: mpsc::Receiver<Rpc>,
    connection_state: ConnectionState,
    buffer: VecDeque<Rpc>,
}

impl Future for ProxyTask {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        trace!("{:?}: poll", self);

        let now = Instant::now();

        // NLL hack.
        let ProxyTask { ref hostports,
                        ref options,
                        ref threadpool,
                        ref handle,
                        ref mut receiver,
                        ref mut connection_state,
                        ref mut buffer } = *self;

        use self::ConnectionState::*;
        loop {
            let state = match *connection_state {
                Quiesced => {
                    // Create a new connection if there are buffered or queued RPCs.
                    if buffer.is_empty() {
                        match try_ready!(receiver.poll()) {
                            Some(rpc) => buffer.push_back(rpc),
                            // No more senders; shutdown.
                            None => return Ok(Async::Ready(())),
                        }
                    }

                    Connecting(Connector::connect(hostports,
                                                  threadpool,
                                                  handle.clone(),
                                                  options.clone()))
                },
                Connecting(ref mut connector) => {
                    match connector.poll() {
                        Ok(Async::Ready(connection)) => Connected(connection),
                        Ok(Async::NotReady) => return Ok(Async::NotReady),
                        Err(error) => {
                            // Connecting to the server failed. Fail all buffered and queued
                            // RPCs, and return to the quiesced state.
                            for rpc in buffer.drain(..) {
                                rpc.fail(error.clone());
                            }
                            while let Ok(Async::Ready(Some(rpc))) = receiver.poll() {
                                rpc.fail(error.clone());
                            }
                            Quiesced
                        }
                    }
                },
                Connected(ref mut conn) => {

                    // Send all buffered and queued RPCs. The result of the loop is ok if either
                    // the connection has no more send capacity, or there are no more messages to
                    // send.  If any message fails to send, the result of the loop is the error.
                    let send_result: Result<(), ()> = loop {
                        match conn.poll_ready(now) {

                            // The connection has capacity to send an RPC.
                            Ok(Async::Ready(_)) => {

                                // Take an RPC from the buffer or queue.
                                let rpc = buffer.pop_front()
                                                .map(|rpc| Ok(Async::Ready(Some(rpc))))
                                                .unwrap_or_else(|| receiver.poll())?;

                                match rpc {
                                    // Attempt to send the RPC.
                                    Async::Ready(Some(rpc)) => match conn.send(rpc, now) {
                                        Ok(()) => continue,
                                        error => break error,
                                    },

                                    // No more senders; shutdown if there are no in-flight RPCs.
                                    Async::Ready(None) => if conn.in_flight_rpcs().is_empty() {
                                        return Ok(Async::Ready(()));
                                    } else {
                                        break Ok(());
                                    },

                                    // No messages to send.
                                    Async::NotReady => break Ok(()),
                                }
                            },

                            // The connection has no remaining capacity.
                            Ok(Async::NotReady) => break Ok(()),

                            // The connection is shutdown.
                            Err(()) => break Err(()),
                        }
                    };

                    // Poll the connection in order to complete in-flight RPCs.
                    match send_result.and_then(|_| conn.poll(now)) {
                        Ok(_) => return Ok(Async::NotReady),
                        Err(_) => {
                            buffer.extend(
                                conn.in_flight_rpcs()
                                    .drain()
                                    .map(|(_, rpc)| rpc)
                                    .flat_map(|rpc| {
                                        if rpc.is_canceled() {
                                            None
                                        } else if rpc.is_timed_out(now) {
                                            rpc.fail(Error::TimedOut);
                                            None
                                        } else {
                                            Some(rpc)
                                        }
                                    }));
                            ConnectionState::Quiesced
                        },
                    }
                },
            };
            *connection_state = state;
        }
    }
}

impl fmt::Debug for ProxyTask {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut debug = f.debug_struct("ProxyTask");
        debug.field("hostports", &format_args!("{:?}", &self.hostports.iter().format(",")));
        debug.field("core", &self.handle.id());
        match self.connection_state {
            ConnectionState::Quiesced => debug.field("state", &self.connection_state),
            ConnectionState::Connecting(_) => debug.field("state", &self.connection_state),
            ConnectionState::Connected(ref connection) => debug.field("connection", connection),
        };
        debug.finish()
    }
}
<commit_msg>add docs to proxy<commit_after>use std::collections::VecDeque;
use std::fmt;
use std::time::Instant;

use cpupool::CpuPool;
use futures::{
    Async,
    AsyncSink,
    Future,
    Poll,
    Sink,
    Stream,
};
use futures::sync::{mpsc, oneshot};
use itertools::Itertools;
use prost::Message;
use tokio::reactor::{
    Handle,
    Remote,
};

use Call;
use Error;
use HostPort;
use Options;
use Rpc;
use RpcFuture;
use connection::Connection;
use connector::Connector;

/// `Proxy` is a handle to a remote server which allows clients to send and recieve RPCs.
#[derive(Clone)]
pub struct Proxy {
    sender: mpsc::Sender<Rpc>,
}

impl Proxy {

    pub fn spawn(hostports: Box<[HostPort]>,
                 options: Options,
                 threadpool: CpuPool,
                 remote: &Remote)
                 -> Proxy {
        let (sender, receiver) = mpsc::channel(options.max_rpcs_in_flight as usize);
        remote.spawn(move |handle| ProxyTask {
            hostports,
            options,
            threadpool,
            handle: handle.clone(),
            receiver,
            connection_state: ConnectionState::Quiesced,
            buffer: VecDeque::new(),
        });
        Proxy { sender }
    }

    /// Polls the proxy to determine if there is guaranteed to be capacity to send at least one
    /// RPC without waiting.
    ///
    /// Returns `Async::Ready(_)` if there is sufficient capacity, or returns `Async::NotReady` if
    /// the proxy is not guaranteed to have capacity.
    ///
    /// This method may only be called from inside the context of a task or future.
    pub fn poll_ready(&mut self) -> Async<()> {
        match self.sender.poll_ready() {
            Ok(async) => async,
            Err(_) => unreachable!(),
        }
    }

    /// Call a remote method asynchronously.
    ///
    /// Typically users will not call this directly, but rather through a generated service trait
    /// implemented by `Proxy`.
    pub fn send<Req, Resp>(&mut self, call: Call<Req, Resp>) -> RpcFuture<Resp>
    where Req: Message + 'static,
          Resp: Message + Default {

        let (completer, receiver) = oneshot::channel();
        let rpc = Rpc {
            service: call.service,
            method: call.method,
            required_feature_flags: call.required_feature_flags,
            timestamp: Instant::now(),
            deadline: call.deadline,
            request: call.request,
            completer,
        };

        match self.sender.start_send(rpc) {
            Ok(AsyncSink::Ready) => (),
            Ok(AsyncSink::NotReady(_)) => panic!("Proxy not ready"),
            Err(..) => unreachable!(),
        }

        RpcFuture::new(receiver)
    }
}

/// `ConnectionState` is a state-machine which drives the `ProxyTask`.
///
/// ## States
///
/// - Quiesced
///     The initial state. The `Quiesced` state is used when the proxy is not connected to the
///     remote server. When the task has buffered RPCs, or when an RPC is received from the
///     channel, the task transitions to `Connecting`.
/// - Connecting
///     The task is attempting to connect to the remote server. No RPCs are received from the RPC
///     channel while connecting, so senders will (eventually) encounter backpressure.
/// - `Connected`
///     RPCs are received from the channel and forwarded to the connection, as connection capacity
///     permits. If a fatal RPC error occurs, all non-failed in-flight RPCs are buffered
///     internally, and the task transitions to `Quiesced`.
/// - `Failed`
///     When connecting to the remote server fails, the task is put into the `Failed` state. All
///     buffered RPCs and RPCs received from the channel are immediately failed. After waiting for
///     a backoff timeout period, the task will transition back to `Quiesced`.
///
/// ## State Diagram
///
/// ```
///               +--------------+
///               |              |
///         +-----+    Failed    <-----+
///         |     |              |     |
///        e|     +--------------+     |c
///         |                          |
///         |                          |
///  +------v-------+          +-------+------+
///  |              |    a     |              |
///  |   Quiesced   +---------->  Connecting  |
///  |              |          |              |
///  +------^-------+          +-------+------+
///         |                          |
///         |                          |
///        d|     +--------------+     |b
///         |     |              |     |
///         +-----+  Connected   < ----+
///               |              |
///               +--------------+
/// ```
///
/// ## State Transitions
///
/// |   | current state | event            | next state   | actions                          |
/// | - | ------------- | ---------------- | ------------ | -------------------------------- |
/// | a | `Quiesced`    | RPC enqueued     | `Connecting` | create a new `Connector`         |
/// | b | `Connecting`  | connect succeeds | `Connected`  |                                  |
/// | c | `Connecting`  | connect fails    | `Failed`     | fail buffered RPCs               |
/// | d | `Connected`   | fatal RPC error  | `Quiesced`   | buffer non-failed in-flight RPCs |
/// | e | `Failed`      | backoff elapsed  | `Quiesced`   |                                  |
///
/// TODO: add the Failed state.
enum ConnectionState {
    Quiesced,
    Connecting(Connector),
    Connected(Connection),
}

impl fmt::Debug for ConnectionState {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ConnectionState::Quiesced => write!(f, "Quiesced"),
            ConnectionState::Connecting(_) => write!(f, "Connecting"),
            ConnectionState::Connected(ref connection) => connection.fmt(f),
        }
    }
}

/// `ProxyTask` is a task which manages the lifecycle of TCP connections to a remote server.
///
///
/// `ProxyTask` handles reconnections, buffering, will automatically attempt to reconnect to the
/// remote server, buffer RPCs while reconnecting (when appropriate).
struct ProxyTask {
    hostports: Box<[HostPort]>,
    options: Options,
    threadpool: CpuPool,
    handle: Handle,
    receiver: mpsc::Receiver<Rpc>,
    connection_state: ConnectionState,
    buffer: VecDeque<Rpc>,
}

impl Future for ProxyTask {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        trace!("{:?}: poll", self);

        let now = Instant::now();

        // NLL hack.
        let ProxyTask { ref hostports,
                        ref options,
                        ref threadpool,
                        ref handle,
                        ref mut receiver,
                        ref mut connection_state,
                        ref mut buffer } = *self;

        use self::ConnectionState::*;
        loop {
            let state = match *connection_state {
                Quiesced => {
                    // Create a new connection if there are buffered or queued RPCs.
                    if buffer.is_empty() {
                        match try_ready!(receiver.poll()) {
                            Some(rpc) => buffer.push_back(rpc),
                            // No more senders; shutdown.
                            None => return Ok(Async::Ready(())),
                        }
                    }

                    Connecting(Connector::connect(hostports,
                                                  threadpool,
                                                  handle.clone(),
                                                  options.clone()))
                },
                Connecting(ref mut connector) => {
                    match connector.poll() {
                        Ok(Async::Ready(connection)) => Connected(connection),
                        Ok(Async::NotReady) => return Ok(Async::NotReady),
                        Err(error) => {
                            // Connecting to the server failed. Fail all buffered and queued
                            // RPCs, and return to the quiesced state.
                            for rpc in buffer.drain(..) {
                                rpc.fail(error.clone());
                            }
                            while let Ok(Async::Ready(Some(rpc))) = receiver.poll() {
                                rpc.fail(error.clone());
                            }
                            Quiesced
                        }
                    }
                },
                Connected(ref mut conn) => {

                    // Send all buffered and queued RPCs. The result of the loop is ok if either
                    // the connection has no more send capacity, or there are no more messages to
                    // send.  If any message fails to send, the result of the loop is the error.
                    let send_result: Result<(), ()> = loop {
                        match conn.poll_ready(now) {

                            // The connection has capacity to send an RPC.
                            Ok(Async::Ready(_)) => {

                                // Take an RPC from the buffer or queue.
                                let rpc = buffer.pop_front()
                                                .map(|rpc| Ok(Async::Ready(Some(rpc))))
                                                .unwrap_or_else(|| receiver.poll())?;

                                match rpc {
                                    // Attempt to send the RPC.
                                    Async::Ready(Some(rpc)) => match conn.send(rpc, now) {
                                        Ok(()) => continue,
                                        error => break error,
                                    },

                                    // No more senders; shutdown if there are no in-flight RPCs.
                                    Async::Ready(None) => if conn.in_flight_rpcs().is_empty() {
                                        return Ok(Async::Ready(()));
                                    } else {
                                        break Ok(());
                                    },

                                    // No messages to send.
                                    Async::NotReady => break Ok(()),
                                }
                            },

                            // The connection has no remaining capacity.
                            Ok(Async::NotReady) => break Ok(()),

                            // The connection is shutdown.
                            Err(()) => break Err(()),
                        }
                    };

                    // Poll the connection in order to complete in-flight RPCs.
                    match send_result.and_then(|_| conn.poll(now)) {
                        Ok(_) => return Ok(Async::NotReady),
                        Err(_) => {
                            buffer.extend(
                                conn.in_flight_rpcs()
                                    .drain()
                                    .map(|(_, rpc)| rpc)
                                    .flat_map(|rpc| {
                                        if rpc.is_canceled() {
                                            None
                                        } else if rpc.is_timed_out(now) {
                                            rpc.fail(Error::TimedOut);
                                            None
                                        } else {
                                            Some(rpc)
                                        }
                                    }));
                            ConnectionState::Quiesced
                        },
                    }
                },
            };
            *connection_state = state;
        }
    }
}

impl fmt::Debug for ProxyTask {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut debug = f.debug_struct("ProxyTask");
        debug.field("hostports", &format_args!("{:?}", &self.hostports.iter().format(",")));
        debug.field("core", &self.handle.id());
        match self.connection_state {
            ConnectionState::Quiesced => debug.field("state", &self.connection_state),
            ConnectionState::Connecting(_) => debug.field("state", &self.connection_state),
            ConnectionState::Connected(ref connection) => debug.field("connection", connection),
        };
        debug.finish()
    }
}
<|endoftext|>


<commit_before>use criterion::{criterion_group, criterion_main, Criterion};
use nibble_vec::NibbleVec;

fn v8_7_6_5() -> NibbleVec {
    NibbleVec::from_byte_vec(vec![8 << 4 | 7, 6 << 4 | 5])
}

fn v11_10_9() -> NibbleVec {
    let mut result = NibbleVec::from_byte_vec(vec![11 << 4 | 10]);
    result.push(9);
    result
}

fn split_test(nibble_vec: &NibbleVec, idx: usize, first: Vec<u8>, second: Vec<u8>) {
    let mut init = nibble_vec.clone();
    let tail = init.split(idx);
    assert!(init == first[..]);
    assert!(tail == second[..]);
}

fn nib_split_even(b: &mut Criterion) {
    let even_length = v8_7_6_5();
    b.bench_function("make nib vec", |b| b.iter(|| {
        split_test(&even_length, 1, vec![8], vec![7, 6, 5]);
        split_test(&even_length, 2, vec![8, 7], vec![6, 5]);
    }));
}

fn nib_make_split(b: &mut Criterion) {
    b.bench_function("nib_make_split", |b| {
        b.iter(|| {
            let odd_length = v11_10_9();
            split_test(&odd_length, 0, vec![], vec![11, 10, 9]);
            split_test(&odd_length, 1, vec![11], vec![10, 9]);
        })
    });
}

fn join_test(vec1: &NibbleVec, vec2: &NibbleVec, result: Vec<u8>) {
    let joined = vec1.clone().join(vec2);
    assert!(joined == result[..]);
}

fn nib_join_test(b: &mut Criterion) {
    b.bench_function("trie remove", |b| {
        b.iter(|| {
            let v1 = v8_7_6_5();
            let v2 = v11_10_9();
            join_test(&v1, &v2, vec![8, 7, 6, 5, 11, 10, 9]);
            join_test(&v1, &v1, vec![8, 7, 6, 5, 8, 7, 6, 5]);
        });
    });
}

criterion_group!(benches, nib_split_even, nib_make_split, nib_join_test);
criterion_main!(benches);
<commit_msg>test perf of smallvec<commit_after>use criterion::{criterion_group, criterion_main, Criterion};
use nibble_vec::NibbleVec;

fn even_8to5() -> NibbleVec {
    NibbleVec::from_byte_vec(vec![8 << 4 | 7, 6 << 4 | 5])
}

fn odd_11to9() -> NibbleVec {
    let mut result = NibbleVec::from_byte_vec(vec![11 << 4 | 10]);
    result.push(9);
    result
}

fn split_test(nibble_vec: &NibbleVec, idx: usize) {
    let mut init = nibble_vec.clone();
    let _tail = init.split(idx);
}

fn nib_split_even(b: &mut Criterion) {
    let even_length = even_8to5();
    b.bench_function("make nib vec", |b| b.iter(|| {
        split_test(&even_length, 1);
        split_test(&even_length, 2);
    }));
}

fn nib_make_split(b: &mut Criterion) {
    b.bench_function("nib_make_split", |b| {
        b.iter(|| {
            let odd_length = odd_11to9();
            split_test(&odd_length, 0);
            split_test(&odd_length, 1);
        })
    });
}

fn nib_get(b: &mut Criterion) {
    b.bench_function("nib_make_split", |b| {
        let v = vec![243, 2, 3, 251, 5, 6, 7, 8, 255];
        let nv = NibbleVec::from(v.clone());
        b.iter(|| {
            for (i, _) in v.iter().enumerate() {
                nv.get(i);
            }
        })
    });
}

fn join_test(vec1: &NibbleVec, vec2: &NibbleVec) {
    let _joined = vec1.clone().join(vec2);
}

fn nib_join_test(b: &mut Criterion) {
    b.bench_function("trie remove", |b| {
        b.iter(|| {
            let v1 = even_8to5();
            let v2 = odd_11to9();
            join_test(&v1, &v2);
            join_test(&v1, &v1);
        });
    });
}

criterion_group!(benches, nib_split_even, nib_make_split, nib_join_test, nib_get);
criterion_main!(benches);
<|endoftext|>


<commit_before>use Parameter;
use fa::{VFunction, Linear};
use agents::PredictionAgent;
use geometry::Space;
use std::marker::PhantomData;

pub struct GTD2<S: Space, V: VFunction<S> + Linear<S>>
{
    v_func: V,
    a_func: V,

    alpha: Parameter,
    beta: Parameter,
    gamma: Parameter,

    phantom: PhantomData<S>,
}

impl<S: Space, V> GTD2<S, V>
    where V: VFunction<S> + Linear<S>
{
    pub fn new<T1, T2, T3>(v_func: V, a_func: V,
                           alpha: T1, beta: T2, gamma: T3) -> Self
        where T1: Into<Parameter>,
              T2: Into<Parameter>,
              T3: Into<Parameter>
    {
        if !v_func.equivalent(&a_func) {
            panic!("v_func and a_func must be equivalent function approximators.")
        }

        GTD2 {
            v_func: v_func,
            a_func: a_func,

            alpha: alpha.into(),
            beta: beta.into(),
            gamma: gamma.into(),

            phantom: PhantomData,
        }
    }
}

impl<S: Space, V> PredictionAgent<S> for GTD2<S, V>
    where V: VFunction<S> + Linear<S>
{
    fn handle_transition(&mut self, s: &S::Repr, ns: &S::Repr, r: f64) -> Option<f64> {
        let phi_s = self.v_func.phi(s);
        let phi_ns = self.v_func.phi(ns);

        let td_error = r + self.gamma*self.v_func.evaluate_phi(&phi_ns) -
            self.v_func.evaluate_phi(&phi_s);
        let td_estimate = self.a_func.evaluate_phi(&phi_s);

        self.v_func.update_phi(&(&phi_s - &(self.gamma.value()*&phi_ns)), self.alpha*td_estimate);
        self.a_func.update_phi(&phi_s, self.beta*(td_error - td_estimate));

        Some(td_error)
    }

    fn handle_terminal(&mut self, _: &S::Repr) {
        self.alpha = self.alpha.step();
        self.beta = self.alpha.step();
        self.gamma = self.gamma.step();
    }
}

pub struct TDC<S: Space, V: VFunction<S> + Linear<S>>
{
    v_func: V,
    a_func: V,

    alpha: Parameter,
    beta: Parameter,
    gamma: Parameter,

    phantom: PhantomData<S>,
}

impl<S: Space, V> TDC<S, V>
    where V: VFunction<S> + Linear<S>
{
    pub fn new<T1, T2, T3>(v_func: V, a_func: V,
                           alpha: T1, beta: T2, gamma: T3) -> Self
        where T1: Into<Parameter>,
              T2: Into<Parameter>,
              T3: Into<Parameter>
    {
        if !v_func.equivalent(&a_func) {
            panic!("v_func and a_func must be equivalent function approximators.")
        }

        TDC {
            v_func: v_func,
            a_func: a_func,

            alpha: alpha.into(),
            beta: beta.into(),
            gamma: gamma.into(),

            phantom: PhantomData,
        }
    }
}

impl<S: Space, V> PredictionAgent<S> for TDC<S, V>
    where V: VFunction<S> + Linear<S>
{
    fn handle_transition(&mut self, s: &S::Repr, ns: &S::Repr, r: f64) -> Option<f64> {
        let phi_s = self.v_func.phi(s);
        let phi_ns = self.v_func.phi(ns);

        let td_error = r + self.gamma*self.v_func.evaluate_phi(&phi_ns) -
            self.v_func.evaluate_phi(&phi_s);
        let td_estimate = self.a_func.evaluate_phi(&phi_s);

        self.v_func.update_phi(&(&(td_error*&phi_s) - &(self.gamma.value()*td_estimate*&phi_ns)), self.alpha.value());
        self.a_func.update_phi(&phi_s, self.beta*(td_error - td_estimate));

        Some(td_error)
    }

    fn handle_terminal(&mut self, _: &S::Repr) {
        self.alpha = self.alpha.step();
        self.beta = self.alpha.step();
        self.gamma = self.gamma.step();
    }
}

<commit_msg>Remove trailing newline<commit_after>use Parameter;
use fa::{VFunction, Linear};
use agents::PredictionAgent;
use geometry::Space;
use std::marker::PhantomData;

pub struct GTD2<S: Space, V: VFunction<S> + Linear<S>>
{
    v_func: V,
    a_func: V,

    alpha: Parameter,
    beta: Parameter,
    gamma: Parameter,

    phantom: PhantomData<S>,
}

impl<S: Space, V> GTD2<S, V>
    where V: VFunction<S> + Linear<S>
{
    pub fn new<T1, T2, T3>(v_func: V, a_func: V,
                           alpha: T1, beta: T2, gamma: T3) -> Self
        where T1: Into<Parameter>,
              T2: Into<Parameter>,
              T3: Into<Parameter>
    {
        if !v_func.equivalent(&a_func) {
            panic!("v_func and a_func must be equivalent function approximators.")
        }

        GTD2 {
            v_func: v_func,
            a_func: a_func,

            alpha: alpha.into(),
            beta: beta.into(),
            gamma: gamma.into(),

            phantom: PhantomData,
        }
    }
}

impl<S: Space, V> PredictionAgent<S> for GTD2<S, V>
    where V: VFunction<S> + Linear<S>
{
    fn handle_transition(&mut self, s: &S::Repr, ns: &S::Repr, r: f64) -> Option<f64> {
        let phi_s = self.v_func.phi(s);
        let phi_ns = self.v_func.phi(ns);

        let td_error = r + self.gamma*self.v_func.evaluate_phi(&phi_ns) -
            self.v_func.evaluate_phi(&phi_s);
        let td_estimate = self.a_func.evaluate_phi(&phi_s);

        self.v_func.update_phi(&(&phi_s - &(self.gamma.value()*&phi_ns)), self.alpha*td_estimate);
        self.a_func.update_phi(&phi_s, self.beta*(td_error - td_estimate));

        Some(td_error)
    }

    fn handle_terminal(&mut self, _: &S::Repr) {
        self.alpha = self.alpha.step();
        self.beta = self.alpha.step();
        self.gamma = self.gamma.step();
    }
}

pub struct TDC<S: Space, V: VFunction<S> + Linear<S>>
{
    v_func: V,
    a_func: V,

    alpha: Parameter,
    beta: Parameter,
    gamma: Parameter,

    phantom: PhantomData<S>,
}

impl<S: Space, V> TDC<S, V>
    where V: VFunction<S> + Linear<S>
{
    pub fn new<T1, T2, T3>(v_func: V, a_func: V,
                           alpha: T1, beta: T2, gamma: T3) -> Self
        where T1: Into<Parameter>,
              T2: Into<Parameter>,
              T3: Into<Parameter>
    {
        if !v_func.equivalent(&a_func) {
            panic!("v_func and a_func must be equivalent function approximators.")
        }

        TDC {
            v_func: v_func,
            a_func: a_func,

            alpha: alpha.into(),
            beta: beta.into(),
            gamma: gamma.into(),

            phantom: PhantomData,
        }
    }
}

impl<S: Space, V> PredictionAgent<S> for TDC<S, V>
    where V: VFunction<S> + Linear<S>
{
    fn handle_transition(&mut self, s: &S::Repr, ns: &S::Repr, r: f64) -> Option<f64> {
        let phi_s = self.v_func.phi(s);
        let phi_ns = self.v_func.phi(ns);

        let td_error = r + self.gamma*self.v_func.evaluate_phi(&phi_ns) -
            self.v_func.evaluate_phi(&phi_s);
        let td_estimate = self.a_func.evaluate_phi(&phi_s);

        self.v_func.update_phi(&(&(td_error*&phi_s) - &(self.gamma.value()*td_estimate*&phi_ns)), self.alpha.value());
        self.a_func.update_phi(&phi_s, self.beta*(td_error - td_estimate));

        Some(td_error)
    }

    fn handle_terminal(&mut self, _: &S::Repr) {
        self.alpha = self.alpha.step();
        self.beta = self.alpha.step();
        self.gamma = self.gamma.step();
    }
}
<|endoftext|>


<commit_before>//! A demonstration of constructing and using a non-blocking stream.
//!
//! Audio from the default input device is passed directly to the default output device in a duplex
//! stream, so beware of feedback!

extern crate portaudio as pa;

use std::collections::HashMap;

const SAMPLE_RATE: f64 = 44_100.0;
const FRAMES: u32 = 256;
const CHANNELS: i32 = 2;
const INTERLEAVED: bool = true;

lazy_static! {
    static ref port_audio: pa::PortAudio = {
        let pa = pa::PortAudio::new();
        match pa
        {
            Result::Ok(val) => val,
            Result::Err(err) =>
              panic!("called `Result::unwrap()` on an `Err` value: {:?}", err),
        }
    };
}

pub fn init()
{

}

pub fn get_devices<'a>() -> Result<HashMap<i32, (&'a str, i32)>, pa::Error> {
    let mut devices = HashMap::new();

    let default_host = try!(port_audio.default_host_api());

    for i in 0..port_audio.host_api_info(default_host).unwrap().device_count
    {
        let device_index = try!(port_audio.api_device_index_to_device_index(default_host, i as i32));
        let input_info = try!(port_audio.device_info(device_index));

        devices.insert(device_index.0 as i32, (input_info.name,
            input_info.max_input_channels));
    }

    return Ok(devices);
}

pub fn get_rms(device: i32, rms_callback: fn(f32) -> ()) -> Result<(), pa::Error> {
    let device_info = try!(port_audio.device_info(pa::DeviceIndex{0: device as u32}));

    let input_params = pa::StreamParameters::<f32>::new(pa::DeviceIndex{0: device as u32},
        device_info.max_input_channels,
        INTERLEAVED,
        0.0f64);

    let audio_callback = move |pa::InputStreamCallbackArgs { buffer, frames, time, .. }| {
        //let current_time = time.current;

        let mut square_sum = 0.0f32;
        for x in 0..buffer.len()
        {
            square_sum += buffer[x] * buffer[x];
        }

        let square_mean = square_sum * 1.0f32/buffer.len() as f32;

        let rms = f32::sqrt(square_mean);

        println!("Total rms: {}", rms);

        assert!(frames == FRAMES as usize);

        pa::Continue
    };

    let settings = pa::InputStreamSettings::new(input_params, SAMPLE_RATE, FRAMES);
    let mut stream = try!(port_audio.open_non_blocking_stream(settings, audio_callback));
    println!("Starting stream..");
    try!(stream.start());

    while let true = try!(stream.is_active()) {
        }

    port_audio.is_input_format_supported(input_params, SAMPLE_RATE)
}

pub fn run() -> Result<(), pa::Error> {

    println!("PortAudio:");
    println!("version: {}", port_audio.version());
    println!("version text: {:?}", port_audio.version_text());
    println!("host count: {}", try!(port_audio.host_api_count()));

    let default_host = try!(port_audio.default_host_api());
    println!("default host: {:#?}", port_audio.host_api_info(default_host));

    let def_input = try!(port_audio.default_input_device());
    let input_info = try!(port_audio.device_info(def_input));
    println!("Default input device info: {:#?}", &input_info);

    // Construct the input stream parameters.
    let latency = input_info.default_low_input_latency;
    let input_params = pa::StreamParameters::<f32>::new(def_input, CHANNELS, INTERLEAVED, latency);

    let def_output = try!(port_audio.default_output_device());
    let output_info = try!(port_audio.device_info(def_output));
    println!("Default output device info: {:#?}", &output_info);

    // Construct the output stream parameters.
    let latency = output_info.default_low_output_latency;
    let output_params = pa::StreamParameters::new(def_output, CHANNELS, INTERLEAVED, latency);

    // Check that the stream format is supported.
    try!(port_audio.is_duplex_format_supported(input_params, output_params, SAMPLE_RATE));

    // Construct the settings with which we'll open our duplex stream.
    let settings = pa::DuplexStreamSettings::new(input_params, output_params, SAMPLE_RATE, FRAMES);

    // Once the countdown reaches 0 we'll close the stream.
    let mut count_down = 1.0;

    // Keep track of the last `current_time` so we can calculate the delta time.
    let mut maybe_last_time = None;

    // We'll use this channel to send the count_down to the main thread for fun.
    let (sender, receiver) = ::std::sync::mpsc::channel();

    // A callback to pass to the non-blocking stream.
    let callback = move |pa::DuplexStreamCallbackArgs { in_buffer, out_buffer, frames, time, .. }| {
        let current_time = time.current;
        let prev_time = maybe_last_time.unwrap_or(current_time);
        let dt = current_time - prev_time;
        count_down -= dt;
        maybe_last_time = Some(current_time);

        assert!(frames == FRAMES as usize);
        sender.send(count_down).ok();

        // Pass the input straight to the output - BEWARE OF FEEDBACK!
        for (output_sample, input_sample) in out_buffer.iter_mut().zip(in_buffer.iter()) {
            *output_sample = *input_sample;
        }

        if count_down > 0.0 { pa::Continue } else { pa::Complete }
    };

    // Construct a stream with input and output sample types of f32.
    let mut stream = try!(port_audio.open_non_blocking_stream(settings, callback));

    try!(stream.start());

    // Loop while the non-blocking stream is active.
    while let true = try!(stream.is_active()) {

        // Do some stuff!
        while let Ok(count_down) = receiver.try_recv() {
            println!("count_down: {:?}", count_down);
        }

    }

    try!(stream.stop());

    Ok(())
}<commit_msg>Created analysis graph struct<commit_after>//! A demonstration of constructing and using a non-blocking stream.
//!
//! Audio from the default input device is passed directly to the default output device in a duplex
//! stream, so beware of feedback!

extern crate portaudio as pa;

use std::collections::HashMap;
use std::cell::RefCell;
use std::rc::Rc;

const SAMPLE_RATE: f64 = 44_100.0;
const FRAMES: u32 = 256;
const CHANNELS: i32 = 2;
const INTERLEAVED: bool = true;

lazy_static! {
    static ref port_audio: pa::PortAudio = {
        let pa = pa::PortAudio::new();
        match pa
        {
            Result::Ok(val) => val,
            Result::Err(err) =>
              panic!("called `Result::unwrap()` on an `Err` value: {:?}", err),
        }
    };
}

struct AArena{
    pub sourcables: HashMap<u64, Box<Sourcable>>,
    pub chainables: HashMap<u64, Box<Chainable>>
}

trait Sourcable {
    fn start(&self, chain: Rc<RefCell<AChain>>);
    fn stop(&self);
}

trait Chainable {

}

struct AChain {
    arena: Rc<AArena>,

    source: u64,
    nodes: Vec<u64>,
}

impl AChain {
    pub fn source_cb(&self, buffer: &[f32], frames: usize)
    {
        for i in 0..self.nodes.len()
        {

        }
    }
}

struct PASource {
    device: u32,
    channels: Vec<u32>,
}

impl Sourcable for PASource {
    fn start(&self, chain: Rc<RefCell<AChain>>) -> () {
        let device_info = port_audio.device_info(pa::DeviceIndex{0: self.device}).unwrap();

        let input_params = pa::StreamParameters::<f32>::new(pa::DeviceIndex{0: self.device},
            device_info.max_input_channels,
            false,
            0.0f64);

        let audio_callback = move |pa::InputStreamCallbackArgs {mut buffer, frames, time, .. }| {
            (*chain.borrow_mut()).source_cb(buffer, frames);

            pa::Continue
        };

        let settings = pa::InputStreamSettings::new(input_params, SAMPLE_RATE, FRAMES);
        let mut stream = port_audio.open_non_blocking_stream(settings, audio_callback).unwrap();
        println!("Starting stream..");
        let _ = stream.start();
    }
    fn stop(&self) -> () {
    }
}

pub fn init()
{

}

pub fn get_devices<'a>() -> Result<HashMap<i32, (&'a str, i32)>, pa::Error> {
    let mut devices = HashMap::new();

    let default_host = try!(port_audio.default_host_api());

    for i in 0..port_audio.host_api_info(default_host).unwrap().device_count
    {
        let device_index = try!(port_audio.api_device_index_to_device_index(default_host, i as i32));
        let input_info = try!(port_audio.device_info(device_index));

        devices.insert(device_index.0 as i32, (input_info.name,
            input_info.max_input_channels));
    }

    return Ok(devices);
}

// WIP. Opens stream and all that. Not part of the proper analysis chain structure.
pub fn get_rms(device: u32, rms_callback: fn(f32) -> ()) -> Result<(), pa::Error> {
    let device_info = try!(port_audio.device_info(pa::DeviceIndex{0: device}));

    let input_params = pa::StreamParameters::<f32>::new(pa::DeviceIndex{0: device},
        device_info.max_input_channels,
        false,
        0.0f64);

    let audio_callback = move |pa::InputStreamCallbackArgs {mut buffer, frames, time, .. }| {
        //let current_time = time.current;
        let mut square_sum = 0.0f32;
        for x in 0..buffer.len()
        {
            square_sum += buffer[x] * buffer[x];
        }

        let square_mean = square_sum * 1.0f32/buffer.len() as f32;

        let rms = f32::sqrt(square_mean);

        println!("Total rms: {}", rms);

        assert!(frames == FRAMES as usize);

        pa::Continue
    };

    let settings = pa::InputStreamSettings::new(input_params, SAMPLE_RATE, FRAMES);
    let mut stream = try!(port_audio.open_non_blocking_stream(settings, audio_callback));
    println!("Starting stream..");
    try!(stream.start());

    while let true = try!(stream.is_active()) {

    }

    port_audio.is_input_format_supported(input_params, SAMPLE_RATE)
}

// Test function, please ignore.
pub fn run() -> Result<(), pa::Error> {

    println!("PortAudio:");
    println!("version: {}", port_audio.version());
    println!("version text: {:?}", port_audio.version_text());
    println!("host count: {}", try!(port_audio.host_api_count()));

    let default_host = try!(port_audio.default_host_api());
    println!("default host: {:#?}", port_audio.host_api_info(default_host));

    let def_input = try!(port_audio.default_input_device());
    let input_info = try!(port_audio.device_info(def_input));
    println!("Default input device info: {:#?}", &input_info);

    // Construct the input stream parameters.
    let latency = input_info.default_low_input_latency;
    let input_params = pa::StreamParameters::<f32>::new(def_input, CHANNELS, INTERLEAVED, latency);

    let def_output = try!(port_audio.default_output_device());
    let output_info = try!(port_audio.device_info(def_output));
    println!("Default output device info: {:#?}", &output_info);

    // Construct the output stream parameters.
    let latency = output_info.default_low_output_latency;
    let output_params = pa::StreamParameters::new(def_output, CHANNELS, INTERLEAVED, latency);

    // Check that the stream format is supported.
    try!(port_audio.is_duplex_format_supported(input_params, output_params, SAMPLE_RATE));

    // Construct the settings with which we'll open our duplex stream.
    let settings = pa::DuplexStreamSettings::new(input_params, output_params, SAMPLE_RATE, FRAMES);

    // Once the countdown reaches 0 we'll close the stream.
    let mut count_down = 1.0;

    // Keep track of the last `current_time` so we can calculate the delta time.
    let mut maybe_last_time = None;

    // We'll use this channel to send the count_down to the main thread for fun.
    let (sender, receiver) = ::std::sync::mpsc::channel();

    // A callback to pass to the non-blocking stream.
    let callback = move |pa::DuplexStreamCallbackArgs { in_buffer, out_buffer, frames, time, .. }| {
        let current_time = time.current;
        let prev_time = maybe_last_time.unwrap_or(current_time);
        let dt = current_time - prev_time;
        count_down -= dt;
        maybe_last_time = Some(current_time);

        assert!(frames == FRAMES as usize);
        sender.send(count_down).ok();

        // Pass the input straight to the output - BEWARE OF FEEDBACK!
        for (output_sample, input_sample) in out_buffer.iter_mut().zip(in_buffer.iter()) {
            *output_sample = *input_sample;
        }

        if count_down > 0.0 { pa::Continue } else { pa::Complete }
    };

    // Construct a stream with input and output sample types of f32.
    let mut stream = try!(port_audio.open_non_blocking_stream(settings, callback));

    try!(stream.start());

    // Loop while the non-blocking stream is active.
    while let true = try!(stream.is_active()) {

        // Do some stuff!
        while let Ok(count_down) = receiver.try_recv() {
            println!("count_down: {:?}", count_down);
        }

    }

    try!(stream.stop());

    Ok(())
}<|endoftext|>


<commit_before>#![feature(macro_rules, phase)]

extern crate collections;

// test harness access
#[cfg(test)]
extern crate test;
#[phase(syntax, link)]
extern crate log;

#[cfg(test)]
extern crate serialize;

pub mod de;
//pub mod json;

//#[cfg(test)]
//pub mod bench_bytes;

//#[cfg(test)]
//pub mod bench_enum;

#[cfg(test)]
pub mod bench_struct;

//#[cfg(test)]
//pub mod bench_vec;

#[cfg(test)]
pub mod bench_map;
<commit_msg>re-enable the vec benchmarks<commit_after>#![feature(macro_rules, phase)]

extern crate collections;

// test harness access
#[cfg(test)]
extern crate test;
#[phase(syntax, link)]
extern crate log;

#[cfg(test)]
extern crate serialize;

pub mod de;
//pub mod json;

//#[cfg(test)]
//pub mod bench_bytes;

//#[cfg(test)]
//pub mod bench_enum;

#[cfg(test)]
pub mod bench_struct;

#[cfg(test)]
pub mod bench_vec;

#[cfg(test)]
pub mod bench_map;
<|endoftext|>


<commit_before>//! Manager for XDG shell v6 client.

use libc;
use wayland_sys::server::WAYLAND_SERVER_HANDLE;
use wayland_sys::server::signal::wl_signal_add;
use wlroots_sys::{wlr_xdg_surface_v6, wlr_xdg_surface_v6_role::*};

use super::xdg_shell_v6_handler::XdgV6Shell;
use {Surface, SurfaceHandle, XdgV6Popup, XdgV6ShellHandler, XdgV6ShellState::*, XdgV6ShellSurface,
     XdgV6TopLevel};
use compositor::{Compositor, COMPOSITOR_PTR};

pub trait XdgV6ShellManagerHandler {
    /// Callback that is triggered when a new XDG shell v6 surface appears.
    fn new_surface(&mut self,
                   &mut Compositor,
                   &mut XdgV6ShellSurface,
                   &mut Surface)
                   -> Option<Box<XdgV6ShellHandler>>;

    /// Callback that is triggered when an XDG shell v6 surface is destroyed.
    fn surface_destroyed(&mut self, &mut Compositor, &mut XdgV6ShellSurface, &mut Surface);
}

wayland_listener!(XdgV6ShellManager, (Vec<Box<XdgV6Shell>>, Box<XdgV6ShellManagerHandler>), [
    add_listener => add_notify: |this: &mut XdgV6ShellManager, data: *mut libc::c_void,|
    unsafe {
        let remove_listener = this.remove_listener() as *mut _ as _;
        let (ref mut shells, ref mut manager) = this.data;
        let data = data as *mut wlr_xdg_surface_v6;
        wlr_log!(L_DEBUG, "New xdg_shell_v6_surface request {:p}", data);
        let compositor = &mut *COMPOSITOR_PTR;
        let mut surface = Surface::new((*data).surface);
        let state = unsafe {
            match (*data).role {
                WLR_XDG_SURFACE_V6_ROLE_NONE => None,
                WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL => {
                    let toplevel = (*data).__bindgen_anon_1.toplevel;
                    Some(TopLevel(XdgV6TopLevel::from_shell(data, toplevel)))
                }
                WLR_XDG_SURFACE_V6_ROLE_POPUP => {
                    let popup = (*data).__bindgen_anon_1.popup;
                    Some(Popup(XdgV6Popup::from_ptr(popup)))
                }
            }
        };
        let mut shell_surface = XdgV6ShellSurface::new(data, state);
        surface.set_lock(true);
        shell_surface.set_lock(true);
        let new_surface_res = manager.new_surface(compositor, &mut shell_surface, &mut surface);
        surface.set_lock(false);
        shell_surface.set_lock(false);
        if let Some(shell_surface_handler) = new_surface_res {

            let mut shell_surface = XdgV6Shell::new((shell_surface,
                                                     surface,
                                                     shell_surface_handler));

            // Hook the destroy event into this manager.
            wl_signal_add(&mut (*data).events.destroy as *mut _ as _,
                          remove_listener);

            // Hook the commit signal from the surface into the shell handler.
            wl_signal_add(&mut (*(*data).surface).events.commit as *mut _ as _,
                          shell_surface.commit_listener() as _);

            wl_signal_add(&mut (*data).events.ping_timeout as *mut _ as _,
                          shell_surface.ping_timeout_listener() as _);
            wl_signal_add(&mut (*data).events.new_popup as *mut _ as _,
                          shell_surface.new_popup_listener() as _);
            let events = match shell_surface.surface_mut().state() {
                None | Some(&mut Popup(_)) => None,
                Some(&mut TopLevel(ref mut toplevel)) => Some((*toplevel.as_ptr()).events)
            };
            if let Some(mut events) = events {
                wl_signal_add(&mut events.request_maximize as *mut _ as _,
                              shell_surface.maximize_listener() as _);
                wl_signal_add(&mut events.request_fullscreen as *mut _ as _,
                              shell_surface.fullscreen_listener() as _);
                wl_signal_add(&mut events.request_minimize as *mut _ as _,
                              shell_surface.minimize_listener() as _);
                wl_signal_add(&mut events.request_move as *mut _ as _,
                              shell_surface.move_listener() as _);
                wl_signal_add(&mut events.request_resize as *mut _ as _,
                              shell_surface.resize_listener() as _);
                wl_signal_add(&mut events.request_show_window_menu as *mut _ as _,
                              shell_surface.show_window_menu_listener() as _);
            }

            shells.push(shell_surface);
        }
    };
    remove_listener => remove_notify: |this: &mut XdgV6ShellManager, data: *mut libc::c_void,|
    unsafe {
        let (ref mut shells, ref mut manager) = this.data;
        let data = data as *mut wlr_xdg_surface_v6;
        let mut surface = SurfaceHandle::from_ptr((*data).surface);
        let compositor = &mut *COMPOSITOR_PTR;
        if let Some(shell) = shells.iter_mut().find(|shell| shell.surface_ptr() == data) {
            let mut shell_surface = shell.surface_mut();
            shell_surface.set_lock(true);
            surface.run(|mut surface| {
                manager.surface_destroyed(compositor, &mut shell_surface, &mut surface);
            }).expect("Surface was invalid")
        }
        if let Some(index) = shells.iter().position(|shell| shell.surface_ptr() == data) {
            let mut removed_shell = shells.remove(index);
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*removed_shell.ping_timeout_listener()).link as *mut _ as _);
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*removed_shell.new_popup_listener()).link as *mut _ as _);
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*removed_shell.maximize_listener()).link as *mut _ as _);
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*removed_shell.fullscreen_listener()).link as *mut _ as _);
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*removed_shell.minimize_listener()).link as *mut _ as _);
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*removed_shell.move_listener()).link as *mut _ as _);
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*removed_shell.resize_listener()).link as *mut _ as _);
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*removed_shell.show_window_menu_listener()).link as *mut _ as _);
        }
        // TODO Remove from list using iter().position
    };
]);
<commit_msg>Removed shell commit listener on destruction<commit_after>//! Manager for XDG shell v6 client.

use libc;
use wayland_sys::server::WAYLAND_SERVER_HANDLE;
use wayland_sys::server::signal::wl_signal_add;
use wlroots_sys::{wlr_xdg_surface_v6, wlr_xdg_surface_v6_role::*};

use super::xdg_shell_v6_handler::XdgV6Shell;
use {Surface, SurfaceHandle, XdgV6Popup, XdgV6ShellHandler, XdgV6ShellState::*, XdgV6ShellSurface,
     XdgV6TopLevel};
use compositor::{Compositor, COMPOSITOR_PTR};

pub trait XdgV6ShellManagerHandler {
    /// Callback that is triggered when a new XDG shell v6 surface appears.
    fn new_surface(&mut self,
                   &mut Compositor,
                   &mut XdgV6ShellSurface,
                   &mut Surface)
                   -> Option<Box<XdgV6ShellHandler>>;

    /// Callback that is triggered when an XDG shell v6 surface is destroyed.
    fn surface_destroyed(&mut self, &mut Compositor, &mut XdgV6ShellSurface, &mut Surface);
}

wayland_listener!(XdgV6ShellManager, (Vec<Box<XdgV6Shell>>, Box<XdgV6ShellManagerHandler>), [
    add_listener => add_notify: |this: &mut XdgV6ShellManager, data: *mut libc::c_void,|
    unsafe {
        let remove_listener = this.remove_listener() as *mut _ as _;
        let (ref mut shells, ref mut manager) = this.data;
        let data = data as *mut wlr_xdg_surface_v6;
        wlr_log!(L_DEBUG, "New xdg_shell_v6_surface request {:p}", data);
        let compositor = &mut *COMPOSITOR_PTR;
        let mut surface = Surface::new((*data).surface);
        let state = unsafe {
            match (*data).role {
                WLR_XDG_SURFACE_V6_ROLE_NONE => None,
                WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL => {
                    let toplevel = (*data).__bindgen_anon_1.toplevel;
                    Some(TopLevel(XdgV6TopLevel::from_shell(data, toplevel)))
                }
                WLR_XDG_SURFACE_V6_ROLE_POPUP => {
                    let popup = (*data).__bindgen_anon_1.popup;
                    Some(Popup(XdgV6Popup::from_ptr(popup)))
                }
            }
        };
        let mut shell_surface = XdgV6ShellSurface::new(data, state);
        surface.set_lock(true);
        shell_surface.set_lock(true);
        let new_surface_res = manager.new_surface(compositor, &mut shell_surface, &mut surface);
        surface.set_lock(false);
        shell_surface.set_lock(false);
        if let Some(shell_surface_handler) = new_surface_res {

            let mut shell_surface = XdgV6Shell::new((shell_surface,
                                                     surface,
                                                     shell_surface_handler));

            // Hook the destroy event into this manager.
            wl_signal_add(&mut (*data).events.destroy as *mut _ as _,
                          remove_listener);

            // Hook the commit signal from the surface into the shell handler.
            wl_signal_add(&mut (*(*data).surface).events.commit as *mut _ as _,
                          shell_surface.commit_listener() as _);

            wl_signal_add(&mut (*data).events.ping_timeout as *mut _ as _,
                          shell_surface.ping_timeout_listener() as _);
            wl_signal_add(&mut (*data).events.new_popup as *mut _ as _,
                          shell_surface.new_popup_listener() as _);
            let events = match shell_surface.surface_mut().state() {
                None | Some(&mut Popup(_)) => None,
                Some(&mut TopLevel(ref mut toplevel)) => Some((*toplevel.as_ptr()).events)
            };
            if let Some(mut events) = events {
                wl_signal_add(&mut events.request_maximize as *mut _ as _,
                              shell_surface.maximize_listener() as _);
                wl_signal_add(&mut events.request_fullscreen as *mut _ as _,
                              shell_surface.fullscreen_listener() as _);
                wl_signal_add(&mut events.request_minimize as *mut _ as _,
                              shell_surface.minimize_listener() as _);
                wl_signal_add(&mut events.request_move as *mut _ as _,
                              shell_surface.move_listener() as _);
                wl_signal_add(&mut events.request_resize as *mut _ as _,
                              shell_surface.resize_listener() as _);
                wl_signal_add(&mut events.request_show_window_menu as *mut _ as _,
                              shell_surface.show_window_menu_listener() as _);
            }

            shells.push(shell_surface);
        }
    };
    remove_listener => remove_notify: |this: &mut XdgV6ShellManager, data: *mut libc::c_void,|
    unsafe {
        let (ref mut shells, ref mut manager) = this.data;
        let data = data as *mut wlr_xdg_surface_v6;
        let mut surface = SurfaceHandle::from_ptr((*data).surface);
        let compositor = &mut *COMPOSITOR_PTR;
        if let Some(shell) = shells.iter_mut().find(|shell| shell.surface_ptr() == data) {
            let mut shell_surface = shell.surface_mut();
            shell_surface.set_lock(true);
            surface.run(|mut surface| {
                manager.surface_destroyed(compositor, &mut shell_surface, &mut surface);
            }).expect("Surface was invalid")
        }
        if let Some(index) = shells.iter().position(|shell| shell.surface_ptr() == data) {
            let mut removed_shell = shells.remove(index);
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*removed_shell.commit_listener()).link as *mut _ as _);
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*removed_shell.ping_timeout_listener()).link as *mut _ as _);
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*removed_shell.new_popup_listener()).link as *mut _ as _);
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*removed_shell.maximize_listener()).link as *mut _ as _);
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*removed_shell.fullscreen_listener()).link as *mut _ as _);
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*removed_shell.minimize_listener()).link as *mut _ as _);
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*removed_shell.move_listener()).link as *mut _ as _);
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*removed_shell.resize_listener()).link as *mut _ as _);
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*removed_shell.show_window_menu_listener()).link as *mut _ as _);
        }
        // TODO Remove from list using iter().position
    };
]);
<|endoftext|>


<commit_before>extern crate ruplicity;
#[macro_use]
extern crate clap;

fn main() {
    let _matches = clap_app!(app =>
        (version: &crate_version!()[..])
        (author: "Michele Bertasi <@brt_device>")
        (about: "Command line client for inspecting duplicity backups")
    ).get_matches();
}
<commit_msg>Added info subcommand to ruplicity-console<commit_after>extern crate ruplicity;
#[macro_use]
extern crate clap;

use std::io::{self, Write};
use std::process;

use ruplicity::backend::Backend;
use ruplicity::backend::local::LocalBackend;
use ruplicity::collections::CollectionsStatus;

fn main() {
    let matches = clap_app!(app =>
        (version: &crate_version!()[..])
        (author: "Michele Bertasi <@brt_device>")
        (about: "Command line client for inspecting duplicity backups")
        (@subcommand info =>
            (about: "informations about snapshots present in a backup")
            (@arg INPUT: +required "the path to the backup")
        )
    ).get_matches();

    if let Some(matches) = matches.subcommand_matches("info") {
        // calling unwrap is safe here, because INPUT is required
        let path = matches.value_of("INPUT").unwrap();
        let backend = LocalBackend::new(path);
        let collection = CollectionsStatus::from_filenames(ordie(backend.get_file_names()));
        println!("{}", collection);
    }
}

// taken from BurntSushi/tabwriter
fn ordie<T, E: ToString>(r: Result<T, E>) -> T {
    match r {
        Ok(r) => r,
        Err(e) => {
            let _ = write!(&mut io::stderr(), "{}", e.to_string());
            process::exit(1);
        }
    }
}
<|endoftext|>