<commit_before>//! Endpoints for event filters.

pub mod create_filter;
pub mod get_filter;

use std::fmt;

use js_int::UInt;
use ruma_api::Outgoing;
use ruma_identifiers::{RoomId, UserId};
use serde::{
    de::{MapAccess, Visitor},
    ser::SerializeStruct,
    Deserialize, Deserializer, Serialize, Serializer,
};

/// Format to use for returned events
#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum EventFormat {
    /// Client format, as described in the Client API.
    Client,

    /// Raw events from federation.
    Federation,
}

/// Filters to be applied to room events
#[derive(Clone, Copy, Debug, Default, Outgoing, Serialize)]
#[incoming_derive(Clone, Serialize)]
pub struct RoomEventFilter<'a> {
    /// A list of event types to exclude.
    ///
    /// If this list is absent then no event types are excluded. A matching type will be excluded
    /// even if it is listed in the 'types' filter. A '*' can be used as a wildcard to match any
    /// sequence of characters.
    #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
    pub not_types: &'a [String],

    /// A list of room IDs to exclude.
    ///
    /// If this list is absent then no rooms are excluded. A matching room will be excluded even if
    /// it is listed in the 'rooms' filter.
    #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
    pub not_rooms: &'a [String],

    /// The maximum number of events to return.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub limit: Option<UInt>,

    /// A list of room IDs to include.
    ///
    /// If this list is absent then all rooms are included.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub rooms: Option<&'a [RoomId]>,

    /// A list of sender IDs to exclude.
    ///
    /// If this list is absent then no senders are excluded. A matching sender will be excluded even
    /// if it is listed in the 'senders' filter.
    #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
    pub not_senders: &'a [UserId],

    /// A list of senders IDs to include.
    ///
    /// If this list is absent then all senders are included.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub senders: Option<&'a [UserId]>,

    /// A list of event types to include.
    ///
    /// If this list is absent then all event types are included. A '*' can be used as a wildcard to
    /// match any sequence of characters.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub types: Option<&'a [String]>,

    /// Controls whether to include events with a URL key in their content.
    ///
    /// * `None`: No filtering
    /// * `Some(true)`: Only events with a URL
    /// * `Some(false)`: Only events without a URL
    #[serde(skip_serializing_if = "Option::is_none")]
    pub contains_url: Option<bool>,

    /// Options to control lazy-loading of membership events.
    #[serde(flatten)]
    pub lazy_load_options: LazyLoadOptions,
}

impl<'a> RoomEventFilter<'a> {
    /// A filter that can be used to ignore all room events
    pub fn ignore_all() -> Self {
        Self { types: Some(&[]), ..Default::default() }
    }
}

/// Filters to be applied to room data
#[derive(Clone, Copy, Debug, Default, Outgoing, Serialize)]
#[incoming_derive(Clone, Serialize)]
pub struct RoomFilter<'a> {
    /// Include rooms that the user has left in the sync.
    ///
    /// Defaults to false if not included.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub include_leave: Option<bool>,

    /// The per user account data to include for rooms.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub account_data: Option<RoomEventFilter<'a>>,

    /// The message and state update events to include for rooms.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub timeline: Option<RoomEventFilter<'a>>,

    /// The events that aren't recorded in the room history, e.g. typing and receipts, to include
    /// for rooms.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub ephemeral: Option<RoomEventFilter<'a>>,

    /// The state events to include for rooms.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub state: Option<RoomEventFilter<'a>>,

    /// A list of room IDs to exclude.
    ///
    /// If this list is absent then no rooms are excluded. A matching room will be excluded even if
    /// it is listed in the 'rooms' filter. This filter is applied before the filters in
    /// `ephemeral`, `state`, `timeline` or `account_data`.
    #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
    pub not_rooms: &'a [RoomId],

    /// A list of room IDs to include.
    ///
    /// If this list is absent then all rooms are included. This filter is applied before the
    /// filters in `ephemeral`, `state`, `timeline` or `account_data`.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub rooms: Option<&'a [RoomId]>,
}

impl<'a> RoomFilter<'a> {
    /// A filter that can be used to ignore all room events (of any type)
    pub fn ignore_all() -> Self {
        Self { rooms: Some(&[]), ..Default::default() }
    }
}

/// Filter for not-room data
#[derive(Clone, Copy, Debug, Default, Outgoing, Serialize)]
#[incoming_derive(Clone, Serialize)]
pub struct Filter<'a> {
    /// A list of event types to exclude.
    ///
    /// If this list is absent then no event types are excluded. A matching type will be excluded
    /// even if it is listed in the 'types' filter. A '*' can be used as a wildcard to match any
    /// sequence of characters.
    #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
    pub not_types: &'a [String],

    /// The maximum number of events to return.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub limit: Option<UInt>,

    /// A list of senders IDs to include.
    ///
    /// If this list is absent then all senders are included.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub senders: Option<&'a [UserId]>,

    /// A list of event types to include.
    ///
    /// If this list is absent then all event types are included. A '*' can be used as a wildcard to
    /// match any sequence of characters.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub types: Option<&'a [String]>,

    /// A list of sender IDs to exclude.
    ///
    /// If this list is absent then no senders are excluded. A matching sender will be excluded even
    /// if it is listed in the 'senders' filter.
    #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
    pub not_senders: &'a [UserId],
}

impl<'a> Filter<'a> {
    /// A filter that can be used to ignore all events
    pub fn ignore_all() -> Self {
        Self { types: Some(&[]), ..Default::default() }
    }
}

/// A filter definition
#[derive(Clone, Copy, Debug, Default, Outgoing, Serialize)]
#[incoming_derive(Clone, Serialize)]
pub struct FilterDefinition<'a> {
    /// List of event fields to include.
    ///
    /// If this list is absent then all fields are included. The entries may include '.' charaters
    /// to indicate sub-fields. So ['content.body'] will include the 'body' field of the 'content'
    /// object. A literal '.' character in a field name may be escaped using a '\'. A server may
    /// include more fields than were requested.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub event_fields: Option<&'a [String]>,

    /// The format to use for events.
    ///
    /// 'client' will return the events in a format suitable for clients. 'federation' will return
    /// the raw event as received over federation. The default is 'client'.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub event_format: Option<EventFormat>,

    /// The presence updates to include.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub presence: Option<Filter<'a>>,

    /// The user account data that isn't associated with rooms to include.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub account_data: Option<Filter<'a>>,

    /// Filters to be applied to room data.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub room: Option<RoomFilter<'a>>,
}

impl<'a> FilterDefinition<'a> {
    /// A filter that can be used to ignore all events
    pub fn ignore_all() -> Self {
        Self {
            account_data: Some(Filter::ignore_all()),
            room: Some(RoomFilter::ignore_all()),
            presence: Some(Filter::ignore_all()),
            ..Default::default()
        }
    }
}

/// Specifies options for [lazy-loading membership events][lazy-loading] on
/// supported endpoints
///
/// [lazy-loading]: https://matrix.org/docs/spec/client_server/r0.6.0#lazy-loading-room-members
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum LazyLoadOptions {
    /// Disables lazy-loading of membership events.
    Disabled,

    /// Enables lazy-loading of events.
    Enabled {
        /// If `true`, sends all membership events for all events, even if they have
        /// already been sent to the client. Defaults to `false`.
        include_redundant_members: bool,
    },
}

impl Serialize for LazyLoadOptions {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut state;
        match *self {
            Self::Enabled { include_redundant_members: true } => {
                state = serializer.serialize_struct("LazyLoad", 2)?;
                state.serialize_field("lazy_load_members", &true)?;
                state.serialize_field("include_redundant_members", &true)?;
            }
            Self::Enabled { .. } => {
                state = serializer.serialize_struct("LazyLoad", 1)?;
                state.serialize_field("lazy_load_members", &true)?;
            }
            _ => {
                state = serializer.serialize_struct("LazyLoad", 0)?;
            }
        }
        state.end()
    }
}

impl Default for LazyLoadOptions {
    fn default() -> Self {
        Self::Disabled
    }
}

struct LazyLoadOptionsVisitor;

impl<'de> Visitor<'de> for LazyLoadOptionsVisitor {
    type Value = LazyLoadOptions;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("Lazy load options")
    }

    fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
    where
        M: MapAccess<'de>,
    {
        let mut lazy_load_members = false;
        let mut include_redundant_members = false;
        while let Some((key, value)) = access.next_entry::<String, bool>()? {
            match &*key {
                "lazy_load_members" => lazy_load_members = value,
                "include_redundant_members" => include_redundant_members = value,
                _ => {}
            };
        }

        Ok(if lazy_load_members {
            LazyLoadOptions::Enabled { include_redundant_members }
        } else {
            LazyLoadOptions::Disabled
        })
    }
}

impl<'de> Deserialize<'de> for LazyLoadOptions {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_map(LazyLoadOptionsVisitor)
    }
}

#[cfg(test)]
mod tests {
    use serde_json::{from_value as from_json_value, json, to_value as to_json_value};

    use super::LazyLoadOptions;

    #[test]
    fn test_serializing_disabled_lazy_load() {
        let lazy_load_options = LazyLoadOptions::Disabled;
        assert_eq!(to_json_value(lazy_load_options).unwrap(), json!({}));
    }

    #[test]
    fn test_serializing_lazy_load_no_redundant() {
        let lazy_load_options = LazyLoadOptions::Enabled { include_redundant_members: false };
        assert_eq!(to_json_value(lazy_load_options).unwrap(), json!({ "lazy_load_members": true }));
    }

    #[test]
    fn test_serializing_lazy_load_with_redundant() {
        let lazy_load_options = LazyLoadOptions::Enabled { include_redundant_members: true };
        assert_eq!(
            to_json_value(lazy_load_options).unwrap(),
            json!({ "lazy_load_members": true, "include_redundant_members": true })
        );
    }

    #[test]
    fn test_deserializing_no_lazy_load() {
        let json = json!({});
        assert_eq!(from_json_value::<LazyLoadOptions>(json).unwrap(), LazyLoadOptions::Disabled,);
    }

    #[test]
    fn test_deserializing_ignore_redundant_members_when_no_lazy_load() {
        let json = json!({ "include_redundant_members": true });
        assert_eq!(from_json_value::<LazyLoadOptions>(json).unwrap(), LazyLoadOptions::Disabled,);
    }
}
<commit_msg>client-api: Update include_leave in RoomFilter from Option<bool> to bool<commit_after>//! Endpoints for event filters.

pub mod create_filter;
pub mod get_filter;

use std::fmt;

use js_int::UInt;
use ruma_api::Outgoing;
use ruma_identifiers::{RoomId, UserId};
use serde::{
    de::{MapAccess, Visitor},
    ser::SerializeStruct,
    Deserialize, Deserializer, Serialize, Serializer,
};

/// Format to use for returned events
#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum EventFormat {
    /// Client format, as described in the Client API.
    Client,

    /// Raw events from federation.
    Federation,
}

/// Filters to be applied to room events
#[derive(Clone, Copy, Debug, Default, Outgoing, Serialize)]
#[incoming_derive(Clone, Serialize)]
pub struct RoomEventFilter<'a> {
    /// A list of event types to exclude.
    ///
    /// If this list is absent then no event types are excluded. A matching type will be excluded
    /// even if it is listed in the 'types' filter. A '*' can be used as a wildcard to match any
    /// sequence of characters.
    #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
    pub not_types: &'a [String],

    /// A list of room IDs to exclude.
    ///
    /// If this list is absent then no rooms are excluded. A matching room will be excluded even if
    /// it is listed in the 'rooms' filter.
    #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
    pub not_rooms: &'a [String],

    /// The maximum number of events to return.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub limit: Option<UInt>,

    /// A list of room IDs to include.
    ///
    /// If this list is absent then all rooms are included.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub rooms: Option<&'a [RoomId]>,

    /// A list of sender IDs to exclude.
    ///
    /// If this list is absent then no senders are excluded. A matching sender will be excluded even
    /// if it is listed in the 'senders' filter.
    #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
    pub not_senders: &'a [UserId],

    /// A list of senders IDs to include.
    ///
    /// If this list is absent then all senders are included.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub senders: Option<&'a [UserId]>,

    /// A list of event types to include.
    ///
    /// If this list is absent then all event types are included. A '*' can be used as a wildcard to
    /// match any sequence of characters.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub types: Option<&'a [String]>,

    /// Controls whether to include events with a URL key in their content.
    ///
    /// * `None`: No filtering
    /// * `Some(true)`: Only events with a URL
    /// * `Some(false)`: Only events without a URL
    #[serde(skip_serializing_if = "Option::is_none")]
    pub contains_url: Option<bool>,

    /// Options to control lazy-loading of membership events.
    #[serde(flatten)]
    pub lazy_load_options: LazyLoadOptions,
}

impl<'a> RoomEventFilter<'a> {
    /// A filter that can be used to ignore all room events
    pub fn ignore_all() -> Self {
        Self { types: Some(&[]), ..Default::default() }
    }
}

/// Filters to be applied to room data
#[derive(Clone, Copy, Debug, Default, Outgoing, Serialize)]
#[incoming_derive(Clone, Serialize)]
pub struct RoomFilter<'a> {
    /// Include rooms that the user has left in the sync.
    ///
    /// Defaults to `false`.
    #[serde(default, skip_serializing_if = "ruma_serde::is_default")]
    pub include_leave: bool,

    /// The per user account data to include for rooms.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub account_data: Option<RoomEventFilter<'a>>,

    /// The message and state update events to include for rooms.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub timeline: Option<RoomEventFilter<'a>>,

    /// The events that aren't recorded in the room history, e.g. typing and receipts, to include
    /// for rooms.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub ephemeral: Option<RoomEventFilter<'a>>,

    /// The state events to include for rooms.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub state: Option<RoomEventFilter<'a>>,

    /// A list of room IDs to exclude.
    ///
    /// If this list is absent then no rooms are excluded. A matching room will be excluded even if
    /// it is listed in the 'rooms' filter. This filter is applied before the filters in
    /// `ephemeral`, `state`, `timeline` or `account_data`.
    #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
    pub not_rooms: &'a [RoomId],

    /// A list of room IDs to include.
    ///
    /// If this list is absent then all rooms are included. This filter is applied before the
    /// filters in `ephemeral`, `state`, `timeline` or `account_data`.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub rooms: Option<&'a [RoomId]>,
}

impl<'a> RoomFilter<'a> {
    /// A filter that can be used to ignore all room events (of any type)
    pub fn ignore_all() -> Self {
        Self { rooms: Some(&[]), ..Default::default() }
    }
}

/// Filter for not-room data
#[derive(Clone, Copy, Debug, Default, Outgoing, Serialize)]
#[incoming_derive(Clone, Serialize)]
pub struct Filter<'a> {
    /// A list of event types to exclude.
    ///
    /// If this list is absent then no event types are excluded. A matching type will be excluded
    /// even if it is listed in the 'types' filter. A '*' can be used as a wildcard to match any
    /// sequence of characters.
    #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
    pub not_types: &'a [String],

    /// The maximum number of events to return.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub limit: Option<UInt>,

    /// A list of senders IDs to include.
    ///
    /// If this list is absent then all senders are included.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub senders: Option<&'a [UserId]>,

    /// A list of event types to include.
    ///
    /// If this list is absent then all event types are included. A '*' can be used as a wildcard to
    /// match any sequence of characters.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub types: Option<&'a [String]>,

    /// A list of sender IDs to exclude.
    ///
    /// If this list is absent then no senders are excluded. A matching sender will be excluded even
    /// if it is listed in the 'senders' filter.
    #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
    pub not_senders: &'a [UserId],
}

impl<'a> Filter<'a> {
    /// A filter that can be used to ignore all events
    pub fn ignore_all() -> Self {
        Self { types: Some(&[]), ..Default::default() }
    }
}

/// A filter definition
#[derive(Clone, Copy, Debug, Default, Outgoing, Serialize)]
#[incoming_derive(Clone, Serialize)]
pub struct FilterDefinition<'a> {
    /// List of event fields to include.
    ///
    /// If this list is absent then all fields are included. The entries may include '.' charaters
    /// to indicate sub-fields. So ['content.body'] will include the 'body' field of the 'content'
    /// object. A literal '.' character in a field name may be escaped using a '\'. A server may
    /// include more fields than were requested.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub event_fields: Option<&'a [String]>,

    /// The format to use for events.
    ///
    /// 'client' will return the events in a format suitable for clients. 'federation' will return
    /// the raw event as received over federation. The default is 'client'.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub event_format: Option<EventFormat>,

    /// The presence updates to include.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub presence: Option<Filter<'a>>,

    /// The user account data that isn't associated with rooms to include.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub account_data: Option<Filter<'a>>,

    /// Filters to be applied to room data.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub room: Option<RoomFilter<'a>>,
}

impl<'a> FilterDefinition<'a> {
    /// A filter that can be used to ignore all events
    pub fn ignore_all() -> Self {
        Self {
            account_data: Some(Filter::ignore_all()),
            room: Some(RoomFilter::ignore_all()),
            presence: Some(Filter::ignore_all()),
            ..Default::default()
        }
    }
}

/// Specifies options for [lazy-loading membership events][lazy-loading] on
/// supported endpoints
///
/// [lazy-loading]: https://matrix.org/docs/spec/client_server/r0.6.0#lazy-loading-room-members
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum LazyLoadOptions {
    /// Disables lazy-loading of membership events.
    Disabled,

    /// Enables lazy-loading of events.
    Enabled {
        /// If `true`, sends all membership events for all events, even if they have
        /// already been sent to the client. Defaults to `false`.
        include_redundant_members: bool,
    },
}

impl Serialize for LazyLoadOptions {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut state;
        match *self {
            Self::Enabled { include_redundant_members: true } => {
                state = serializer.serialize_struct("LazyLoad", 2)?;
                state.serialize_field("lazy_load_members", &true)?;
                state.serialize_field("include_redundant_members", &true)?;
            }
            Self::Enabled { .. } => {
                state = serializer.serialize_struct("LazyLoad", 1)?;
                state.serialize_field("lazy_load_members", &true)?;
            }
            _ => {
                state = serializer.serialize_struct("LazyLoad", 0)?;
            }
        }
        state.end()
    }
}

impl Default for LazyLoadOptions {
    fn default() -> Self {
        Self::Disabled
    }
}

struct LazyLoadOptionsVisitor;

impl<'de> Visitor<'de> for LazyLoadOptionsVisitor {
    type Value = LazyLoadOptions;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("Lazy load options")
    }

    fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
    where
        M: MapAccess<'de>,
    {
        let mut lazy_load_members = false;
        let mut include_redundant_members = false;
        while let Some((key, value)) = access.next_entry::<String, bool>()? {
            match &*key {
                "lazy_load_members" => lazy_load_members = value,
                "include_redundant_members" => include_redundant_members = value,
                _ => {}
            };
        }

        Ok(if lazy_load_members {
            LazyLoadOptions::Enabled { include_redundant_members }
        } else {
            LazyLoadOptions::Disabled
        })
    }
}

impl<'de> Deserialize<'de> for LazyLoadOptions {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_map(LazyLoadOptionsVisitor)
    }
}

#[cfg(test)]
mod tests {
    use serde_json::{from_value as from_json_value, json, to_value as to_json_value};

    use super::LazyLoadOptions;

    #[test]
    fn test_serializing_disabled_lazy_load() {
        let lazy_load_options = LazyLoadOptions::Disabled;
        assert_eq!(to_json_value(lazy_load_options).unwrap(), json!({}));
    }

    #[test]
    fn test_serializing_lazy_load_no_redundant() {
        let lazy_load_options = LazyLoadOptions::Enabled { include_redundant_members: false };
        assert_eq!(to_json_value(lazy_load_options).unwrap(), json!({ "lazy_load_members": true }));
    }

    #[test]
    fn test_serializing_lazy_load_with_redundant() {
        let lazy_load_options = LazyLoadOptions::Enabled { include_redundant_members: true };
        assert_eq!(
            to_json_value(lazy_load_options).unwrap(),
            json!({ "lazy_load_members": true, "include_redundant_members": true })
        );
    }

    #[test]
    fn test_deserializing_no_lazy_load() {
        let json = json!({});
        assert_eq!(from_json_value::<LazyLoadOptions>(json).unwrap(), LazyLoadOptions::Disabled,);
    }

    #[test]
    fn test_deserializing_ignore_redundant_members_when_no_lazy_load() {
        let json = json!({ "include_redundant_members": true });
        assert_eq!(from_json_value::<LazyLoadOptions>(json).unwrap(), LazyLoadOptions::Disabled,);
    }
}
<|endoftext|>


<commit_before>
use std::fs;
use std::path::{Path, PathBuf};
use std::io;
use std::char::from_u32;
use std::env;
use std::io::Write;
use std::process::{Command, Stdio};
use std::ffi::{OsStr, OsString};
use hyper::{self, Client};

use rand::random;

pub fn ensure_dir_exists<P: AsRef<Path>, F: FnOnce(&Path)>(path: P, callback: F) -> io::Result<bool> {
	if !is_directory(path.as_ref()) {
		callback(path.as_ref());
		fs::create_dir_all(path.as_ref()).map(|()| true)
	} else {
		Ok(false)
	}
}

pub fn is_directory<P: AsRef<Path>>(path: P) -> bool {
	fs::metadata(path).ok().as_ref().map(fs::Metadata::is_dir) == Some(true)
}

pub fn is_file<P: AsRef<Path>>(path: P) -> bool {
	fs::metadata(path).ok().as_ref().map(fs::Metadata::is_file) == Some(true)
}

pub fn path_exists<P: AsRef<Path>>(path: P) -> bool {
	fs::metadata(path).is_ok()
}

pub fn random_string(length: usize) -> String {
	let chars = b"abcdefghijklmnopqrstuvwxyz0123456789_";
	(0..length).map(|_| from_u32(chars[random::<usize>() % chars.len()] as u32).unwrap()).collect()
}

pub fn to_absolute<P: AsRef<Path>>(path: P) -> Option<PathBuf> {
	env::current_dir().map(|mut v| {
			v.push(path);
			v
		}).ok()
}

pub fn if_not_empty<S: PartialEq<str>>(s: S) -> Option<S> {
	if s == *"" {
		None
	} else {
		Some(s)
	}
}

pub fn write_file(path: &Path, contents: &str) -> io::Result<()> {
	let mut file = try!(fs::OpenOptions::new()
		.write(true)
		.truncate(true)
		.create(true)
		.open(path));

	try!(io::Write::write_all(&mut file, contents.as_bytes()));

	try!(file.sync_data());

	Ok(())
}

pub fn read_file(path: &Path) -> io::Result<String> {
	let mut file = try!(fs::OpenOptions::new()
		.read(true)
		.open(path));

	let mut contents = String::new();

	try!(io::Read::read_to_string(&mut file, &mut contents));

	Ok(contents)
}

pub fn filter_file<F: FnMut(&str) -> bool>(src: &Path, dest: &Path, mut filter: F) -> io::Result<usize> {
	let src_file = try!(fs::File::open(src));
	let dest_file = try!(fs::File::create(dest));

	let mut reader = io::BufReader::new(src_file);
	let mut writer = io::BufWriter::new(dest_file);
	let mut removed = 0;

	for result in io::BufRead::lines(&mut reader) {
		let line = try!(result);
		if filter(&line) {
			try!(writeln!(&mut writer, "{}", &line));
		} else {
			removed += 1;
		}
	}

	try!(writer.flush());

	Ok(removed)
}

pub fn match_file<T, F: FnMut(&str) -> Option<T>>(src: &Path, mut f: F) -> io::Result<Option<T>> {
	let src_file = try!(fs::File::open(src));

	let mut reader = io::BufReader::new(src_file);

	for result in io::BufRead::lines(&mut reader) {
		let line = try!(result);
		if let Some(r) = f(&line) {
			return Ok(Some(r));
		}
	}

	Ok(None)
}

pub fn append_file(dest: &Path, line: &str) -> io::Result<()> {
	let mut dest_file = try!(fs::OpenOptions::new()
		.write(true)
		.append(true)
		.create(true)
		.open(dest)
		);

	try!(writeln!(&mut dest_file, "{}", line));

	try!(dest_file.sync_data());

	Ok(())
}

pub fn download_file<P: AsRef<Path>>(url: hyper::Url, path: P) -> Result<(),()> {
	let client = Client::new();

	let mut res = try!(client.get(url).send().map_err(|_|()));
	if res.status != hyper::Ok { return Err(()); }

	let buffer_size = 0x1000;
	let mut buffer = vec![0u8; buffer_size];

	let mut file = try!(fs::File::create(path).map_err(|_|()));

	loop {
		let bytes_read = try!(io::Read::read(&mut res, &mut buffer).map_err(|_|()));
		if bytes_read != 0 {
			try!(io::Write::write_all(&mut file, &mut buffer[0..bytes_read]).map_err(|_|()));
		} else {
			try!(file.sync_data().map_err(|_|()));
			return Ok(());
		}
	}
}

pub fn symlink_dir(src: &Path, dest: &Path) -> Option<()> {
	#[cfg(windows)]
	fn symlink_dir_inner(src: &Path, dest: &Path) -> Option<()> {
		::std::os::windows::fs::symlink_dir(src, dest).ok()
	}
	#[cfg(not(windows))]
	fn symlink_dir_inner(src: &Path, dest: &Path) -> Option<()> {
		::std::os::unix::fs::symlink(src, dest).ok()
	}

	symlink_dir_inner(src, dest)
}

pub fn copy_dir(src: &Path, dest: &Path) -> Option<()> {
	#[cfg(windows)]
	fn copy_dir_inner(src: &Path, dest: &Path) -> Option<()> {
		Command::new("robocopy")
			.arg(src).arg(dest).arg("/E")
			.status().ok()
			.and_then(|code| if code.success() { Some(()) } else { None })
	}
	#[cfg(not(windows))]
	fn copy_dir_inner(src: &Path, dest: &Path) -> Option<()> {
		Command::new("cp")
			.arg("-R").arg(src).arg(dest)
			.status().ok()
			.and_then(|code| if code.success() { Some(()) } else { None })
	}

	copy_dir_inner(src, dest)
}

pub fn prefix_arg<S: AsRef<OsStr>>(name: &str, s: S) -> OsString {
	let mut arg = OsString::from(name);
	arg.push(s);
	arg
}

pub fn open_browser(path: &Path) -> io::Result<bool> {
	#[cfg(not(windows))]
	fn has_cmd(cmd: &str) -> bool {
		Command::new("command")
			.arg("-v").arg(cmd)
			.stdin(Stdio::null())
			.stdout(Stdio::null())
			.stderr(Stdio::null())
			.status()
			.map(|s| s.success()) == Ok(true)
	}
	#[cfg(not(windows))]
	fn inner(path: &Path) -> io::Result<bool> {
		let commands = ["xdg-open", "open", "firefox", "chromium"];
		if let Some(cmd) = commands.filter(has_cmd).next() {
			Command::new(cmd)
				.arg(path)
				.stdin(Stdio::null())
				.stdout(Stdio::null())
				.stderr(Stdio::null())
				.spawn()
				.map(|_| true)
		} else {
			Ok(false)
		}
	}
	#[cfg(windows)]
	fn inner(path: &Path) -> io::Result<bool> {
		Command::new("start")
			.arg(path)
			.stdin(Stdio::null())
			.stdout(Stdio::null())
			.stderr(Stdio::null())
			.spawn()
			.map(|_| true)
	}
	inner(path)
}
<commit_msg>Fix non-windows build<commit_after>
use std::fs;
use std::path::{Path, PathBuf};
use std::io;
use std::char::from_u32;
use std::env;
use std::io::Write;
use std::process::{Command, Stdio};
use std::ffi::{OsStr, OsString};
use hyper::{self, Client};

use rand::random;

pub fn ensure_dir_exists<P: AsRef<Path>, F: FnOnce(&Path)>(path: P, callback: F) -> io::Result<bool> {
	if !is_directory(path.as_ref()) {
		callback(path.as_ref());
		fs::create_dir_all(path.as_ref()).map(|()| true)
	} else {
		Ok(false)
	}
}

pub fn is_directory<P: AsRef<Path>>(path: P) -> bool {
	fs::metadata(path).ok().as_ref().map(fs::Metadata::is_dir) == Some(true)
}

pub fn is_file<P: AsRef<Path>>(path: P) -> bool {
	fs::metadata(path).ok().as_ref().map(fs::Metadata::is_file) == Some(true)
}

pub fn path_exists<P: AsRef<Path>>(path: P) -> bool {
	fs::metadata(path).is_ok()
}

pub fn random_string(length: usize) -> String {
	let chars = b"abcdefghijklmnopqrstuvwxyz0123456789_";
	(0..length).map(|_| from_u32(chars[random::<usize>() % chars.len()] as u32).unwrap()).collect()
}

pub fn to_absolute<P: AsRef<Path>>(path: P) -> Option<PathBuf> {
	env::current_dir().map(|mut v| {
			v.push(path);
			v
		}).ok()
}

pub fn if_not_empty<S: PartialEq<str>>(s: S) -> Option<S> {
	if s == *"" {
		None
	} else {
		Some(s)
	}
}

pub fn write_file(path: &Path, contents: &str) -> io::Result<()> {
	let mut file = try!(fs::OpenOptions::new()
		.write(true)
		.truncate(true)
		.create(true)
		.open(path));

	try!(io::Write::write_all(&mut file, contents.as_bytes()));

	try!(file.sync_data());

	Ok(())
}

pub fn read_file(path: &Path) -> io::Result<String> {
	let mut file = try!(fs::OpenOptions::new()
		.read(true)
		.open(path));

	let mut contents = String::new();

	try!(io::Read::read_to_string(&mut file, &mut contents));

	Ok(contents)
}

pub fn filter_file<F: FnMut(&str) -> bool>(src: &Path, dest: &Path, mut filter: F) -> io::Result<usize> {
	let src_file = try!(fs::File::open(src));
	let dest_file = try!(fs::File::create(dest));

	let mut reader = io::BufReader::new(src_file);
	let mut writer = io::BufWriter::new(dest_file);
	let mut removed = 0;

	for result in io::BufRead::lines(&mut reader) {
		let line = try!(result);
		if filter(&line) {
			try!(writeln!(&mut writer, "{}", &line));
		} else {
			removed += 1;
		}
	}

	try!(writer.flush());

	Ok(removed)
}

pub fn match_file<T, F: FnMut(&str) -> Option<T>>(src: &Path, mut f: F) -> io::Result<Option<T>> {
	let src_file = try!(fs::File::open(src));

	let mut reader = io::BufReader::new(src_file);

	for result in io::BufRead::lines(&mut reader) {
		let line = try!(result);
		if let Some(r) = f(&line) {
			return Ok(Some(r));
		}
	}

	Ok(None)
}

pub fn append_file(dest: &Path, line: &str) -> io::Result<()> {
	let mut dest_file = try!(fs::OpenOptions::new()
		.write(true)
		.append(true)
		.create(true)
		.open(dest)
		);

	try!(writeln!(&mut dest_file, "{}", line));

	try!(dest_file.sync_data());

	Ok(())
}

pub fn download_file<P: AsRef<Path>>(url: hyper::Url, path: P) -> Result<(),()> {
	let client = Client::new();

	let mut res = try!(client.get(url).send().map_err(|_|()));
	if res.status != hyper::Ok { return Err(()); }

	let buffer_size = 0x1000;
	let mut buffer = vec![0u8; buffer_size];

	let mut file = try!(fs::File::create(path).map_err(|_|()));

	loop {
		let bytes_read = try!(io::Read::read(&mut res, &mut buffer).map_err(|_|()));
		if bytes_read != 0 {
			try!(io::Write::write_all(&mut file, &mut buffer[0..bytes_read]).map_err(|_|()));
		} else {
			try!(file.sync_data().map_err(|_|()));
			return Ok(());
		}
	}
}

pub fn symlink_dir(src: &Path, dest: &Path) -> Option<()> {
	#[cfg(windows)]
	fn symlink_dir_inner(src: &Path, dest: &Path) -> Option<()> {
		::std::os::windows::fs::symlink_dir(src, dest).ok()
	}
	#[cfg(not(windows))]
	fn symlink_dir_inner(src: &Path, dest: &Path) -> Option<()> {
		::std::os::unix::fs::symlink(src, dest).ok()
	}

	symlink_dir_inner(src, dest)
}

pub fn copy_dir(src: &Path, dest: &Path) -> Option<()> {
	#[cfg(windows)]
	fn copy_dir_inner(src: &Path, dest: &Path) -> Option<()> {
		Command::new("robocopy")
			.arg(src).arg(dest).arg("/E")
			.status().ok()
			.and_then(|code| if code.success() { Some(()) } else { None })
	}
	#[cfg(not(windows))]
	fn copy_dir_inner(src: &Path, dest: &Path) -> Option<()> {
		Command::new("cp")
			.arg("-R").arg(src).arg(dest)
			.status().ok()
			.and_then(|code| if code.success() { Some(()) } else { None })
	}

	copy_dir_inner(src, dest)
}

pub fn prefix_arg<S: AsRef<OsStr>>(name: &str, s: S) -> OsString {
	let mut arg = OsString::from(name);
	arg.push(s);
	arg
}

pub fn open_browser(path: &Path) -> io::Result<bool> {
	#[cfg(not(windows))]
	fn has_cmd(cmd: &&str) -> bool {
		Command::new("command")
			.arg("-v").arg(cmd)
			.stdin(Stdio::null())
			.stdout(Stdio::null())
			.stderr(Stdio::null())
			.status()
			.map(|s| s.success())
			.unwrap_or(false)
	}
	#[cfg(not(windows))]
	fn inner(path: &Path) -> io::Result<bool> {
		let commands = ["xdg-open", "open", "firefox", "chromium"];
		if let Some(cmd) = commands.iter().map(|s| *s).filter(has_cmd).next() {
			Command::new(cmd)
				.arg(path)
				.stdin(Stdio::null())
				.stdout(Stdio::null())
				.stderr(Stdio::null())
				.spawn()
				.map(|_| true)
		} else {
			Ok(false)
		}
	}
	#[cfg(windows)]
	fn inner(path: &Path) -> io::Result<bool> {
		Command::new("start")
			.arg(path)
			.stdin(Stdio::null())
			.stdout(Stdio::null())
			.stderr(Stdio::null())
			.spawn()
			.map(|_| true)
	}
	inner(path)
}
<|endoftext|>


<commit_before>#[cfg(feature = "term_size")]
extern crate textwrap;

#[cfg(not(feature = "term_size"))]
fn main() {
    println!("Please enable the term_size feature to run this example.");
}

#[cfg(feature = "term_size")]
fn main() {
    let example = "Memory safety without garbage collection. \
                   Concurrency without data races. \
                   Zero-cost abstractions.";
    // Create a new Wrapper -- automatically set the width to the
    // current terminal width.
    let wrapper = textwrap::Wrapper::with_termwidth();
    println!("Formatted in within {} columns:", wrapper.width);
    println!("----");
    println!("{}", wrapper.fill(example));
    println!("----");
}
<commit_msg>examples: let termwidth example use hyphenation<commit_after>#[cfg(feature = "hyphenation")]
extern crate hyphenation;
extern crate textwrap;

#[cfg(feature = "hyphenation")]
use hyphenation::Language;
use textwrap::Wrapper;

#[cfg(not(feature = "term_size"))]
fn main() {
    println!("Please enable the term_size feature to run this example.");
}

#[cfg(feature = "term_size")]
fn main() {
    #[cfg(not(feature = "hyphenation"))]
    fn new_wrapper<'a>() -> (&'static str, Wrapper<'a, textwrap::HyphenSplitter>) {
        ("without hyphenation", Wrapper::with_termwidth())
    }

    #[cfg(feature = "hyphenation")]
    fn new_wrapper<'a>() -> (&'static str, Wrapper<'a, hyphenation::Corpus>) {
        let corpus = hyphenation::load(Language::English_US).unwrap();
        ("with hyphenation", Wrapper::with_splitter(textwrap::termwidth(), corpus))
    }

    let example = "Memory safety without garbage collection. \
                   Concurrency without data races. \
                   Zero-cost abstractions.";
    // Create a new Wrapper -- automatically set the width to the
    // current terminal width.
    let (msg, wrapper) = new_wrapper();
    println!("Formatted {} in {} columns:", msg, wrapper.width);
    println!("----");
    println!("{}", wrapper.fill(example));
    println!("----");
}
<|endoftext|>


<commit_before>use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::Duration;

use crossbeam_deque::{Steal, Stealer, Worker};
use rand::distributions::{Distribution, Uniform};
use rand::thread_rng;
use scoped_threadpool::Pool;

use gc::root::Slot;
use gc::{Address, Region};

pub fn start(rootset: &[Slot], heap: Region, perm: Region, threadpool: &mut Pool) {
    let number_workers = threadpool.thread_count() as usize;
    let mut workers = Vec::with_capacity(number_workers);
    let mut stealers = Vec::with_capacity(number_workers);

    for _ in 0..number_workers {
        let w = Worker::new_lifo();
        let s = w.stealer();
        workers.push(w);
        stealers.push(s);
    }

    for root in rootset {
        let root_ptr = root.get();

        if heap.contains(root_ptr) {
            let root_obj = root_ptr.to_mut_obj();

            if !root_obj.header().is_marked_non_atomic() {
                root_obj.header_mut().mark_non_atomic();
                workers[0].push(root_ptr);
            }
        } else {
            debug_assert!(root_ptr.is_null() || perm.contains(root_ptr));
        }
    }

    let terminator = Arc::new(Terminator::new(number_workers));

    threadpool.scoped(|scoped| {
        for (task_id, worker) in workers.into_iter().enumerate() {
            let heap_region = heap.clone();
            let perm_region = perm.clone();

            let stealers = stealers.clone();
            let terminator = terminator.clone();

            scoped.execute(move || {
                let mut task = MarkingTask {
                    task_id: task_id,
                    local: Segment::new(),
                    worker: worker,
                    stealers: stealers,
                    terminator: terminator,
                    heap_region: heap_region,
                    perm_region: perm_region,
                    marked: 0,
                };

                task.run();
            });
        }
    });
}

pub struct Terminator {
    nworkers: AtomicUsize,
}

impl Terminator {
    pub fn new(number_workers: usize) -> Terminator {
        Terminator {
            nworkers: AtomicUsize::new(number_workers),
        }
    }

    pub fn try_terminate(&self) -> bool {
        self.decrease_workers();
        thread::sleep(Duration::from_micros(1));
        self.zero_or_increase_workers()
    }

    fn decrease_workers(&self) -> bool {
        self.nworkers.fetch_sub(1, Ordering::SeqCst) == 1
    }

    fn zero_or_increase_workers(&self) -> bool {
        let mut nworkers = self.nworkers.load(Ordering::Relaxed);

        loop {
            if nworkers == 0 {
                return true;
            }

            let prev_nworkers =
                self.nworkers
                    .compare_and_swap(nworkers, nworkers + 1, Ordering::SeqCst);

            if nworkers == prev_nworkers {
                return false;
            }

            nworkers = prev_nworkers;
        }
    }
}

struct MarkingTask {
    task_id: usize,
    local: Segment,
    worker: Worker<Address>,
    stealers: Vec<Stealer<Address>>,
    terminator: Arc<Terminator>,
    heap_region: Region,
    perm_region: Region,
    marked: usize,
}

impl MarkingTask {
    fn pop(&mut self) -> Option<Address> {
        self.pop_local()
            .or_else(|| self.pop_worker())
            .or_else(|| self.steal())
    }

    fn pop_local(&mut self) -> Option<Address> {
        if self.local.is_empty() {
            return None;
        }

        let obj = self.local.pop().expect("should be non-empty");
        Some(obj)
    }

    fn pop_worker(&mut self) -> Option<Address> {
        self.worker.pop()
    }

    fn steal(&self) -> Option<Address> {
        if self.stealers.len() == 1 {
            return None;
        }

        let mut rng = thread_rng();
        let range = Uniform::new(0, self.stealers.len());

        for _ in 0..2 * self.stealers.len() {
            let mut stealer_id = self.task_id;

            while stealer_id == self.task_id {
                stealer_id = range.sample(&mut rng);
            }

            let stealer = &self.stealers[stealer_id];

            loop {
                match stealer.steal_batch_and_pop(&self.worker) {
                    Steal::Empty => break,
                    Steal::Success(address) => return Some(address),
                    Steal::Retry => continue,
                }
            }
        }

        None
    }

    fn run(&mut self) {
        loop {
            let object_addr = if let Some(object_addr) = self.pop() {
                object_addr
            } else if self.terminator.try_terminate() {
                break;
            } else {
                continue;
            };

            let object = object_addr.to_mut_obj();

            object.visit_reference_fields(|field| {
                self.trace(field);
            });
        }
    }

    fn trace(&mut self, slot: Slot) {
        let field_addr = slot.get();

        if self.heap_region.contains(field_addr) {
            let field_obj = field_addr.to_mut_obj();

            if field_obj.header().try_mark_non_atomic() {
                if self.local.has_capacity() {
                    self.local.push(field_addr);
                    self.defensive_push();
                } else {
                    self.worker.push(field_addr);
                }
            }
        } else {
            debug_assert!(field_addr.is_null() || self.perm_region.contains(field_addr));
        }
    }

    fn defensive_push(&mut self) {
        self.marked += 1;

        if self.marked > 256 {
            if self.local.len() > 4 {
                let target_len = self.local.len() / 2;

                while self.local.len() > target_len {
                    let val = self.local.pop().unwrap();
                    self.worker.push(val);
                }
            }

            self.marked = 0;
        }
    }
}

const SEGMENT_SIZE: usize = 64;

struct Segment {
    data: Vec<Address>,
}

impl Segment {
    fn new() -> Segment {
        Segment {
            data: Vec::with_capacity(SEGMENT_SIZE),
        }
    }

    fn empty() -> Segment {
        Segment { data: Vec::new() }
    }

    fn with(addr: Address) -> Segment {
        let mut segment = Segment::new();
        segment.data.push(addr);

        segment
    }

    fn has_capacity(&self) -> bool {
        self.data.len() < SEGMENT_SIZE
    }

    fn is_empty(&self) -> bool {
        self.data.is_empty()
    }

    fn push(&mut self, addr: Address) {
        debug_assert!(self.has_capacity());
        self.data.push(addr);
    }

    fn pop(&mut self) -> Option<Address> {
        self.data.pop()
    }

    fn len(&mut self) -> usize {
        self.data.len()
    }
}
<commit_msg>swiper: global queue for parallel marking<commit_after>use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::Duration;

use crossbeam_deque::{Injector, Steal, Stealer, Worker};
use rand::distributions::{Distribution, Uniform};
use rand::thread_rng;
use scoped_threadpool::Pool;

use gc::root::Slot;
use gc::{Address, Region};

pub fn start(rootset: &[Slot], heap: Region, perm: Region, threadpool: &mut Pool) {
    let number_workers = threadpool.thread_count() as usize;
    let mut workers = Vec::with_capacity(number_workers);
    let mut stealers = Vec::with_capacity(number_workers);
    let injector = Injector::new();

    for _ in 0..number_workers {
        let w = Worker::new_lifo();
        let s = w.stealer();
        workers.push(w);
        stealers.push(s);
    }

    for root in rootset {
        let root_ptr = root.get();

        if heap.contains(root_ptr) {
            let root_obj = root_ptr.to_mut_obj();

            if !root_obj.header().is_marked_non_atomic() {
                root_obj.header_mut().mark_non_atomic();
                injector.push(root_ptr);
            }
        } else {
            debug_assert!(root_ptr.is_null() || perm.contains(root_ptr));
        }
    }

    let terminator = Arc::new(Terminator::new(number_workers));

    threadpool.scoped(|scoped| {
        for (task_id, worker) in workers.into_iter().enumerate() {
            let heap_region = heap.clone();
            let perm_region = perm.clone();

            let injector = &injector;
            let stealers = stealers.clone();
            let terminator = terminator.clone();

            scoped.execute(move || {
                let mut task = MarkingTask {
                    task_id: task_id,
                    local: Segment::new(),
                    worker: worker,
                    injector: injector,
                    stealers: stealers,
                    terminator: terminator,
                    heap_region: heap_region,
                    perm_region: perm_region,
                    marked: 0,
                };

                task.run();
            });
        }
    });
}

pub struct Terminator {
    nworkers: AtomicUsize,
}

impl Terminator {
    pub fn new(number_workers: usize) -> Terminator {
        Terminator {
            nworkers: AtomicUsize::new(number_workers),
        }
    }

    pub fn try_terminate(&self) -> bool {
        self.decrease_workers();
        thread::sleep(Duration::from_micros(1));
        self.zero_or_increase_workers()
    }

    fn decrease_workers(&self) -> bool {
        self.nworkers.fetch_sub(1, Ordering::SeqCst) == 1
    }

    fn zero_or_increase_workers(&self) -> bool {
        let mut nworkers = self.nworkers.load(Ordering::Relaxed);

        loop {
            if nworkers == 0 {
                return true;
            }

            let prev_nworkers =
                self.nworkers
                    .compare_and_swap(nworkers, nworkers + 1, Ordering::SeqCst);

            if nworkers == prev_nworkers {
                return false;
            }

            nworkers = prev_nworkers;
        }
    }
}

struct MarkingTask<'a> {
    task_id: usize,
    local: Segment,
    worker: Worker<Address>,
    injector: &'a Injector<Address>,
    stealers: Vec<Stealer<Address>>,
    terminator: Arc<Terminator>,
    heap_region: Region,
    perm_region: Region,
    marked: usize,
}

impl<'a> MarkingTask<'a> {
    fn pop(&mut self) -> Option<Address> {
        self.pop_local()
            .or_else(|| self.pop_worker())
            .or_else(|| self.pop_global())
            .or_else(|| self.steal())
    }

    fn pop_local(&mut self) -> Option<Address> {
        if self.local.is_empty() {
            return None;
        }

        let obj = self.local.pop().expect("should be non-empty");
        Some(obj)
    }

    fn pop_worker(&mut self) -> Option<Address> {
        self.worker.pop()
    }

    fn pop_global(&mut self) -> Option<Address> {
        loop {
            let result = self.injector.steal_batch_and_pop(&mut self.worker);

            match result {
                Steal::Empty => break,
                Steal::Success(value) => return Some(value),
                Steal::Retry => continue,
            }
        }

        None
    }

    fn steal(&self) -> Option<Address> {
        if self.stealers.len() == 1 {
            return None;
        }

        let mut rng = thread_rng();
        let range = Uniform::new(0, self.stealers.len());

        for _ in 0..2 * self.stealers.len() {
            let mut stealer_id = self.task_id;

            while stealer_id == self.task_id {
                stealer_id = range.sample(&mut rng);
            }

            let stealer = &self.stealers[stealer_id];

            loop {
                match stealer.steal_batch_and_pop(&self.worker) {
                    Steal::Empty => break,
                    Steal::Success(address) => return Some(address),
                    Steal::Retry => continue,
                }
            }
        }

        None
    }

    fn run(&mut self) {
        loop {
            let object_addr = if let Some(object_addr) = self.pop() {
                object_addr
            } else if self.terminator.try_terminate() {
                break;
            } else {
                continue;
            };

            let object = object_addr.to_mut_obj();

            object.visit_reference_fields(|field| {
                self.trace(field);
            });
        }
    }

    fn trace(&mut self, slot: Slot) {
        let field_addr = slot.get();

        if self.heap_region.contains(field_addr) {
            let field_obj = field_addr.to_mut_obj();

            if field_obj.header().try_mark_non_atomic() {
                if self.local.has_capacity() {
                    self.local.push(field_addr);
                    self.defensive_push();
                } else {
                    self.worker.push(field_addr);
                }
            }
        } else {
            debug_assert!(field_addr.is_null() || self.perm_region.contains(field_addr));
        }
    }

    fn defensive_push(&mut self) {
        self.marked += 1;

        if self.marked > 256 {
            if self.local.len() > 4 {
                let target_len = self.local.len() / 2;

                while self.local.len() > target_len {
                    let val = self.local.pop().unwrap();
                    self.injector.push(val);
                }
            }

            self.marked = 0;
        }
    }
}

const SEGMENT_SIZE: usize = 64;

struct Segment {
    data: Vec<Address>,
}

impl Segment {
    fn new() -> Segment {
        Segment {
            data: Vec::with_capacity(SEGMENT_SIZE),
        }
    }

    fn empty() -> Segment {
        Segment { data: Vec::new() }
    }

    fn with(addr: Address) -> Segment {
        let mut segment = Segment::new();
        segment.data.push(addr);

        segment
    }

    fn has_capacity(&self) -> bool {
        self.data.len() < SEGMENT_SIZE
    }

    fn is_empty(&self) -> bool {
        self.data.is_empty()
    }

    fn push(&mut self, addr: Address) {
        debug_assert!(self.has_capacity());
        self.data.push(addr);
    }

    fn pop(&mut self) -> Option<Address> {
        self.data.pop()
    }

    fn len(&mut self) -> usize {
        self.data.len()
    }
}
<|endoftext|>


<commit_before>use libc::{c_int, c_double, c_char};

pub type EnergyMonInitFn = unsafe extern fn() -> c_int;
pub type EnergyMonReadTotalFn = unsafe extern fn() -> c_double;
pub type EnergyMonFinishFn = unsafe extern fn() -> c_int;
pub type EnergyMonGetSourceFn = unsafe extern fn(*mut c_char) -> *mut c_char;

#[repr(C)]
pub struct EnergyMon {
    pub finit: EnergyMonInitFn,
    pub fread: EnergyMonReadTotalFn,
    pub ffinish: EnergyMonFinishFn,
    pub fsource: EnergyMonGetSourceFn,
}
<commit_msg>reworked energymon interface<commit_after>use libc::{c_int, c_double, c_char, c_void};

pub type EnergyMonInitFn = unsafe extern fn(em: *mut EnergyMon) -> c_int;
pub type EnergyMonReadTotalFn = unsafe extern fn(em: *mut EnergyMon) -> c_double;
pub type EnergyMonFinishFn = unsafe extern fn(em: *mut EnergyMon) -> c_int;
pub type EnergyMonGetSourceFn = unsafe extern fn(*mut c_char) -> *mut c_char;

#[repr(C)]
pub struct EnergyMon {
    pub finit: EnergyMonInitFn,
    pub fread: EnergyMonReadTotalFn,
    pub ffinish: EnergyMonFinishFn,
    pub fsource: EnergyMonGetSourceFn,
    pub state: *mut c_void,
}
<|endoftext|>


<commit_before>use libc::{gid_t, uid_t};

/// Credentials of a process
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct UCred {
    /// UID (user ID) of the process
    uid: uid_t,
    /// GID (group ID) of the process
    gid: gid_t,
}

impl UCred {
    /// Gets UID (user ID) of the process.
    pub fn uid(&self) -> uid_t {
        self.uid
    }

    /// Gets GID (group ID) of the process.
    pub fn gid(&self) -> gid_t {
        self.gid
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
pub(crate) use self::impl_linux::get_peer_cred;

#[cfg(any(
    target_os = "dragonfly",
    target_os = "macos",
    target_os = "ios",
    target_os = "freebsd",
    target_os = "netbsd",
    target_os = "openbsd"
))]
pub(crate) use self::impl_macos::get_peer_cred;

#[cfg(any(target_os = "solaris", target_os = "illumos"))]
pub(crate) use self::impl_solaris::get_peer_cred;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub(crate) mod impl_linux {
    use crate::net::unix::UnixStream;

    use libc::{c_void, getsockopt, socklen_t, SOL_SOCKET, SO_PEERCRED};
    use std::{io, mem};

    use libc::ucred;

    pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
        use std::os::unix::io::AsRawFd;

        unsafe {
            let raw_fd = sock.as_raw_fd();

            let mut ucred = ucred {
                pid: 0,
                uid: 0,
                gid: 0,
            };

            let ucred_size = mem::size_of::<ucred>();

            // These paranoid checks should be optimized-out
            assert!(mem::size_of::<u32>() <= mem::size_of::<usize>());
            assert!(ucred_size <= u32::max_value() as usize);

            let mut ucred_size = ucred_size as socklen_t;

            let ret = getsockopt(
                raw_fd,
                SOL_SOCKET,
                SO_PEERCRED,
                &mut ucred as *mut ucred as *mut c_void,
                &mut ucred_size,
            );
            if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() {
                Ok(super::UCred {
                    uid: ucred.uid,
                    gid: ucred.gid,
                })
            } else {
                Err(io::Error::last_os_error())
            }
        }
    }
}

#[cfg(any(
    target_os = "dragonfly",
    target_os = "macos",
    target_os = "ios",
    target_os = "freebsd",
    target_os = "netbsd",
    target_os = "openbsd"
))]
pub(crate) mod impl_macos {
    use crate::net::unix::UnixStream;

    use libc::getpeereid;
    use std::io;
    use std::mem::MaybeUninit;
    use std::os::unix::io::AsRawFd;

    pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
        unsafe {
            let raw_fd = sock.as_raw_fd();

            let mut uid = MaybeUninit::uninit();
            let mut gid = MaybeUninit::uninit();

            let ret = getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr());

            if ret == 0 {
                Ok(super::UCred {
                    uid: uid.assume_init(),
                    gid: gid.assume_init(),
                })
            } else {
                Err(io::Error::last_os_error())
            }
        }
    }
}

#[cfg(any(target_os = "solaris", target_os = "illumos"))]
pub(crate) mod impl_solaris {
    use crate::net::unix::UnixStream;
    use std::io;
    use std::os::unix::io::AsRawFd;
    use std::ptr;

    #[allow(non_camel_case_types)]
    enum ucred_t {}

    extern "C" {
        fn ucred_free(cred: *mut ucred_t);
        fn ucred_geteuid(cred: *const ucred_t) -> super::uid_t;
        fn ucred_getegid(cred: *const ucred_t) -> super::gid_t;

        fn getpeerucred(fd: std::os::raw::c_int, cred: *mut *mut ucred_t) -> std::os::raw::c_int;
    }

    pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
        unsafe {
            let raw_fd = sock.as_raw_fd();

            let mut cred = ptr::null_mut::<*mut ucred_t>() as *mut ucred_t;

            let ret = getpeerucred(raw_fd, &mut cred);

            if ret == 0 {
                let uid = ucred_geteuid(cred);
                let gid = ucred_getegid(cred);

                ucred_free(cred);

                Ok(super::UCred { uid, gid })
            } else {
                Err(io::Error::last_os_error())
            }
        }
    }
}
<commit_msg>net: add pid to tokio::net::unix::UCred (#2633)<commit_after>use libc::{gid_t, pid_t, uid_t};

/// Credentials of a process
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct UCred {
    /// PID (process ID) of the process
    pid: Option<pid_t>,
    /// UID (user ID) of the process
    uid: uid_t,
    /// GID (group ID) of the process
    gid: gid_t,
}

impl UCred {
    /// Gets UID (user ID) of the process.
    pub fn uid(&self) -> uid_t {
        self.uid
    }

    /// Gets GID (group ID) of the process.
    pub fn gid(&self) -> gid_t {
        self.gid
    }

    /// Gets PID (process ID) of the process.
    ///
    /// This is only implemented under linux, android, IOS and MacOS
    pub fn pid(&self) -> Option<pid_t> {
        self.pid
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
pub(crate) use self::impl_linux::get_peer_cred;

#[cfg(any(
    target_os = "dragonfly",
    target_os = "freebsd",
    target_os = "netbsd",
    target_os = "openbsd"
))]
pub(crate) use self::impl_bsd::get_peer_cred;

#[cfg(any(target_os = "macos", target_os = "ios"))]
pub(crate) use self::impl_macos::get_peer_cred;

#[cfg(any(target_os = "solaris", target_os = "illumos"))]
pub(crate) use self::impl_solaris::get_peer_cred;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub(crate) mod impl_linux {
    use crate::net::unix::UnixStream;

    use libc::{c_void, getsockopt, socklen_t, SOL_SOCKET, SO_PEERCRED};
    use std::{io, mem};

    use libc::ucred;

    pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
        use std::os::unix::io::AsRawFd;

        unsafe {
            let raw_fd = sock.as_raw_fd();

            let mut ucred = ucred {
                pid: 0,
                uid: 0,
                gid: 0,
            };

            let ucred_size = mem::size_of::<ucred>();

            // These paranoid checks should be optimized-out
            assert!(mem::size_of::<u32>() <= mem::size_of::<usize>());
            assert!(ucred_size <= u32::max_value() as usize);

            let mut ucred_size = ucred_size as socklen_t;

            let ret = getsockopt(
                raw_fd,
                SOL_SOCKET,
                SO_PEERCRED,
                &mut ucred as *mut ucred as *mut c_void,
                &mut ucred_size,
            );
            if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() {
                Ok(super::UCred {
                    uid: ucred.uid,
                    gid: ucred.gid,
                    pid: Some(ucred.pid),
                })
            } else {
                Err(io::Error::last_os_error())
            }
        }
    }
}

#[cfg(any(
    target_os = "dragonfly",
    target_os = "freebsd",
    target_os = "netbsd",
    target_os = "openbsd"
))]
pub(crate) mod impl_bsd {
    use crate::net::unix::UnixStream;

    use libc::getpeereid;
    use std::io;
    use std::mem::MaybeUninit;
    use std::os::unix::io::AsRawFd;

    pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
        unsafe {
            let raw_fd = sock.as_raw_fd();

            let mut uid = MaybeUninit::uninit();
            let mut gid = MaybeUninit::uninit();

            let ret = getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr());

            if ret == 0 {
                Ok(super::UCred {
                    uid: uid.assume_init(),
                    gid: gid.assume_init(),
                    pid: None,
                })
            } else {
                Err(io::Error::last_os_error())
            }
        }
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
pub(crate) mod impl_macos {
    use crate::net::unix::UnixStream;

    use libc::{c_void, getpeereid, getsockopt, pid_t, LOCAL_PEEREPID, SOL_LOCAL};
    use std::io;
    use std::mem::size_of;
    use std::mem::MaybeUninit;
    use std::os::unix::io::AsRawFd;

    pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
        unsafe {
            let raw_fd = sock.as_raw_fd();

            let mut uid = MaybeUninit::uninit();
            let mut gid = MaybeUninit::uninit();
            let mut pid: MaybeUninit<pid_t> = MaybeUninit::uninit();
            let mut pid_size: MaybeUninit<u32> = MaybeUninit::new(size_of::<pid_t>() as u32);

            if getsockopt(
                raw_fd,
                SOL_LOCAL,
                LOCAL_PEEREPID,
                pid.as_mut_ptr() as *mut c_void,
                pid_size.as_mut_ptr(),
            ) != 0
            {
                return Err(io::Error::last_os_error());
            }

            assert!(pid_size.assume_init() == (size_of::<pid_t>() as u32));

            let ret = getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr());

            if ret == 0 {
                Ok(super::UCred {
                    uid: uid.assume_init(),
                    gid: gid.assume_init(),
                    pid: Some(pid.assume_init()),
                })
            } else {
                Err(io::Error::last_os_error())
            }
        }
    }
}

#[cfg(any(target_os = "solaris", target_os = "illumos"))]
pub(crate) mod impl_solaris {
    use crate::net::unix::UnixStream;
    use std::io;
    use std::os::unix::io::AsRawFd;
    use std::ptr;

    #[allow(non_camel_case_types)]
    enum ucred_t {}

    extern "C" {
        fn ucred_free(cred: *mut ucred_t);
        fn ucred_geteuid(cred: *const ucred_t) -> super::uid_t;
        fn ucred_getegid(cred: *const ucred_t) -> super::gid_t;

        fn getpeerucred(fd: std::os::raw::c_int, cred: *mut *mut ucred_t) -> std::os::raw::c_int;
    }

    pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
        unsafe {
            let raw_fd = sock.as_raw_fd();

            let mut cred = ptr::null_mut::<*mut ucred_t>() as *mut ucred_t;

            let ret = getpeerucred(raw_fd, &mut cred);

            if ret == 0 {
                let uid = ucred_geteuid(cred);
                let gid = ucred_getegid(cred);

                ucred_free(cred);

                Ok(super::UCred {
                    uid,
                    gid,
                    pid: None,
                })
            } else {
                Err(io::Error::last_os_error())
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate sfml;
#[macro_use]
extern crate log;
extern crate env_logger;

use sfml::window::{ContextSettings, VideoMode, window_style};
use sfml::window::event;
use sfml::graphics::RenderWindow;
use sfml::system::Clock;

mod engine_config;
mod utility;

fn fake_main() -> i32 {
    // Init'ing the log system is the first thing to try. Without it, nothing else
    // can be done or reported, so unwrap() will be used here and ONLY here.
    env_logger::init().unwrap();
    info!("env_logger has been initialized successfully.");

    // TODO: Init Lua here.

    // Acquire the engine configuration. Failing this is a fatal error.
    let engine_config = match engine_config::get_engine_config() {
        Ok(config) => config,
        Err(error) => {
            error!("Failed to acquire engine configuration:\n\t{}", error);
            return 1;
        }
    };

    // TODO: Init the game state here.

    // Initialize the game window. If this can't be done, there's really no point in
    // continuing on.
    let mut window = match RenderWindow::new(VideoMode::new_init(engine_config.screen_width,
                                                                 engine_config.screen_height,
                                                                 32),
                                             "Game Title",
                                             window_style::CLOSE,
                                             &ContextSettings::default()) {
        Some(window) => window,
        None => {
            error!("Could not init a RenderWindow. There is likely a problem with your system.");
            return 1;
        }
    };
    // Set the game's maximum framerate.
    window.set_framerate_limit(engine_config.maximum_framerate);

    // Set up a clock to keep track of how long frames take.
    let frame_clock = Clock::new();
    while window.is_open() {
        // events() returns an iterator over all events in the queue.
        for current_event in window.events() {
            if current_event == event::Closed {
                window.close();
            }
        }

        // TODO: Change the world's state here.

    }
    return 0;
}

fn main() {
    // Fake-main technique. This allows the main() function to return an int (i32) status code.
    std::process::exit(fake_main());
}
<commit_msg>Disable dead code warnings globally.<commit_after>#![allow(dead_code)]

extern crate sfml;
#[macro_use]
extern crate log;
extern crate env_logger;

use sfml::window::{ContextSettings, VideoMode, window_style};
use sfml::window::event;
use sfml::graphics::RenderWindow;
use sfml::system::Clock;

mod engine_config;
mod utility;

fn fake_main() -> i32 {
    // Init'ing the log system is the first thing to try. Without it, nothing else
    // can be done or reported, so unwrap() will be used here and ONLY here.
    env_logger::init().unwrap();
    info!("env_logger has been initialized successfully.");

    // TODO: Init Lua here.

    // Acquire the engine configuration. Failing this is a fatal error.
    let engine_config = match engine_config::get_engine_config() {
        Ok(config) => config,
        Err(error) => {
            error!("Failed to acquire engine configuration:\n\t{}", error);
            return 1;
        }
    };

    // TODO: Init the game state here.

    // Initialize the game window. If this can't be done, there's really no point in
    // continuing on.
    let mut window = match RenderWindow::new(VideoMode::new_init(engine_config.screen_width,
                                                                 engine_config.screen_height,
                                                                 32),
                                             "Game Title",
                                             window_style::CLOSE,
                                             &ContextSettings::default()) {
        Some(window) => window,
        None => {
            error!("Could not init a RenderWindow. There is likely a problem with your system.");
            return 1;
        }
    };
    // Set the game's maximum framerate.
    window.set_framerate_limit(engine_config.maximum_framerate);

    // Set up a clock to keep track of how long frames take.
    let frame_clock = Clock::new();
    while window.is_open() {
        // events() returns an iterator over all events in the queue.
        for current_event in window.events() {
            if current_event == event::Closed {
                window.close();
            }
        }

        // TODO: Change the world's state here.

    }
    return 0;
}

fn main() {
    // Fake-main technique. This allows the main() function to return an int (i32) status code.
    std::process::exit(fake_main());
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Read;
use std::io::Write;
use std::net::SocketAddr;

use futures::done;
use futures::Future;
use futures::stream::Stream;

use tokio_core::io::read_exact;
use tokio_core::io::write_all;
use tokio_core::io::Io;
use tokio_core::net::TcpStream;
use tokio_core::reactor;

use solicit::HttpError;
use solicit::frame::RawFrame;
use solicit::frame::FrameIR;
use solicit::frame::unpack_header;
use solicit::frame::settings::SettingsFrame;
use solicit::frame::settings::HttpSetting;
use solicit::connection::HttpFrame;

pub type HttpFuture<T> = Box<Future<Item=T, Error=HttpError>>;
// Type is called `HttpFutureStream`, not just `HttpStream`
// to avoid confusion with streams from HTTP/2 spec
pub type HttpFutureStream<T> = Box<Stream<Item=T, Error=HttpError>>;

pub type HttpFutureSend<T> = Box<Future<Item=T, Error=HttpError> + Send>;
pub type HttpFutureStreamSend<T> = Box<Stream<Item=T, Error=HttpError> + Send>;

struct VecWithPos<T> {
    vec: Vec<T>,
    pos: usize,
}

impl<T> AsMut<[T]> for VecWithPos<T> {
    fn as_mut(&mut self) -> &mut [T] {
        &mut self.vec[self.pos..]
    }
}

pub fn recv_raw_frame<R : Read + Send + 'static>(read: R) -> HttpFuture<(R, RawFrame)> {
    let header = read_exact(read, [0; 9]);
    let frame_buf = header.and_then(|(read, raw_header)| {
        let header = unpack_header(&raw_header);
        let total_len = 9 + header.0 as usize;
        let mut full_frame = VecWithPos {
            vec: Vec::with_capacity(9),
            pos: 0,
        };

        full_frame.vec.reserve_exact(total_len);
        full_frame.vec.extend(&raw_header);
        full_frame.vec.resize(total_len, 0);
        full_frame.pos = 9;

        read_exact(read, full_frame)
    });
    let frame = frame_buf.map(|(read, frame_buf)| {
        (read, RawFrame::from(frame_buf.vec))
    });
    Box::new(frame
        .map_err(|e| e.into()))
}

#[allow(dead_code)]
pub fn recv_raw_frame_stream<R : Read + Send + 'static>(_read: R) -> HttpFutureStream<RawFrame> {
    // https://users.rust-lang.org/t/futures-rs-how-to-generate-a-stream-from-futures/7020
    panic!();
}

pub fn recv_settings_frame<R : Read + Send + 'static>(read: R) -> HttpFuture<(R, SettingsFrame)> {
    Box::new(recv_raw_frame(read)
        .then(|result| {
            result.and_then(|(read, raw_frame)| {
                match HttpFrame::from_raw(&raw_frame) {
                    Ok(HttpFrame::SettingsFrame(f)) => Ok((read, f)),
                    Ok(_) => Err(HttpError::InvalidFrame),
                    Err(e) => Err(e),
                }
            })
        }))
}

#[allow(dead_code)]
pub fn send_raw_frame<W : Write + Send + 'static>(write: W, frame: RawFrame) -> HttpFuture<W> {
    let bytes = frame.serialize();
    Box::new(write_all(write, bytes)
        .map(|(w, _)| w)
        .map_err(|e| e.into()))
}

pub fn send_frame<W : Write + Send + 'static, F : FrameIR>(write: W, frame: F) -> HttpFuture<W> {
    let mut buf = io::Cursor::new(Vec::with_capacity(16));
    frame.serialize_into(&mut buf).unwrap();
    Box::new(write_all(write, buf.into_inner())
        .map(|(w, _)| w)
        .map_err(|e| e.into()))
}

static PREFACE: &'static [u8] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";

pub fn client_handshake<I : Io + Send + 'static>(conn: I) -> HttpFuture<I> {
    let send_preface = write_all(conn, PREFACE)
        .map(|(conn, _)| conn)
        .map_err(|e| e.into());

    let send_settings = send_preface.and_then(|conn| {
        let settings = {
            let mut frame = SettingsFrame::new();
            frame.add_setting(HttpSetting::EnablePush(0));
            frame
        };
        send_frame(conn, settings)
    });

    let recv_settings = send_settings.and_then(|conn| {
        recv_settings_frame(conn).map(|(conn, _)| conn)
    });

    let done = recv_settings;

    Box::new(done)
}

pub fn server_handshake<I : Io + Send + 'static>(conn: I) -> HttpFuture<I> {
    let mut preface_buf = Vec::with_capacity(PREFACE.len());
    preface_buf.resize(PREFACE.len(), 0);
    let recv_preface = read_exact(conn, preface_buf)
        .map_err(|e| e.into())
        .and_then(|(conn, preface_buf)| {
            done(if preface_buf == PREFACE {
                Ok((conn))
            } else {
                Err(HttpError::InvalidFrame)
            })
        });

    let recv_settings = recv_preface.and_then(|conn| {
        recv_settings_frame(conn).map(|(conn, _)| conn)
    });

    let send_settings = recv_settings.and_then(|conn| {
        send_frame(conn, SettingsFrame::new_ack())
    });

    Box::new(send_settings)
}

pub fn connect_and_handshake(lh: &reactor::Handle, addr: &SocketAddr) -> HttpFuture<TcpStream> {
    let connect = TcpStream::connect(&addr, lh)
        .map_err(|e| e.into());

    let handshake = connect.and_then(client_handshake);

    Box::new(handshake)
}
<commit_msg>Allocate proper capacity and use constant<commit_after>use std::io;
use std::io::Read;
use std::io::Write;
use std::net::SocketAddr;

use futures::done;
use futures::Future;
use futures::stream::Stream;

use tokio_core::io::read_exact;
use tokio_core::io::write_all;
use tokio_core::io::Io;
use tokio_core::net::TcpStream;
use tokio_core::reactor;

use solicit::HttpError;
use solicit::frame::FRAME_HEADER_LEN;
use solicit::frame::RawFrame;
use solicit::frame::FrameIR;
use solicit::frame::unpack_header;
use solicit::frame::settings::SettingsFrame;
use solicit::frame::settings::HttpSetting;
use solicit::connection::HttpFrame;

pub type HttpFuture<T> = Box<Future<Item=T, Error=HttpError>>;
// Type is called `HttpFutureStream`, not just `HttpStream`
// to avoid confusion with streams from HTTP/2 spec
pub type HttpFutureStream<T> = Box<Stream<Item=T, Error=HttpError>>;

pub type HttpFutureSend<T> = Box<Future<Item=T, Error=HttpError> + Send>;
pub type HttpFutureStreamSend<T> = Box<Stream<Item=T, Error=HttpError> + Send>;

struct VecWithPos<T> {
    vec: Vec<T>,
    pos: usize,
}

impl<T> AsMut<[T]> for VecWithPos<T> {
    fn as_mut(&mut self) -> &mut [T] {
        &mut self.vec[self.pos..]
    }
}

pub fn recv_raw_frame<R : Read + Send + 'static>(read: R) -> HttpFuture<(R, RawFrame)> {
    let header = read_exact(read, [0; FRAME_HEADER_LEN]);
    let frame_buf = header.and_then(|(read, raw_header)| {
        let header = unpack_header(&raw_header);
        let total_len = FRAME_HEADER_LEN + header.0 as usize;
        let mut full_frame = VecWithPos {
            vec: Vec::with_capacity(total_len),
            pos: 0,
        };

        full_frame.vec.extend(&raw_header);
        full_frame.vec.resize(total_len, 0);
        full_frame.pos = FRAME_HEADER_LEN;

        read_exact(read, full_frame)
    });
    let frame = frame_buf.map(|(read, frame_buf)| {
        (read, RawFrame::from(frame_buf.vec))
    });
    Box::new(frame
        .map_err(|e| e.into()))
}

#[allow(dead_code)]
pub fn recv_raw_frame_stream<R : Read + Send + 'static>(_read: R) -> HttpFutureStream<RawFrame> {
    // https://users.rust-lang.org/t/futures-rs-how-to-generate-a-stream-from-futures/7020
    panic!();
}

pub fn recv_settings_frame<R : Read + Send + 'static>(read: R) -> HttpFuture<(R, SettingsFrame)> {
    Box::new(recv_raw_frame(read)
        .then(|result| {
            result.and_then(|(read, raw_frame)| {
                match HttpFrame::from_raw(&raw_frame) {
                    Ok(HttpFrame::SettingsFrame(f)) => Ok((read, f)),
                    Ok(_) => Err(HttpError::InvalidFrame),
                    Err(e) => Err(e),
                }
            })
        }))
}

#[allow(dead_code)]
pub fn send_raw_frame<W : Write + Send + 'static>(write: W, frame: RawFrame) -> HttpFuture<W> {
    let bytes = frame.serialize();
    Box::new(write_all(write, bytes)
        .map(|(w, _)| w)
        .map_err(|e| e.into()))
}

pub fn send_frame<W : Write + Send + 'static, F : FrameIR>(write: W, frame: F) -> HttpFuture<W> {
    let mut buf = io::Cursor::new(Vec::with_capacity(16));
    frame.serialize_into(&mut buf).unwrap();
    Box::new(write_all(write, buf.into_inner())
        .map(|(w, _)| w)
        .map_err(|e| e.into()))
}

static PREFACE: &'static [u8] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";

pub fn client_handshake<I : Io + Send + 'static>(conn: I) -> HttpFuture<I> {
    let send_preface = write_all(conn, PREFACE)
        .map(|(conn, _)| conn)
        .map_err(|e| e.into());

    let send_settings = send_preface.and_then(|conn| {
        let settings = {
            let mut frame = SettingsFrame::new();
            frame.add_setting(HttpSetting::EnablePush(0));
            frame
        };
        send_frame(conn, settings)
    });

    let recv_settings = send_settings.and_then(|conn| {
        recv_settings_frame(conn).map(|(conn, _)| conn)
    });

    let done = recv_settings;

    Box::new(done)
}

pub fn server_handshake<I : Io + Send + 'static>(conn: I) -> HttpFuture<I> {
    let mut preface_buf = Vec::with_capacity(PREFACE.len());
    preface_buf.resize(PREFACE.len(), 0);
    let recv_preface = read_exact(conn, preface_buf)
        .map_err(|e| e.into())
        .and_then(|(conn, preface_buf)| {
            done(if preface_buf == PREFACE {
                Ok((conn))
            } else {
                Err(HttpError::InvalidFrame)
            })
        });

    let recv_settings = recv_preface.and_then(|conn| {
        recv_settings_frame(conn).map(|(conn, _)| conn)
    });

    let send_settings = recv_settings.and_then(|conn| {
        send_frame(conn, SettingsFrame::new_ack())
    });

    Box::new(send_settings)
}

pub fn connect_and_handshake(lh: &reactor::Handle, addr: &SocketAddr) -> HttpFuture<TcpStream> {
    let connect = TcpStream::connect(&addr, lh)
        .map_err(|e| e.into());

    let handshake = connect.and_then(client_handshake);

    Box::new(handshake)
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! System Mutexes
//!
//! The Windows implementation of mutexes is a little odd and it may not be
//! immediately obvious what's going on. The primary oddness is that SRWLock is
//! used instead of CriticalSection, and this is done because:
//!
//! 1. SRWLock is several times faster than CriticalSection according to
//!    benchmarks performed on both Windows 8 and Windows 7.
//!
//! 2. CriticalSection allows recursive locking while SRWLock deadlocks. The
//!    Unix implementation deadlocks so consistency is preferred. See #19962 for
//!    more details.
//!
//! 3. While CriticalSection is fair and SRWLock is not, the current Rust policy
//!    is that there are no guarantees of fairness.
//!
//! The downside of this approach, however, is that SRWLock is not available on
//! Windows XP, so we continue to have a fallback implementation where
//! CriticalSection is used and we keep track of who's holding the mutex to
//! detect recursive locks.

use cell::UnsafeCell;
use mem;
use sync::atomic::{AtomicUsize, Ordering};
use sys::c;
use sys::compat;

pub struct Mutex {
    lock: AtomicUsize,
    held: UnsafeCell<bool>,
}

unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}

#[derive(Clone, Copy)]
enum Kind {
    SRWLock = 1,
    CriticalSection = 2,
}

#[inline]
pub unsafe fn raw(m: &Mutex) -> c::PSRWLOCK {
    debug_assert!(mem::size_of::<c::SRWLOCK>() <= mem::size_of_val(&m.lock));
    &m.lock as *const _ as *mut _
}

impl Mutex {
    pub const fn new() -> Mutex {
        Mutex {
            // This works because SRWLOCK_INIT is 0 (wrapped in a struct), so we are also properly
            // initializing an SRWLOCK here.
            lock: AtomicUsize::new(0),
            held: UnsafeCell::new(false),
        }
    }
    #[inline]
    pub unsafe fn init(&mut self) {}
    pub unsafe fn lock(&self) {
        match kind() {
            Kind::SRWLock => c::AcquireSRWLockExclusive(raw(self)),
            Kind::CriticalSection => {
                let re = self.remutex();
                (*re).lock();
                if !self.flag_locked() {
                    (*re).unlock();
                    panic!("cannot recursively lock a mutex");
                }
            }
        }
    }
    pub unsafe fn try_lock(&self) -> bool {
        match kind() {
            Kind::SRWLock => c::TryAcquireSRWLockExclusive(raw(self)) != 0,
            Kind::CriticalSection => {
                let re = self.remutex();
                if !(*re).try_lock() {
                    false
                } else if self.flag_locked() {
                    true
                } else {
                    (*re).unlock();
                    false
                }
            }
        }
    }
    pub unsafe fn unlock(&self) {
        *self.held.get() = false;
        match kind() {
            Kind::SRWLock => c::ReleaseSRWLockExclusive(raw(self)),
            Kind::CriticalSection => (*self.remutex()).unlock(),
        }
    }
    pub unsafe fn destroy(&self) {
        match kind() {
            Kind::SRWLock => {}
            Kind::CriticalSection => {
                match self.lock.load(Ordering::SeqCst) {
                    0 => {}
                    n => { Box::from_raw(n as *mut ReentrantMutex).destroy(); }
                }
            }
        }
    }

    unsafe fn remutex(&self) -> *mut ReentrantMutex {
        match self.lock.load(Ordering::SeqCst) {
            0 => {}
            n => return n as *mut _,
        }
        let mut re = box ReentrantMutex::uninitialized();
        re.init();
        let re = Box::into_raw(re);
        match self.lock.compare_and_swap(0, re as usize, Ordering::SeqCst) {
            0 => re,
            n => { Box::from_raw(re).destroy(); n as *mut _ }
        }
    }

    unsafe fn flag_locked(&self) -> bool {
        if *self.held.get() {
            false
        } else {
            *self.held.get() = true;
            true
        }

    }
}

fn kind() -> Kind {
    static KIND: AtomicUsize = AtomicUsize::new(0);

    let val = KIND.load(Ordering::SeqCst);
    if val == Kind::SRWLock as usize {
        return Kind::SRWLock
    } else if val == Kind::CriticalSection as usize {
        return Kind::CriticalSection
    }

    let ret = match compat::lookup("kernel32", "AcquireSRWLockExclusive") {
        None => Kind::CriticalSection,
        Some(..) => Kind::SRWLock,
    };
    KIND.store(ret as usize, Ordering::SeqCst);
    return ret;
}

pub struct ReentrantMutex { inner: UnsafeCell<c::CRITICAL_SECTION> }

unsafe impl Send for ReentrantMutex {}
unsafe impl Sync for ReentrantMutex {}

impl ReentrantMutex {
    pub unsafe fn uninitialized() -> ReentrantMutex {
        mem::uninitialized()
    }

    pub unsafe fn init(&mut self) {
        c::InitializeCriticalSection(self.inner.get());
    }

    pub unsafe fn lock(&self) {
        c::EnterCriticalSection(self.inner.get());
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        c::TryEnterCriticalSection(self.inner.get()) != 0
    }

    pub unsafe fn unlock(&self) {
        c::LeaveCriticalSection(self.inner.get());
    }

    pub unsafe fn destroy(&self) {
        c::DeleteCriticalSection(self.inner.get());
    }
}
<commit_msg>use MaybeUninit instead of mem::uninitialized for Windows Mutex<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! System Mutexes
//!
//! The Windows implementation of mutexes is a little odd and it may not be
//! immediately obvious what's going on. The primary oddness is that SRWLock is
//! used instead of CriticalSection, and this is done because:
//!
//! 1. SRWLock is several times faster than CriticalSection according to
//!    benchmarks performed on both Windows 8 and Windows 7.
//!
//! 2. CriticalSection allows recursive locking while SRWLock deadlocks. The
//!    Unix implementation deadlocks so consistency is preferred. See #19962 for
//!    more details.
//!
//! 3. While CriticalSection is fair and SRWLock is not, the current Rust policy
//!    is that there are no guarantees of fairness.
//!
//! The downside of this approach, however, is that SRWLock is not available on
//! Windows XP, so we continue to have a fallback implementation where
//! CriticalSection is used and we keep track of who's holding the mutex to
//! detect recursive locks.

use cell::UnsafeCell;
use mem::{self, MaybeUninit};
use sync::atomic::{AtomicUsize, Ordering};
use sys::c;
use sys::compat;

pub struct Mutex {
    lock: AtomicUsize,
    held: UnsafeCell<bool>,
}

unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}

#[derive(Clone, Copy)]
enum Kind {
    SRWLock = 1,
    CriticalSection = 2,
}

#[inline]
pub unsafe fn raw(m: &Mutex) -> c::PSRWLOCK {
    debug_assert!(mem::size_of::<c::SRWLOCK>() <= mem::size_of_val(&m.lock));
    &m.lock as *const _ as *mut _
}

impl Mutex {
    pub const fn new() -> Mutex {
        Mutex {
            // This works because SRWLOCK_INIT is 0 (wrapped in a struct), so we are also properly
            // initializing an SRWLOCK here.
            lock: AtomicUsize::new(0),
            held: UnsafeCell::new(false),
        }
    }
    #[inline]
    pub unsafe fn init(&mut self) {}
    pub unsafe fn lock(&self) {
        match kind() {
            Kind::SRWLock => c::AcquireSRWLockExclusive(raw(self)),
            Kind::CriticalSection => {
                let re = self.remutex();
                (*re).lock();
                if !self.flag_locked() {
                    (*re).unlock();
                    panic!("cannot recursively lock a mutex");
                }
            }
        }
    }
    pub unsafe fn try_lock(&self) -> bool {
        match kind() {
            Kind::SRWLock => c::TryAcquireSRWLockExclusive(raw(self)) != 0,
            Kind::CriticalSection => {
                let re = self.remutex();
                if !(*re).try_lock() {
                    false
                } else if self.flag_locked() {
                    true
                } else {
                    (*re).unlock();
                    false
                }
            }
        }
    }
    pub unsafe fn unlock(&self) {
        *self.held.get() = false;
        match kind() {
            Kind::SRWLock => c::ReleaseSRWLockExclusive(raw(self)),
            Kind::CriticalSection => (*self.remutex()).unlock(),
        }
    }
    pub unsafe fn destroy(&self) {
        match kind() {
            Kind::SRWLock => {}
            Kind::CriticalSection => {
                match self.lock.load(Ordering::SeqCst) {
                    0 => {}
                    n => { Box::from_raw(n as *mut ReentrantMutex).destroy(); }
                }
            }
        }
    }

    unsafe fn remutex(&self) -> *mut ReentrantMutex {
        match self.lock.load(Ordering::SeqCst) {
            0 => {}
            n => return n as *mut _,
        }
        let mut re = box ReentrantMutex::uninitialized();
        re.init();
        let re = Box::into_raw(re);
        match self.lock.compare_and_swap(0, re as usize, Ordering::SeqCst) {
            0 => re,
            n => { Box::from_raw(re).destroy(); n as *mut _ }
        }
    }

    unsafe fn flag_locked(&self) -> bool {
        if *self.held.get() {
            false
        } else {
            *self.held.get() = true;
            true
        }

    }
}

fn kind() -> Kind {
    static KIND: AtomicUsize = AtomicUsize::new(0);

    let val = KIND.load(Ordering::SeqCst);
    if val == Kind::SRWLock as usize {
        return Kind::SRWLock
    } else if val == Kind::CriticalSection as usize {
        return Kind::CriticalSection
    }

    let ret = match compat::lookup("kernel32", "AcquireSRWLockExclusive") {
        None => Kind::CriticalSection,
        Some(..) => Kind::SRWLock,
    };
    KIND.store(ret as usize, Ordering::SeqCst);
    return ret;
}

pub struct ReentrantMutex { inner: MaybeUninit<UnsafeCell<c::CRITICAL_SECTION>> }

unsafe impl Send for ReentrantMutex {}
unsafe impl Sync for ReentrantMutex {}

impl ReentrantMutex {
    pub fn uninitialized() -> ReentrantMutex {
        MaybeUninit::uninitialized()
    }

    pub unsafe fn init(&mut self) {
        c::InitializeCriticalSection(self.inner.get_ref().get());
    }

    pub unsafe fn lock(&self) {
        c::EnterCriticalSection(self.inner.get_ref().get());
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        c::TryEnterCriticalSection(self.inner.get_ref().get()) != 0
    }

    pub unsafe fn unlock(&self) {
        c::LeaveCriticalSection(self.inner.get_ref().get());
    }

    pub unsafe fn destroy(&self) {
        c::DeleteCriticalSection(self.inner.get_ref().get());
    }
}
<|endoftext|>