<commit_before>//! Matrix room version identifiers.

use std::{
    cmp::Ordering,
    convert::TryFrom,
    fmt::{self, Display, Formatter},
};

#[cfg(feature = "serde")]
use serde1::{Deserialize, Deserializer, Serialize, Serializer};

use crate::Error;

/// A Matrix room version ID.
///
/// A `RoomVersionId` can be or converted or deserialized from a string slice, and can be converted
/// or serialized back into a string as needed.
///
/// ```
/// # use std::convert::TryFrom;
/// # use ruma_identifiers::RoomVersionId;
/// assert_eq!(RoomVersionId::try_from("1").unwrap().as_ref(), "1");
/// ```
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum RoomVersionId {
    /// A version 1 room.
    Version1,

    /// A version 2 room.
    Version2,

    /// A version 3 room.
    Version3,

    /// A version 4 room.
    Version4,

    /// A version 5 room.
    Version5,

    /// A version 6 room.
    Version6,

    /// A custom room version.
    Custom(CustomRoomVersion),
}

impl RoomVersionId {
    /// Creates a version 1 room ID.
    #[deprecated = "use RoomVersionId::Version1 instead"]
    pub fn version_1() -> Self {
        Self::Version1
    }

    /// Creates a version 2 room ID.
    #[deprecated = "use RoomVersionId::Version2 instead"]
    pub fn version_2() -> Self {
        Self::Version2
    }

    /// Creates a version 3 room ID.
    #[deprecated = "use RoomVersionId::Version3 instead"]
    pub fn version_3() -> Self {
        Self::Version3
    }

    /// Creates a version 4 room ID.
    #[deprecated = "use RoomVersionId::Version4 instead"]
    pub fn version_4() -> Self {
        Self::Version4
    }

    /// Creates a version 5 room ID.
    #[deprecated = "use RoomVersionId::Version5 instead"]
    pub fn version_5() -> Self {
        Self::Version5
    }

    /// Creates a version 6 room ID.
    #[deprecated = "use RoomVersionId::Version6 instead"]
    pub fn version_6() -> Self {
        Self::Version6
    }

    /// Creates a string slice from this `RoomVersionId`.
    pub fn as_str(&self) -> &str {
        match &self {
            Self::Version1 => "1",
            Self::Version2 => "2",
            Self::Version3 => "3",
            Self::Version4 => "4",
            Self::Version5 => "5",
            Self::Version6 => "6",
            Self::Custom(version) => version.as_str(),
        }
    }

    /// Creates a byte slice from this `RoomVersionId`.
    pub fn as_bytes(&self) -> &[u8] {
        self.as_str().as_bytes()
    }

    /// Whether or not this room version is an official one specified by the Matrix protocol.
    pub fn is_official(&self) -> bool {
        !self.is_custom()
    }

    /// Whether or not this is a custom room version.
    pub fn is_custom(&self) -> bool {
        matches!(self, Self::Custom(_))
    }

    /// Whether or not this is a version 1 room.
    #[deprecated = "compare to RoomVersionId::Version1 instead"]
    pub fn is_version_1(&self) -> bool {
        matches!(self, Self::Version1)
    }

    /// Whether or not this is a version 2 room.
    #[deprecated = "compare to RoomVersionId::Version2 instead"]
    pub fn is_version_2(&self) -> bool {
        matches!(self, Self::Version2)
    }

    /// Whether or not this is a version 3 room.
    #[deprecated = "compare to RoomVersionId::Version3 instead"]
    pub fn is_version_3(&self) -> bool {
        matches!(self, Self::Version3)
    }

    /// Whether or not this is a version 4 room.
    #[deprecated = "compare to RoomVersionId::Version4 instead"]
    pub fn is_version_4(&self) -> bool {
        matches!(self, Self::Version4)
    }

    /// Whether or not this is a version 5 room.
    #[deprecated = "compare to RoomVersionId::Version5 instead"]
    pub fn is_version_5(&self) -> bool {
        matches!(self, Self::Version5)
    }

    /// Whether or not this is a version 6 room.
    #[deprecated = "compare to RoomVersionId::Version6 instead"]
    pub fn is_version_6(&self) -> bool {
        matches!(self, Self::Version6)
    }
}

impl From<RoomVersionId> for String {
    fn from(id: RoomVersionId) -> Self {
        match id {
            RoomVersionId::Version1 => "1".to_owned(),
            RoomVersionId::Version2 => "2".to_owned(),
            RoomVersionId::Version3 => "3".to_owned(),
            RoomVersionId::Version4 => "4".to_owned(),
            RoomVersionId::Version5 => "5".to_owned(),
            RoomVersionId::Version6 => "6".to_owned(),
            RoomVersionId::Custom(version) => version.into(),
        }
    }
}

impl AsRef<str> for RoomVersionId {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl Display for RoomVersionId {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.as_ref())
    }
}

impl PartialOrd for RoomVersionId {
    /// Compare the two given room version IDs by comparing their string representations.
    ///
    /// Please be aware that room version IDs don't have a defined ordering in the Matrix
    /// specification. This implementation only exists to be able to use `RoomVersionId`s or
    /// types containing `RoomVersionId`s as `BTreeMap` keys.
    fn partial_cmp(&self, other: &RoomVersionId) -> Option<Ordering> {
        self.as_ref().partial_cmp(other.as_ref())
    }
}

impl Ord for RoomVersionId {
    /// Compare the two given room version IDs by comparing their string representations.
    ///
    /// Please be aware that room version IDs don't have a defined ordering in the Matrix
    /// specification. This implementation only exists to be able to use `RoomVersionId`s or
    /// types containing `RoomVersionId`s as `BTreeMap` keys.
    fn cmp(&self, other: &Self) -> Ordering {
        self.as_ref().cmp(other.as_ref())
    }
}

#[cfg(feature = "serde")]
impl Serialize for RoomVersionId {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(self.as_ref())
    }
}

#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for RoomVersionId {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        crate::deserialize_id(deserializer, "a Matrix room version ID as a string")
    }
}

/// Attempts to create a new Matrix room version ID from a string representation.
fn try_from<S>(room_version_id: S) -> Result<RoomVersionId, Error>
where
    S: AsRef<str> + Into<Box<str>>,
{
    let version = match room_version_id.as_ref() {
        "1" => RoomVersionId::Version1,
        "2" => RoomVersionId::Version2,
        "3" => RoomVersionId::Version3,
        "4" => RoomVersionId::Version4,
        "5" => RoomVersionId::Version5,
        "6" => RoomVersionId::Version6,
        custom => {
            ruma_identifiers_validation::room_version_id::validate(custom)?;
            RoomVersionId::Custom(CustomRoomVersion(room_version_id.into()))
        }
    };

    Ok(version)
}

impl TryFrom<&str> for RoomVersionId {
    type Error = crate::Error;

    fn try_from(s: &str) -> Result<Self, Error> {
        try_from(s)
    }
}

impl TryFrom<String> for RoomVersionId {
    type Error = crate::Error;

    fn try_from(s: String) -> Result<Self, Error> {
        try_from(s)
    }
}

impl PartialEq<&str> for RoomVersionId {
    fn eq(&self, other: &&str) -> bool {
        self.as_str() == *other
    }
}

impl PartialEq<RoomVersionId> for &str {
    fn eq(&self, other: &RoomVersionId) -> bool {
        *self == other.as_str()
    }
}

impl PartialEq<String> for RoomVersionId {
    fn eq(&self, other: &String) -> bool {
        self.as_str() == other
    }
}

impl PartialEq<RoomVersionId> for String {
    fn eq(&self, other: &RoomVersionId) -> bool {
        self == other.as_str()
    }
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct CustomRoomVersion(Box<str>);

impl CustomRoomVersion {
    /// Creates a string slice from this `CustomRoomVersion`
    pub fn as_str(&self) -> &str {
        &self.0
    }
}

impl From<CustomRoomVersion> for String {
    fn from(v: CustomRoomVersion) -> Self {
        v.0.into()
    }
}

impl AsRef<str> for CustomRoomVersion {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

#[cfg(test)]
mod tests {
    use std::convert::TryFrom;

    #[cfg(feature = "serde")]
    use serde_json::{from_str, to_string};

    use super::RoomVersionId;
    use crate::Error;

    #[test]
    fn valid_version_1_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("1").expect("Failed to create RoomVersionId.").as_ref(),
            "1"
        );
    }

    #[test]
    fn valid_version_2_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("2").expect("Failed to create RoomVersionId.").as_ref(),
            "2"
        );
    }

    #[test]
    fn valid_version_3_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("3").expect("Failed to create RoomVersionId.").as_ref(),
            "3"
        );
    }

    #[test]
    fn valid_version_4_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("4").expect("Failed to create RoomVersionId.").as_ref(),
            "4"
        );
    }

    #[test]
    fn valid_version_5_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("5").expect("Failed to create RoomVersionId.").as_ref(),
            "5"
        );
    }

    #[test]
    fn valid_version_6_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("6").expect("Failed to create RoomVersionId.").as_ref(),
            "6"
        );
    }

    #[test]
    fn valid_custom_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("io.ruma.1").expect("Failed to create RoomVersionId.").as_ref(),
            "io.ruma.1"
        );
    }

    #[test]
    fn empty_room_version_id() {
        assert_eq!(RoomVersionId::try_from(""), Err(Error::MinimumLengthNotSatisfied));
    }

    #[test]
    fn over_max_code_point_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("0123456789012345678901234567890123456789"),
            Err(Error::MaximumLengthExceeded)
        );
    }

    #[cfg(feature = "serde")]
    #[test]
    fn serialize_official_room_id() {
        assert_eq!(
            to_string(&RoomVersionId::try_from("1").expect("Failed to create RoomVersionId."))
                .expect("Failed to convert RoomVersionId to JSON."),
            r#""1""#
        );
    }

    #[cfg(feature = "serde")]
    #[test]
    fn deserialize_official_room_id() {
        let deserialized =
            from_str::<RoomVersionId>(r#""1""#).expect("Failed to convert RoomVersionId to JSON.");

        assert_eq!(deserialized, RoomVersionId::Version1);
        assert!(deserialized.is_official());

        assert_eq!(
            deserialized,
            RoomVersionId::try_from("1").expect("Failed to create RoomVersionId.")
        );
    }

    #[cfg(feature = "serde")]
    #[test]
    fn serialize_custom_room_id() {
        assert_eq!(
            to_string(
                &RoomVersionId::try_from("io.ruma.1").expect("Failed to create RoomVersionId.")
            )
            .expect("Failed to convert RoomVersionId to JSON."),
            r#""io.ruma.1""#
        );
    }

    #[cfg(feature = "serde")]
    #[test]
    fn deserialize_custom_room_id() {
        let deserialized = from_str::<RoomVersionId>(r#""io.ruma.1""#)
            .expect("Failed to convert RoomVersionId to JSON.");

        assert!(deserialized.is_custom());

        assert_eq!(
            deserialized,
            RoomVersionId::try_from("io.ruma.1").expect("Failed to create RoomVersionId.")
        );
    }

    #[test]
    #[allow(deprecated)]
    fn constructors() {
        assert!(RoomVersionId::version_1().is_version_1());
        assert!(RoomVersionId::version_2().is_version_2());
        assert!(RoomVersionId::version_3().is_version_3());
        assert!(RoomVersionId::version_4().is_version_4());
        assert!(RoomVersionId::version_5().is_version_5());
        assert!(RoomVersionId::version_6().is_version_6());
    }

    #[test]
    #[allow(deprecated, clippy::cognitive_complexity)]
    fn predicate_methods() {
        let version_1 = RoomVersionId::try_from("1").expect("Failed to create RoomVersionId.");
        let version_2 = RoomVersionId::try_from("2").expect("Failed to create RoomVersionId.");
        let version_3 = RoomVersionId::try_from("3").expect("Failed to create RoomVersionId.");
        let version_4 = RoomVersionId::try_from("4").expect("Failed to create RoomVersionId.");
        let version_5 = RoomVersionId::try_from("5").expect("Failed to create RoomVersionId.");
        let version_6 = RoomVersionId::try_from("6").expect("Failed to create RoomVersionId.");
        let custom = RoomVersionId::try_from("io.ruma.1").expect("Failed to create RoomVersionId.");

        assert!(version_1.is_version_1());
        assert!(version_2.is_version_2());
        assert!(version_3.is_version_3());
        assert!(version_4.is_version_4());
        assert!(version_5.is_version_5());
        assert!(version_6.is_version_6());

        assert!(!version_1.is_version_2());
        assert!(!version_1.is_version_3());
        assert!(!version_1.is_version_4());
        assert!(!version_1.is_version_5());
        assert!(!version_1.is_version_6());

        assert!(version_1.is_official());
        assert!(version_2.is_official());
        assert!(version_3.is_official());
        assert!(version_4.is_official());
        assert!(version_5.is_official());
        assert!(version_6.is_official());

        assert!(!version_1.is_custom());
        assert!(!version_2.is_custom());
        assert!(!version_3.is_custom());
        assert!(!version_4.is_custom());
        assert!(!version_5.is_custom());
        assert!(!version_6.is_custom());

        assert!(custom.is_custom());
        assert!(!custom.is_official());
        assert!(!custom.is_version_1());
        assert!(!custom.is_version_2());
        assert!(!custom.is_version_3());
        assert!(!custom.is_version_4());
        assert!(!custom.is_version_5());
        assert!(!custom.is_version_6());
    }
}
<commit_msg>Clean up room version id tests<commit_after>//! Matrix room version identifiers.

use std::{
    cmp::Ordering,
    convert::TryFrom,
    fmt::{self, Display, Formatter},
};

#[cfg(feature = "serde")]
use serde1::{Deserialize, Deserializer, Serialize, Serializer};

use crate::Error;

/// A Matrix room version ID.
///
/// A `RoomVersionId` can be or converted or deserialized from a string slice, and can be converted
/// or serialized back into a string as needed.
///
/// ```
/// # use std::convert::TryFrom;
/// # use ruma_identifiers::RoomVersionId;
/// assert_eq!(RoomVersionId::try_from("1").unwrap().as_ref(), "1");
/// ```
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum RoomVersionId {
    /// A version 1 room.
    Version1,

    /// A version 2 room.
    Version2,

    /// A version 3 room.
    Version3,

    /// A version 4 room.
    Version4,

    /// A version 5 room.
    Version5,

    /// A version 6 room.
    Version6,

    /// A custom room version.
    Custom(CustomRoomVersion),
}

impl RoomVersionId {
    /// Creates a version 1 room ID.
    #[deprecated = "use RoomVersionId::Version1 instead"]
    pub fn version_1() -> Self {
        Self::Version1
    }

    /// Creates a version 2 room ID.
    #[deprecated = "use RoomVersionId::Version2 instead"]
    pub fn version_2() -> Self {
        Self::Version2
    }

    /// Creates a version 3 room ID.
    #[deprecated = "use RoomVersionId::Version3 instead"]
    pub fn version_3() -> Self {
        Self::Version3
    }

    /// Creates a version 4 room ID.
    #[deprecated = "use RoomVersionId::Version4 instead"]
    pub fn version_4() -> Self {
        Self::Version4
    }

    /// Creates a version 5 room ID.
    #[deprecated = "use RoomVersionId::Version5 instead"]
    pub fn version_5() -> Self {
        Self::Version5
    }

    /// Creates a version 6 room ID.
    #[deprecated = "use RoomVersionId::Version6 instead"]
    pub fn version_6() -> Self {
        Self::Version6
    }

    /// Creates a string slice from this `RoomVersionId`.
    pub fn as_str(&self) -> &str {
        match &self {
            Self::Version1 => "1",
            Self::Version2 => "2",
            Self::Version3 => "3",
            Self::Version4 => "4",
            Self::Version5 => "5",
            Self::Version6 => "6",
            Self::Custom(version) => version.as_str(),
        }
    }

    /// Creates a byte slice from this `RoomVersionId`.
    pub fn as_bytes(&self) -> &[u8] {
        self.as_str().as_bytes()
    }

    /// Whether or not this room version is an official one specified by the Matrix protocol.
    pub fn is_official(&self) -> bool {
        !self.is_custom()
    }

    /// Whether or not this is a custom room version.
    pub fn is_custom(&self) -> bool {
        matches!(self, Self::Custom(_))
    }

    /// Whether or not this is a version 1 room.
    #[deprecated = "compare to RoomVersionId::Version1 instead"]
    pub fn is_version_1(&self) -> bool {
        matches!(self, Self::Version1)
    }

    /// Whether or not this is a version 2 room.
    #[deprecated = "compare to RoomVersionId::Version2 instead"]
    pub fn is_version_2(&self) -> bool {
        matches!(self, Self::Version2)
    }

    /// Whether or not this is a version 3 room.
    #[deprecated = "compare to RoomVersionId::Version3 instead"]
    pub fn is_version_3(&self) -> bool {
        matches!(self, Self::Version3)
    }

    /// Whether or not this is a version 4 room.
    #[deprecated = "compare to RoomVersionId::Version4 instead"]
    pub fn is_version_4(&self) -> bool {
        matches!(self, Self::Version4)
    }

    /// Whether or not this is a version 5 room.
    #[deprecated = "compare to RoomVersionId::Version5 instead"]
    pub fn is_version_5(&self) -> bool {
        matches!(self, Self::Version5)
    }

    /// Whether or not this is a version 6 room.
    #[deprecated = "compare to RoomVersionId::Version6 instead"]
    pub fn is_version_6(&self) -> bool {
        matches!(self, Self::Version6)
    }
}

impl From<RoomVersionId> for String {
    fn from(id: RoomVersionId) -> Self {
        match id {
            RoomVersionId::Version1 => "1".to_owned(),
            RoomVersionId::Version2 => "2".to_owned(),
            RoomVersionId::Version3 => "3".to_owned(),
            RoomVersionId::Version4 => "4".to_owned(),
            RoomVersionId::Version5 => "5".to_owned(),
            RoomVersionId::Version6 => "6".to_owned(),
            RoomVersionId::Custom(version) => version.into(),
        }
    }
}

impl AsRef<str> for RoomVersionId {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl Display for RoomVersionId {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.as_ref())
    }
}

impl PartialOrd for RoomVersionId {
    /// Compare the two given room version IDs by comparing their string representations.
    ///
    /// Please be aware that room version IDs don't have a defined ordering in the Matrix
    /// specification. This implementation only exists to be able to use `RoomVersionId`s or
    /// types containing `RoomVersionId`s as `BTreeMap` keys.
    fn partial_cmp(&self, other: &RoomVersionId) -> Option<Ordering> {
        self.as_ref().partial_cmp(other.as_ref())
    }
}

impl Ord for RoomVersionId {
    /// Compare the two given room version IDs by comparing their string representations.
    ///
    /// Please be aware that room version IDs don't have a defined ordering in the Matrix
    /// specification. This implementation only exists to be able to use `RoomVersionId`s or
    /// types containing `RoomVersionId`s as `BTreeMap` keys.
    fn cmp(&self, other: &Self) -> Ordering {
        self.as_ref().cmp(other.as_ref())
    }
}

#[cfg(feature = "serde")]
impl Serialize for RoomVersionId {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(self.as_ref())
    }
}

#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for RoomVersionId {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        crate::deserialize_id(deserializer, "a Matrix room version ID as a string")
    }
}

/// Attempts to create a new Matrix room version ID from a string representation.
fn try_from<S>(room_version_id: S) -> Result<RoomVersionId, Error>
where
    S: AsRef<str> + Into<Box<str>>,
{
    let version = match room_version_id.as_ref() {
        "1" => RoomVersionId::Version1,
        "2" => RoomVersionId::Version2,
        "3" => RoomVersionId::Version3,
        "4" => RoomVersionId::Version4,
        "5" => RoomVersionId::Version5,
        "6" => RoomVersionId::Version6,
        custom => {
            ruma_identifiers_validation::room_version_id::validate(custom)?;
            RoomVersionId::Custom(CustomRoomVersion(room_version_id.into()))
        }
    };

    Ok(version)
}

impl TryFrom<&str> for RoomVersionId {
    type Error = crate::Error;

    fn try_from(s: &str) -> Result<Self, Error> {
        try_from(s)
    }
}

impl TryFrom<String> for RoomVersionId {
    type Error = crate::Error;

    fn try_from(s: String) -> Result<Self, Error> {
        try_from(s)
    }
}

impl PartialEq<&str> for RoomVersionId {
    fn eq(&self, other: &&str) -> bool {
        self.as_str() == *other
    }
}

impl PartialEq<RoomVersionId> for &str {
    fn eq(&self, other: &RoomVersionId) -> bool {
        *self == other.as_str()
    }
}

impl PartialEq<String> for RoomVersionId {
    fn eq(&self, other: &String) -> bool {
        self.as_str() == other
    }
}

impl PartialEq<RoomVersionId> for String {
    fn eq(&self, other: &RoomVersionId) -> bool {
        self == other.as_str()
    }
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct CustomRoomVersion(Box<str>);

impl CustomRoomVersion {
    /// Creates a string slice from this `CustomRoomVersion`
    pub fn as_str(&self) -> &str {
        &self.0
    }
}

impl From<CustomRoomVersion> for String {
    fn from(v: CustomRoomVersion) -> Self {
        v.0.into()
    }
}

impl AsRef<str> for CustomRoomVersion {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

#[cfg(test)]
mod tests {
    use std::convert::TryFrom;

    #[cfg(feature = "serde")]
    use serde_json::{from_str, to_string};

    use super::{CustomRoomVersion, RoomVersionId};
    use crate::Error;

    #[test]
    fn valid_version_1_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("1").expect("Failed to create RoomVersionId.").as_ref(),
            "1"
        );
    }

    #[test]
    fn valid_version_2_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("2").expect("Failed to create RoomVersionId.").as_ref(),
            "2"
        );
    }

    #[test]
    fn valid_version_3_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("3").expect("Failed to create RoomVersionId.").as_ref(),
            "3"
        );
    }

    #[test]
    fn valid_version_4_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("4").expect("Failed to create RoomVersionId.").as_ref(),
            "4"
        );
    }

    #[test]
    fn valid_version_5_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("5").expect("Failed to create RoomVersionId.").as_ref(),
            "5"
        );
    }

    #[test]
    fn valid_version_6_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("6").expect("Failed to create RoomVersionId.").as_ref(),
            "6"
        );
    }

    #[test]
    fn valid_custom_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("io.ruma.1").expect("Failed to create RoomVersionId.").as_ref(),
            "io.ruma.1"
        );
    }

    #[test]
    fn empty_room_version_id() {
        assert_eq!(RoomVersionId::try_from(""), Err(Error::MinimumLengthNotSatisfied));
    }

    #[test]
    fn over_max_code_point_room_version_id() {
        assert_eq!(
            RoomVersionId::try_from("0123456789012345678901234567890123456789"),
            Err(Error::MaximumLengthExceeded)
        );
    }

    #[cfg(feature = "serde")]
    #[test]
    fn serialize_official_room_id() {
        assert_eq!(
            to_string(&RoomVersionId::try_from("1").expect("Failed to create RoomVersionId."))
                .expect("Failed to convert RoomVersionId to JSON."),
            r#""1""#
        );
    }

    #[cfg(feature = "serde")]
    #[test]
    fn deserialize_official_room_id() {
        let deserialized =
            from_str::<RoomVersionId>(r#""1""#).expect("Failed to convert RoomVersionId to JSON.");

        assert_eq!(deserialized, RoomVersionId::Version1);
        assert!(deserialized.is_official());

        assert_eq!(
            deserialized,
            RoomVersionId::try_from("1").expect("Failed to create RoomVersionId.")
        );
    }

    #[cfg(feature = "serde")]
    #[test]
    fn serialize_custom_room_id() {
        assert_eq!(
            to_string(
                &RoomVersionId::try_from("io.ruma.1").expect("Failed to create RoomVersionId.")
            )
            .expect("Failed to convert RoomVersionId to JSON."),
            r#""io.ruma.1""#
        );
    }

    #[cfg(feature = "serde")]
    #[test]
    fn deserialize_custom_room_id() {
        let deserialized = from_str::<RoomVersionId>(r#""io.ruma.1""#)
            .expect("Failed to convert RoomVersionId to JSON.");

        assert!(deserialized.is_custom());

        assert_eq!(
            deserialized,
            RoomVersionId::try_from("io.ruma.1").expect("Failed to create RoomVersionId.")
        );
    }

    #[test]
    #[allow(deprecated)]
    fn constructors() {
        assert!(RoomVersionId::version_1().is_version_1());
        assert!(RoomVersionId::version_2().is_version_2());
        assert!(RoomVersionId::version_3().is_version_3());
        assert!(RoomVersionId::version_4().is_version_4());
        assert!(RoomVersionId::version_5().is_version_5());
        assert!(RoomVersionId::version_6().is_version_6());
    }

    #[test]
    fn official_versions() {
        assert!(RoomVersionId::Version1.is_official());
        assert!(RoomVersionId::Version2.is_official());
        assert!(RoomVersionId::Version3.is_official());
        assert!(RoomVersionId::Version4.is_official());
        assert!(RoomVersionId::Version5.is_official());
        assert!(RoomVersionId::Version6.is_official());
        assert!(!RoomVersionId::Custom(CustomRoomVersion("io.ruma.1".into())).is_official());
    }

    #[test]
    fn custom_versions() {
        assert!(!RoomVersionId::Version1.is_custom());
        assert!(!RoomVersionId::Version2.is_custom());
        assert!(!RoomVersionId::Version3.is_custom());
        assert!(!RoomVersionId::Version4.is_custom());
        assert!(!RoomVersionId::Version5.is_custom());
        assert!(!RoomVersionId::Version6.is_custom());
        assert!(RoomVersionId::Custom(CustomRoomVersion("io.ruma.1".into())).is_custom());
    }
}
<|endoftext|>


<commit_before>use std::fmt::{self, Display, Formatter};
use rlua::{self, Table, Lua, UserData, UserDataMethods};
use super::{class, object};

use rustwlc::*;
#[allow(deprecated)]
use rustwlc::xkb::Keysym;

#[derive(Clone, Debug)]
pub struct Button {
    num: u32
}

impl Display for Button {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Button: {:p}", self)
    }
}

impl UserData for Button {
    fn add_methods(methods: &mut UserDataMethods<Self>) {
        object::add_meta_methods(methods);
        class::add_meta_methods(methods);
    }
}

/// Makes a new button stored in a table beside its signals
pub fn new(lua: &Lua, num: u32) -> rlua::Result<Table> {
    let button_table = lua.create_table();
    button_table.set("data", Button { num })?;
    let meta = lua.create_table();
    meta.set("__index", lua.create_function(default_index))?;
    meta.set("signals", lua.create_table());
    meta.set("__tostring", lua.create_function(|_, button_table: Table|
                                               Ok(format!("{}", button_table.get::<_, Button>("data").unwrap()))));
    button_table.set_metatable(Some(meta));
    Ok(button_table)
}

fn default_index<'lua>(lua: &'lua Lua, (button_table, index): (Table<'lua>, String))
                 -> rlua::Result<rlua::Value<'lua>> {
    if let Ok(val) = button_table.get::<_, rlua::Value>(index.clone()) {
        return Ok(val)
    }
    // TODO error handling
    let button = button_table.raw_get::<_, Button>("data").unwrap();
    match index.as_str() {
        "connect_signal" => {
            lua.globals().set("__temp", button_table);
            Ok(rlua::Value::Function(lua.create_function(|lua, val: rlua::Value| {
                let button_table = lua.globals().get::<_, Table>("__temp").unwrap();
                lua.globals().set("__temp", rlua::Value::Nil);
                let signals = button_table.get_metatable()
                    .expect("no meta")
                    .get::<_, Table>("signals")
                    .expect("signals was not a table");
                signals.set(signals.len().expect("No length"), val);
                Ok(())
            })))
        },
        "emit_signal" => {
            lua.globals().set("__temp", button_table);
            Ok(rlua::Value::Function(lua.create_function(|lua, val: rlua::Value| {
                let button_table = lua.globals().get::<_, Table>("__temp").unwrap();
                lua.globals().set("__temp", rlua::Value::Nil);
                let signals = button_table.get_metatable().unwrap().get::<_, Table>("signals").unwrap();
                signals.get::<_,rlua::Function>(0).unwrap().call::<_,()>(button_table);
                Ok(())
            })))
        },
        "num" => Ok(rlua::Value::Number(button.num as _)),
        // TODO Error here
        _ => Ok(rlua::Value::Nil)
    }
    // TODO special "valid" property
}

pub fn init(lua: &Lua) -> rlua::Result<()> {
    unimplemented!()
}

mod test {
    use rlua::*;
    use super::*;
    #[test]
    fn basic_test() {
        let lua = Lua::new();
        lua.globals().set("button0", new(&lua, 0).unwrap());
        lua.globals().set("button1", new(&lua, 1).unwrap());
        lua.eval(r#"
                 print(button0)
                 print(button0.num)
                 print(button1.num)
                 print(button0.connect_signal(function(button) button.num = 3 end))
                 print(button0.emit_signal())
                 print(button0.num)
"#,
        None).unwrap()
    }
}

<commit_msg>Fixed that silly temp lua value.<commit_after>use std::fmt::{self, Display, Formatter};
use rlua::{self, Table, Lua, UserData, UserDataMethods};
use super::{class, object};

use rustwlc::*;
#[allow(deprecated)]
use rustwlc::xkb::Keysym;

#[derive(Clone, Debug)]
pub struct Button {
    num: u32
}

impl Display for Button {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Button: {:p}", self)
    }
}

impl UserData for Button {
    fn add_methods(methods: &mut UserDataMethods<Self>) {
        object::add_meta_methods(methods);
        class::add_meta_methods(methods);
    }
}

/// Makes a new button stored in a table beside its signals
pub fn new(lua: &Lua, num: u32) -> rlua::Result<Table> {
    let button_table = lua.create_table();
    button_table.set("data", Button { num })?;
    let meta = lua.create_table();
    meta.set("__index", lua.create_function(default_index))?;
    meta.set("signals", lua.create_table());
    meta.set("__tostring", lua.create_function(|_, button_table: Table|
                                               Ok(format!("{}", button_table.get::<_, Button>("data").unwrap()))));
    button_table.set_metatable(Some(meta));
    Ok(button_table)
}

fn default_index<'lua>(lua: &'lua Lua, (button_table, index): (Table<'lua>, String))
                 -> rlua::Result<rlua::Value<'lua>> {
    if let Ok(val) = button_table.get::<_, rlua::Value>(index.clone()) {
        return Ok(val)
    }
    // TODO error handling
    let button = button_table.raw_get::<_, Button>("data").unwrap();
    match index.as_str() {
        "connect_signal" => {
            let func = lua.create_function(|lua, (button_table, val): (Table, rlua::Value)| {
                let signals = button_table.get_metatable()
                    .expect("no meta")
                    .get::<_, Table>("signals")
                    .expect("signals was not a table");
                signals.set(signals.len().expect("No length"), val);
                Ok(())
            });
            func.bind(button_table).map(rlua::Value::Function)
        },
        "emit_signal" => {
            let func = lua.create_function(|lua, (button_table, val): (Table, rlua::Value)| {
                let signals = button_table.get_metatable().unwrap().get::<_, Table>("signals").unwrap();
                signals.get::<_,rlua::Function>(0).unwrap().call::<_,()>(button_table);
                Ok(())
            });
            func.bind(button_table).map(rlua::Value::Function)

        },
        "num" => Ok(rlua::Value::Number(button.num as _)),
        // TODO Error here
        _ => Ok(rlua::Value::Nil)
    }
    // TODO special "valid" property
}

pub fn init(lua: &Lua) -> rlua::Result<()> {
    unimplemented!()
}

mod test {
    use rlua::*;
    use super::*;
    #[test]
    fn basic_test() {
        let lua = Lua::new();
        lua.globals().set("button0", new(&lua, 0).unwrap());
        lua.globals().set("button1", new(&lua, 1).unwrap());
        lua.eval(r#"
                 print(button0)
                 print(button0.num)
                 print(button1.num)
                 print(button0.connect_signal(function(button) button.num = 3 end))
                 print(button0.emit_signal())
                 print(button0.num)
"#,
        None).unwrap()
    }
}

<|endoftext|>


<commit_before>//! Utility methods and constructors for Lua objects

use std::fmt::Display;
use std::convert::From;
use rlua::{self, Lua, Table, UserData, AnyUserData, Value,
           FromLua, ToLua, Function};
use super::signal;
use super::class::Class;
use super::property::Property;

/// All Lua objects can be cast to this.
#[derive(Clone, Debug)]
pub struct Object<'lua> {
    pub object: AnyUserData<'lua>
}

impl <'lua> From<AnyUserData<'lua>> for Object<'lua> {
    fn from(object: AnyUserData<'lua>) -> Self {
        Object { object }
    }
}

/// Construct a new object, used when using the default Objectable::new.
pub struct ObjectBuilder<'lua>{
    lua: &'lua Lua,
    object: Object<'lua>
}

impl <'lua> ObjectBuilder<'lua> {
    pub fn add_to_meta(self, new_meta: Table<'lua>) -> rlua::Result<Self> {
        let meta = self.object.table()?.get_metatable()
            .expect("Object had no meta table");
        for entry in new_meta.pairs::<rlua::Value, rlua::Value>() {
            let (key, value) = entry?;
            meta.set(key, value)?;
        }
        self.object.table()?.set_metatable(Some(meta));
        Ok(self)
    }

    #[allow(dead_code)]
    pub fn add_to_signals(self, name: String, func: rlua::Function)
                          -> rlua::Result<Self> {
        signal::connect_signal(self.lua, self.object.clone(), name, &[func])?;
        Ok(self)
    }

    pub fn handle_constructor_argument(self, args: Table) -> rlua::Result<Self> {
        let meta = self.object.table()?.get_metatable()
            .expect("Object had no meta table");
        let class = meta.get::<_, AnyUserData>("__class")?;
        let class_table = class.get_user_value::<Table>()?;
        let props = class_table.get::<_, Vec<Property>>("properties")?;

        // Handle all table entries that correspond to known properties,
        // silently ignore all other keys
        for pair in args.pairs() {
            let (key, value): (Value, Value) = pair?;
            if let rlua::Value::String(key) = key {
                if let Ok(key) = key.to_str() {
                    // Find the property
                    for prop in props.iter() {
                        if prop.name == key {
                            // Property exists and has a cb_new callback
                            if let Some(ref new) = prop.cb_new {
                                let _: () = new.bind(self.object.clone())?.call(value)?;
                                break;
                            }
                        }
                    }
                }
            }
        }
        Ok(self)
    }

    pub fn build(self) -> Object<'lua> {
        self.object
    }
}

/// Trait implemented by all objects that represent OO lua objects.
///
/// This trait allows casting an object gotten back from the Lua runtime
/// into a concrete object so that Rust can do things with it.
///
/// You can't do anything to the object until it has been converted into a
/// canonical form using this trait.
pub trait Objectable<'lua, T, S: UserData + Default + Display + Clone + Send> {
    fn cast(obj: Object<'lua>) -> rlua::Result<T> {
        if obj.object.is::<S>()? {
            Ok(Self::_wrap(obj))
        } else {
            use rlua::Error::RuntimeError;
            Err(RuntimeError("Could not cast object to concrete type".into()))
        }
    }

    /// Given the internal object table, constructs a concrete object out
    /// of it.
    ///
    /// This is only used internally, which is why it's prefixed with a "_"
    /// Please do not use it outside of object.rs.
    fn _wrap(table: Object<'lua>) -> T;

    fn state(&self) -> rlua::Result<S> {
        Ok(self.get_object()?.clone())
    }

    fn set_state(&mut self, data: S) -> rlua::Result<()> {
        *self.get_object_mut()? = data;
        Ok(())
    }

    /// Gets the internal state for the concrete object.
    /// Used internally `state`, though there's nothing wrong with it being
    /// used outside of internal object use.
    fn get_object(&self) -> rlua::Result<S>;

    /// Gets a mutable reference to the internal state for the concrete object.
    /// Used internally `set_state`, though there's nothing wrong with it being
    /// used outside of internal object use.
    fn get_object_mut(&mut self) -> rlua::Result<::std::cell::RefMut<S>>;

    /// Lua objects in Way Cooler are just how they are in Awesome:
    /// * We expose the user data directly.
    /// * State for the object is stored using set_user_value in a "wrapper" table.
    /// * The wrapper table has a data field which hosts the data.
    /// * Class methods/attributes are on the meta table of the wrapper table.
    fn allocate(lua: &'lua Lua, class: Class) -> rlua::Result<ObjectBuilder<'lua>>
    {
        let object = lua.create_userdata(S::default())?;
        // TODO Increment the instance count
        let wrapper_table = lua.create_table()?;
        let data_table = lua.create_table()?;
        wrapper_table.set("data", data_table)?;
        let meta = lua.create_table()?;
        meta.set("__class", class)?;
        meta.set("properties", Vec::<Property>::new().to_lua(lua)?)?;
        meta.set("signals", lua.create_table()?)?;
        meta.set("connect_signal",
                 lua.create_function(connect_signal)?)?;
        meta.set("disconnect_signal",
                 lua.create_function(disconnect_signal)?)?;
        meta.set("emit_signal", lua.create_function(emit_signal)?)?;
        meta.set("__index", meta.clone())?;
        meta.set("__tostring", lua.create_function(|_, data: AnyUserData| {
            Ok(format!("{}", data.borrow::<S>()?.clone()))
        })?)?;
        wrapper_table.set_metatable(Some(meta));
        object.set_user_value(wrapper_table)?;
        // TODO Emit new signal event
        let object = Object { object };
        Ok(ObjectBuilder { object, lua })
    }
}

impl <'lua> ToLua<'lua> for Object<'lua> {
    fn to_lua(self, _: &'lua Lua) -> rlua::Result<Value<'lua>> {
        Ok(Value::UserData(self.object))
    }
}

impl <'lua> Object<'lua> {
    pub fn signals(&self) -> rlua::Result<rlua::Table<'lua>> {
        self.table()?.get::<_, Table>("signals")
    }

    pub fn table(&self) -> rlua::Result<Table<'lua>> {
        self.object.get_user_value::<Table<'lua>>()
    }
}

/// Default indexing of an Awesome object.
///
/// Automatically looks up contents in meta table, so instead of overriding this
/// it's easier to just add the required data in the meta table.
pub fn default_index<'lua>(lua: &'lua Lua,
                           (obj, index): (AnyUserData<'lua>, Value<'lua>))
                           -> rlua::Result<Value<'lua>> {
    // Look up in metatable first
    let obj: Object<'lua> = obj.into();
    let obj_table = obj.table()?;
    let meta = obj_table.get_metatable()
        .expect("Object had no metatable");
    if meta.get::<_, AnyUserData>("__class").is_ok() {
        if let Ok(val) = meta.raw_get::<_, Value>(index.clone()) {
            match val {
                Value::Nil => {},
                val => return Ok(val)
            }
        }
    }
    let index = match String::from_lua(index, lua) {
        Ok(s) => s,
        Err(_) => return Ok(Value::Nil)
    };
    match index.as_str() {
        "valid" => {
            Ok(Value::Boolean(
                if let Ok(class) = meta.get::<_, AnyUserData>("__class") {
                    let class: Class = class.into();
                    class.checker()?
                        .map(|checker| checker(obj))
                        .unwrap_or(true)
                } else {
                    false
                }))
        },
        "data" => {
            obj_table.to_lua(lua)
        },
        index => {
            // Try see if there is a property of the class with the name
            if let Ok(class) = meta.get::<_, AnyUserData>("__class") {
                let class_table = class.get_user_value::<Table>()?;
                let props = class_table.get::<_, Vec<Property>>("properties")?;
                for prop in props {
                    if prop.name.as_str() == index {
                        // Property exists and has an index callback
                        if let Some(index) = prop.cb_index {
                            return index.call(obj)
                        }
                    }
                }
                if let Some(meta) = class_table.get_metatable() {
                    match meta.get::<_, Function>("__index_miss_handler") {
                        Ok(function) => {
                            return function.bind(obj)?.call(index)
                        },
                        Err(_) => {}
                    }
                }
            }
            // TODO property miss handler if index doesn't exst
            Ok(rlua::Value::Nil)
        }
    }
}

/// Default new indexing (assignment) of an Awesome object.
///
/// Automatically looks up contents in meta table, so instead of overriding this
/// it's easier to just add the required data in the meta table.
pub fn default_newindex<'lua>(_: &'lua Lua,
                              (obj, index, val):
                              (AnyUserData<'lua>, String, Value<'lua>))
                              -> rlua::Result<Value<'lua>> {
    // Look up in metatable first
    let obj: Object<'lua> = obj.into();
    let obj_table = obj.table()?;
    if let Some(meta) = obj_table.get_metatable() {
        if let Ok(val) = meta.raw_get::<_, Value>(index.clone()) {
            match val {
                Value::Nil => {},
                val => return Ok(val)
            }
        }
        let class = meta.get::<_, AnyUserData>("__class")?;
        let class_table = class.get_user_value::<Table>()?;
        let props = class_table.get::<_, Vec<Property>>("properties")?;
        for prop in props {
            if prop.name.as_str() == index {
                // Property exists and has a newindex callback
                if let Some(newindex) = prop.cb_newindex {
                    return newindex.bind(obj.clone())?.call(val)
                }
            }
        }
        if let Some(meta) = class_table.get_metatable() {
            match meta.get::<_, Function>("__newindex_miss_handler") {
                Ok(function) => {
                    return function.bind(obj)?.call((index, val))
                },
                Err(_) => {}
            }
        }
        // TODO property miss handler if index doesn't exst
    }
    Ok(Value::Nil)
}

fn connect_signal(lua: &Lua, (obj, signal, func): (AnyUserData, String, Function))
                  -> rlua::Result<()> {
    signal::connect_signal(lua, obj.into(), signal, &[func])
}

fn disconnect_signal(lua: &Lua, (obj, signal): (AnyUserData, String))
                     -> rlua::Result<()> {
    signal::disconnect_signal(lua, obj.into(), signal)
}

fn emit_signal(lua: &Lua, (obj, signal, args): (AnyUserData, String, Value))
               -> rlua::Result<()> {
    signal::emit_object_signal(lua, obj.into(), signal, args)
}
<commit_msg>Remove set_state()<commit_after>//! Utility methods and constructors for Lua objects

use std::fmt::Display;
use std::convert::From;
use rlua::{self, Lua, Table, UserData, AnyUserData, Value,
           FromLua, ToLua, Function};
use super::signal;
use super::class::Class;
use super::property::Property;

/// All Lua objects can be cast to this.
#[derive(Clone, Debug)]
pub struct Object<'lua> {
    pub object: AnyUserData<'lua>
}

impl <'lua> From<AnyUserData<'lua>> for Object<'lua> {
    fn from(object: AnyUserData<'lua>) -> Self {
        Object { object }
    }
}

/// Construct a new object, used when using the default Objectable::new.
pub struct ObjectBuilder<'lua>{
    lua: &'lua Lua,
    object: Object<'lua>
}

impl <'lua> ObjectBuilder<'lua> {
    pub fn add_to_meta(self, new_meta: Table<'lua>) -> rlua::Result<Self> {
        let meta = self.object.table()?.get_metatable()
            .expect("Object had no meta table");
        for entry in new_meta.pairs::<rlua::Value, rlua::Value>() {
            let (key, value) = entry?;
            meta.set(key, value)?;
        }
        self.object.table()?.set_metatable(Some(meta));
        Ok(self)
    }

    #[allow(dead_code)]
    pub fn add_to_signals(self, name: String, func: rlua::Function)
                          -> rlua::Result<Self> {
        signal::connect_signal(self.lua, self.object.clone(), name, &[func])?;
        Ok(self)
    }

    pub fn handle_constructor_argument(self, args: Table) -> rlua::Result<Self> {
        let meta = self.object.table()?.get_metatable()
            .expect("Object had no meta table");
        let class = meta.get::<_, AnyUserData>("__class")?;
        let class_table = class.get_user_value::<Table>()?;
        let props = class_table.get::<_, Vec<Property>>("properties")?;

        // Handle all table entries that correspond to known properties,
        // silently ignore all other keys
        for pair in args.pairs() {
            let (key, value): (Value, Value) = pair?;
            if let rlua::Value::String(key) = key {
                if let Ok(key) = key.to_str() {
                    // Find the property
                    for prop in props.iter() {
                        if prop.name == key {
                            // Property exists and has a cb_new callback
                            if let Some(ref new) = prop.cb_new {
                                let _: () = new.bind(self.object.clone())?.call(value)?;
                                break;
                            }
                        }
                    }
                }
            }
        }
        Ok(self)
    }

    pub fn build(self) -> Object<'lua> {
        self.object
    }
}

/// Trait implemented by all objects that represent OO lua objects.
///
/// This trait allows casting an object gotten back from the Lua runtime
/// into a concrete object so that Rust can do things with it.
///
/// You can't do anything to the object until it has been converted into a
/// canonical form using this trait.
pub trait Objectable<'lua, T, S: UserData + Default + Display + Clone + Send> {
    fn cast(obj: Object<'lua>) -> rlua::Result<T> {
        if obj.object.is::<S>()? {
            Ok(Self::_wrap(obj))
        } else {
            use rlua::Error::RuntimeError;
            Err(RuntimeError("Could not cast object to concrete type".into()))
        }
    }

    /// Given the internal object table, constructs a concrete object out
    /// of it.
    ///
    /// This is only used internally, which is why it's prefixed with a "_"
    /// Please do not use it outside of object.rs.
    fn _wrap(table: Object<'lua>) -> T;

    fn state(&self) -> rlua::Result<S> {
        Ok(self.get_object()?.clone())
    }

    /// Gets the internal state for the concrete object.
    /// Used internally `state`, though there's nothing wrong with it being
    /// used outside of internal object use.
    fn get_object(&self) -> rlua::Result<S>;

    /// Gets a mutable reference to the internal state for the concrete object.
    fn get_object_mut(&mut self) -> rlua::Result<::std::cell::RefMut<S>>;

    /// Lua objects in Way Cooler are just how they are in Awesome:
    /// * We expose the user data directly.
    /// * State for the object is stored using set_user_value in a "wrapper" table.
    /// * The wrapper table has a data field which hosts the data.
    /// * Class methods/attributes are on the meta table of the wrapper table.
    fn allocate(lua: &'lua Lua, class: Class) -> rlua::Result<ObjectBuilder<'lua>>
    {
        let object = lua.create_userdata(S::default())?;
        // TODO Increment the instance count
        let wrapper_table = lua.create_table()?;
        let data_table = lua.create_table()?;
        wrapper_table.set("data", data_table)?;
        let meta = lua.create_table()?;
        meta.set("__class", class)?;
        meta.set("properties", Vec::<Property>::new().to_lua(lua)?)?;
        meta.set("signals", lua.create_table()?)?;
        meta.set("connect_signal",
                 lua.create_function(connect_signal)?)?;
        meta.set("disconnect_signal",
                 lua.create_function(disconnect_signal)?)?;
        meta.set("emit_signal", lua.create_function(emit_signal)?)?;
        meta.set("__index", meta.clone())?;
        meta.set("__tostring", lua.create_function(|_, data: AnyUserData| {
            Ok(format!("{}", data.borrow::<S>()?.clone()))
        })?)?;
        wrapper_table.set_metatable(Some(meta));
        object.set_user_value(wrapper_table)?;
        // TODO Emit new signal event
        let object = Object { object };
        Ok(ObjectBuilder { object, lua })
    }
}

impl <'lua> ToLua<'lua> for Object<'lua> {
    fn to_lua(self, _: &'lua Lua) -> rlua::Result<Value<'lua>> {
        Ok(Value::UserData(self.object))
    }
}

impl <'lua> Object<'lua> {
    pub fn signals(&self) -> rlua::Result<rlua::Table<'lua>> {
        self.table()?.get::<_, Table>("signals")
    }

    pub fn table(&self) -> rlua::Result<Table<'lua>> {
        self.object.get_user_value::<Table<'lua>>()
    }
}

/// Default indexing of an Awesome object.
///
/// Automatically looks up contents in meta table, so instead of overriding this
/// it's easier to just add the required data in the meta table.
pub fn default_index<'lua>(lua: &'lua Lua,
                           (obj, index): (AnyUserData<'lua>, Value<'lua>))
                           -> rlua::Result<Value<'lua>> {
    // Look up in metatable first
    let obj: Object<'lua> = obj.into();
    let obj_table = obj.table()?;
    let meta = obj_table.get_metatable()
        .expect("Object had no metatable");
    if meta.get::<_, AnyUserData>("__class").is_ok() {
        if let Ok(val) = meta.raw_get::<_, Value>(index.clone()) {
            match val {
                Value::Nil => {},
                val => return Ok(val)
            }
        }
    }
    let index = match String::from_lua(index, lua) {
        Ok(s) => s,
        Err(_) => return Ok(Value::Nil)
    };
    match index.as_str() {
        "valid" => {
            Ok(Value::Boolean(
                if let Ok(class) = meta.get::<_, AnyUserData>("__class") {
                    let class: Class = class.into();
                    class.checker()?
                        .map(|checker| checker(obj))
                        .unwrap_or(true)
                } else {
                    false
                }))
        },
        "data" => {
            obj_table.to_lua(lua)
        },
        index => {
            // Try see if there is a property of the class with the name
            if let Ok(class) = meta.get::<_, AnyUserData>("__class") {
                let class_table = class.get_user_value::<Table>()?;
                let props = class_table.get::<_, Vec<Property>>("properties")?;
                for prop in props {
                    if prop.name.as_str() == index {
                        // Property exists and has an index callback
                        if let Some(index) = prop.cb_index {
                            return index.call(obj)
                        }
                    }
                }
                if let Some(meta) = class_table.get_metatable() {
                    match meta.get::<_, Function>("__index_miss_handler") {
                        Ok(function) => {
                            return function.bind(obj)?.call(index)
                        },
                        Err(_) => {}
                    }
                }
            }
            // TODO property miss handler if index doesn't exst
            Ok(rlua::Value::Nil)
        }
    }
}

/// Default new indexing (assignment) of an Awesome object.
///
/// Automatically looks up contents in meta table, so instead of overriding this
/// it's easier to just add the required data in the meta table.
pub fn default_newindex<'lua>(_: &'lua Lua,
                              (obj, index, val):
                              (AnyUserData<'lua>, String, Value<'lua>))
                              -> rlua::Result<Value<'lua>> {
    // Look up in metatable first
    let obj: Object<'lua> = obj.into();
    let obj_table = obj.table()?;
    if let Some(meta) = obj_table.get_metatable() {
        if let Ok(val) = meta.raw_get::<_, Value>(index.clone()) {
            match val {
                Value::Nil => {},
                val => return Ok(val)
            }
        }
        let class = meta.get::<_, AnyUserData>("__class")?;
        let class_table = class.get_user_value::<Table>()?;
        let props = class_table.get::<_, Vec<Property>>("properties")?;
        for prop in props {
            if prop.name.as_str() == index {
                // Property exists and has a newindex callback
                if let Some(newindex) = prop.cb_newindex {
                    return newindex.bind(obj.clone())?.call(val)
                }
            }
        }
        if let Some(meta) = class_table.get_metatable() {
            match meta.get::<_, Function>("__newindex_miss_handler") {
                Ok(function) => {
                    return function.bind(obj)?.call((index, val))
                },
                Err(_) => {}
            }
        }
        // TODO property miss handler if index doesn't exst
    }
    Ok(Value::Nil)
}

fn connect_signal(lua: &Lua, (obj, signal, func): (AnyUserData, String, Function))
                  -> rlua::Result<()> {
    signal::connect_signal(lua, obj.into(), signal, &[func])
}

fn disconnect_signal(lua: &Lua, (obj, signal): (AnyUserData, String))
                     -> rlua::Result<()> {
    signal::disconnect_signal(lua, obj.into(), signal)
}

fn emit_signal(lua: &Lua, (obj, signal, args): (AnyUserData, String, Value))
               -> rlua::Result<()> {
    signal::emit_object_signal(lua, obj.into(), signal, args)
}
<|endoftext|>


<commit_before>// Copyright (C) 2018, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#[macro_use]
extern crate criterion;

use ring::rand::*;

use criterion::Criterion;

fn handshake(c: &mut Criterion) {
    let mut buf = [0; 65535];

    let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
    config
        .load_cert_chain_from_pem_file("examples/cert.crt")
        .unwrap();
    config
        .load_priv_key_from_pem_file("examples/cert.key")
        .unwrap();
    config
        .set_application_protos(b"\x06proto1\x06proto2")
        .unwrap();
    config.set_initial_max_data(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_bidi_local(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_bidi_remote(2u64.pow(62) - 1);
    config.set_initial_max_streams_bidi(3);
    config.set_initial_max_streams_uni(3);
    config.verify_peer(false);

    c.bench_function("handshake", move |b| b.iter(|| {
        let mut pipe = quiche::testing::Pipe::with_config(&mut config).unwrap();
        pipe.handshake(&mut buf).unwrap();
    }));
}

fn stream(c: &mut Criterion) {
    let mut buf = [0; 65535];

    let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
    config
        .load_cert_chain_from_pem_file("examples/cert.crt")
        .unwrap();
    config
        .load_priv_key_from_pem_file("examples/cert.key")
        .unwrap();
    config
        .set_application_protos(b"\x06proto1\x06proto2")
        .unwrap();
    config.set_max_packet_size(1350);
    config.set_initial_max_data(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_bidi_local(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_bidi_remote(2u64.pow(62) - 1);
    config.set_initial_max_streams_bidi(3);
    config.set_initial_max_streams_uni(3);
    config.verify_peer(false);

    let mut pipe = quiche::testing::Pipe::with_config(&mut config).unwrap();
    pipe.handshake(&mut buf).unwrap();

    let mut send_buf = vec![0; 5_000_000];
    SystemRandom::new().fill(&mut send_buf[..]).unwrap();

    let mut recv_buf = vec![0; send_buf.len()];

    c.bench_function_over_inputs("stream", move |b, &&size| b.iter(|| {
        pipe.client.stream_send(4, &send_buf[..size], false).unwrap();

        let mut recv_len = 0;

        while recv_len < size {
            loop {
                let len = match pipe.client.send(&mut buf) {
                    Ok(write) => write,

                    Err(quiche::Error::Done) => break,

                    Err(e) => panic!("client send failed {}", e),
                };

                match pipe.server.recv(&mut buf[..len]) {
                    Ok(_) => (),

                    Err(quiche::Error::Done) => (),

                    Err(e) => panic!("server recv failed {}", e),
                }
            }

            let (len, _) = pipe
                .server
                .stream_recv(4, &mut recv_buf[recv_len..])
                .unwrap();
            recv_len += len;

            loop {
                let len = match pipe.server.send(&mut buf) {
                    Ok(write) => write,

                    Err(quiche::Error::Done) => break,

                    Err(e) => panic!("server send failed {}", e),
                };

                match pipe.client.recv(&mut buf[..len]) {
                    Ok(_) => (),

                    Err(quiche::Error::Done) => (),

                    Err(e) => panic!("client recv failed {}", e),
                }
            }
        }

        assert_eq!(&recv_buf[..size], &send_buf[..size]);
    }), &[128_000, 5_000_000]);
}

criterion_group!(benches, handshake, stream);

criterion_main!(benches);
<commit_msg>benches: format<commit_after>// Copyright (C) 2018, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#[macro_use]
extern crate criterion;

use ring::rand::*;

use criterion::Criterion;

fn handshake(c: &mut Criterion) {
    let mut buf = [0; 65535];

    let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
    config
        .load_cert_chain_from_pem_file("examples/cert.crt")
        .unwrap();
    config
        .load_priv_key_from_pem_file("examples/cert.key")
        .unwrap();
    config
        .set_application_protos(b"\x06proto1\x06proto2")
        .unwrap();
    config.set_initial_max_data(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_bidi_local(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_bidi_remote(2u64.pow(62) - 1);
    config.set_initial_max_streams_bidi(3);
    config.set_initial_max_streams_uni(3);
    config.verify_peer(false);

    c.bench_function("handshake", move |b| {
        b.iter(|| {
            let mut pipe =
                quiche::testing::Pipe::with_config(&mut config).unwrap();
            pipe.handshake(&mut buf).unwrap();
        })
    });
}

fn stream(c: &mut Criterion) {
    let mut buf = [0; 65535];

    let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
    config
        .load_cert_chain_from_pem_file("examples/cert.crt")
        .unwrap();
    config
        .load_priv_key_from_pem_file("examples/cert.key")
        .unwrap();
    config
        .set_application_protos(b"\x06proto1\x06proto2")
        .unwrap();
    config.set_max_packet_size(1350);
    config.set_initial_max_data(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_bidi_local(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_bidi_remote(2u64.pow(62) - 1);
    config.set_initial_max_streams_bidi(3);
    config.set_initial_max_streams_uni(3);
    config.verify_peer(false);

    let mut pipe = quiche::testing::Pipe::with_config(&mut config).unwrap();
    pipe.handshake(&mut buf).unwrap();

    let mut send_buf = vec![0; 5_000_000];
    SystemRandom::new().fill(&mut send_buf[..]).unwrap();

    let mut recv_buf = vec![0; send_buf.len()];

    c.bench_function_over_inputs(
        "stream",
        move |b, &&size| {
            b.iter(|| {
                pipe.client
                    .stream_send(4, &send_buf[..size], false)
                    .unwrap();

                let mut recv_len = 0;

                while recv_len < size {
                    loop {
                        let len = match pipe.client.send(&mut buf) {
                            Ok(write) => write,

                            Err(quiche::Error::Done) => break,

                            Err(e) => panic!("client send failed {}", e),
                        };

                        match pipe.server.recv(&mut buf[..len]) {
                            Ok(_) => (),

                            Err(quiche::Error::Done) => (),

                            Err(e) => panic!("server recv failed {}", e),
                        }
                    }

                    let (len, _) = pipe
                        .server
                        .stream_recv(4, &mut recv_buf[recv_len..])
                        .unwrap();
                    recv_len += len;

                    loop {
                        let len = match pipe.server.send(&mut buf) {
                            Ok(write) => write,

                            Err(quiche::Error::Done) => break,

                            Err(e) => panic!("server send failed {}", e),
                        };

                        match pipe.client.recv(&mut buf[..len]) {
                            Ok(_) => (),

                            Err(quiche::Error::Done) => (),

                            Err(e) => panic!("client recv failed {}", e),
                        }
                    }
                }

                assert_eq!(&recv_buf[..size], &send_buf[..size]);
            })
        },
        &[128_000, 5_000_000],
    );
}

criterion_group!(benches, handshake, stream);

criterion_main!(benches);
<|endoftext|>


<commit_before>#![feature(macro_rules)]

//! Implementation of a Micro Transport Protocol library,
//! as well as a small client and server.
//!
//! http://www.bittorrent.org/beps/bep_0029.html

extern crate utp;
use std::io::net::ip::{Ipv4Addr, SocketAddr};

fn usage() {
    println!("Usage: utp [-s|-c] <address> <port>");
}

fn main() {
    use utp::UtpStream;
    use std::from_str::FromStr;

    // Defaults
    static BUF_SIZE: uint = 4096;
    let mut addr = SocketAddr { ip: Ipv4Addr(127,0,0,1), port: 8080 };

    let args = std::os::args();

	if args.len() != 2 && args.len() != 4 {
		usage();
		return;
	}

    if args.len() == 4 {
        addr = SocketAddr {
            ip:   FromStr::from_str(args[2].as_slice()).unwrap(),
            port: FromStr::from_str(args[3].as_slice()).unwrap(),
        };
    }

    match args[1].as_slice() {
        "-s" => {
            let mut buf = [0, ..BUF_SIZE];
            let mut stream = UtpStream::bind(addr);

            println!("Serving on {}", addr);

            loop {
                match stream.read(buf) {
                    Ok(_read) => {}
                    Err(e) => fail!("{}", e),
                }
            }
        }
        "-c" => {
            let mut stream = UtpStream::connect(addr);

            let buf = [0xF, ..BUF_SIZE];
            match stream.write(buf) {
                Ok(_) => {},
                Err(e) => fail!("{}", e),
            }

            let mut buf = [0u8, ..BUF_SIZE];
            match stream.read(buf) {
                Ok(n) => println!("{}", Vec::from_slice(buf.slice(0, n))),
                Err(e) => println!("{}", e),
            }

            match stream.close() {
                Ok(_) => {},
                Err(e) => fail!("{}", e),
            }
            drop(stream);
        }
        _ => usage(),
    }
}
<commit_msg>Fix example client.<commit_after>#![feature(macro_rules)]

//! Implementation of a Micro Transport Protocol library,
//! as well as a small client and server.
//!
//! http://www.bittorrent.org/beps/bep_0029.html

extern crate utp;
use std::io::net::ip::{Ipv4Addr, SocketAddr};

fn usage() {
    println!("Usage: utp [-s|-c] <address> <port>");
}

fn main() {
    use utp::UtpStream;
    use std::from_str::FromStr;

    // Defaults
    static BUF_SIZE: uint = 4096;
    let mut addr = SocketAddr { ip: Ipv4Addr(127,0,0,1), port: 8080 };

    let args = std::os::args();

	if args.len() != 2 && args.len() != 4 {
		usage();
		return;
	}

    if args.len() == 4 {
        addr = SocketAddr {
            ip:   FromStr::from_str(args[2].as_slice()).unwrap(),
            port: FromStr::from_str(args[3].as_slice()).unwrap(),
        };
    }

    match args[1].as_slice() {
        "-s" => {
            let mut buf = [0, ..BUF_SIZE];
            let mut stream = UtpStream::bind(addr);

            println!("Serving on {}", addr);

            loop {
                match stream.read(buf) {
                    Ok(_read) => {}
                    Err(e) => fail!("{}", e),
                }
            }
        }
        "-c" => {
            let mut stream = UtpStream::connect(addr);

            let buf = [0xF, ..BUF_SIZE];
            match stream.write(buf) {
                Ok(_) => {},
                Err(e) => fail!("{}", e),
            }

            match stream.close() {
                Ok(_) => {},
                Err(e) => fail!("{}", e),
            }
            drop(stream);
        }
        _ => usage(),
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "cargo-clippy", allow(clone_on_ref_ptr))]
#![cfg_attr(feature = "cargo-clippy", allow(not_unsafe_ptr_arg_deref))]
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]

extern crate cairo;
extern crate cairo_sys;
extern crate cssparser;
extern crate data_url;
extern crate downcast_rs;
extern crate encoding;
extern crate float_cmp;
extern crate gdk_pixbuf;
extern crate gio;
extern crate gio_sys;
extern crate glib;
extern crate glib_sys;
extern crate itertools;
extern crate language_tags;
extern crate libc;
extern crate locale_config;
extern crate nalgebra;
extern crate num_traits;
extern crate owning_ref;
extern crate pango;
extern crate pango_cairo_sys;
extern crate pango_sys;
extern crate pangocairo;
extern crate rayon;
extern crate regex;
extern crate url;

#[macro_use]
extern crate lazy_static;

pub use color::{rsvg_css_parse_color, ColorKind, ColorSpec};

pub use drawing_ctx::{
    rsvg_drawing_ctx_add_node_and_ancestors_to_stack,
    rsvg_drawing_ctx_draw_node_from_stack,
    rsvg_drawing_ctx_free,
    rsvg_drawing_ctx_get_geometry,
    rsvg_drawing_ctx_new,
};

pub use handle::{
    rsvg_handle_acquire_data,
    rsvg_handle_acquire_stream,
    rsvg_handle_defs_lookup,
    rsvg_handle_rust_free,
    rsvg_handle_rust_get_base_gfile,
    rsvg_handle_rust_new,
    rsvg_handle_rust_node_is_root,
    rsvg_handle_rust_set_base_url,
    rsvg_handle_rust_steal_result,
};

pub use io::rsvg_get_input_stream_for_loading;

pub use node::rsvg_node_unref;

pub use property_bag::{
    rsvg_property_bag_free,
    rsvg_property_bag_iter_begin,
    rsvg_property_bag_iter_end,
    rsvg_property_bag_iter_next,
    rsvg_property_bag_new,
};

pub use structure::rsvg_node_svg_get_size;

pub use xml::{
    rsvg_xml_state_characters,
    rsvg_xml_state_end_element,
    rsvg_xml_state_entity_insert,
    rsvg_xml_state_entity_lookup,
    rsvg_xml_state_error,
    rsvg_xml_state_free,
    rsvg_xml_state_load_css_from_href,
    rsvg_xml_state_new,
    rsvg_xml_state_start_element,
};

#[macro_use]
mod log;

#[macro_use]
mod coord_units;

#[macro_use]
mod float_eq_cairo;

#[macro_use]
mod property_macros;

mod allowed_url;
mod aspect_ratio;
mod attributes;
mod bbox;
mod clip_path;
mod color;
mod cond;
mod create_node;
mod croco;
mod css;
mod defs;
mod drawing_ctx;
mod error;
pub mod filters;
mod font_props;
mod gradient;
mod handle;
mod image;
mod io;
mod iri;
mod length;
mod link;
mod marker;
mod mask;
mod node;
mod paint_server;
mod parsers;
mod path_builder;
mod path_parser;
mod pattern;
mod property_bag;
mod rect;
mod shapes;
mod space;
pub mod srgb;
mod state;
mod stop;
mod structure;
mod style;
pub mod surface_utils;
mod svg;
mod text;
mod transform;
mod tree;
mod unitinterval;
mod util;
mod viewbox;
mod viewport;
mod xml;
<commit_msg>lib.rs: Export some missing functions, oops<commit_after>#![cfg_attr(feature = "cargo-clippy", allow(clone_on_ref_ptr))]
#![cfg_attr(feature = "cargo-clippy", allow(not_unsafe_ptr_arg_deref))]
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]

extern crate cairo;
extern crate cairo_sys;
extern crate cssparser;
extern crate data_url;
extern crate downcast_rs;
extern crate encoding;
extern crate float_cmp;
extern crate gdk_pixbuf;
extern crate gio;
extern crate gio_sys;
extern crate glib;
extern crate glib_sys;
extern crate itertools;
extern crate language_tags;
extern crate libc;
extern crate locale_config;
extern crate nalgebra;
extern crate num_traits;
extern crate owning_ref;
extern crate pango;
extern crate pango_cairo_sys;
extern crate pango_sys;
extern crate pangocairo;
extern crate rayon;
extern crate regex;
extern crate url;

#[macro_use]
extern crate lazy_static;

pub use color::{rsvg_css_parse_color, ColorKind, ColorSpec};

pub use drawing_ctx::{
    rsvg_drawing_ctx_add_node_and_ancestors_to_stack,
    rsvg_drawing_ctx_draw_node_from_stack,
    rsvg_drawing_ctx_free,
    rsvg_drawing_ctx_get_geometry,
    rsvg_drawing_ctx_new,
};

pub use handle::{
    rsvg_handle_acquire_data,
    rsvg_handle_acquire_stream,
    rsvg_handle_defs_lookup,
    rsvg_handle_rust_cascade,
    rsvg_handle_rust_free,
    rsvg_handle_rust_get_base_gfile,
    rsvg_handle_rust_get_root,
    rsvg_handle_rust_new,
    rsvg_handle_rust_node_is_root,
    rsvg_handle_rust_set_base_url,
    rsvg_handle_rust_steal_result,
};

pub use io::rsvg_get_input_stream_for_loading;

pub use node::rsvg_node_unref;

pub use property_bag::{
    rsvg_property_bag_free,
    rsvg_property_bag_iter_begin,
    rsvg_property_bag_iter_end,
    rsvg_property_bag_iter_next,
    rsvg_property_bag_new,
};

pub use structure::rsvg_node_svg_get_size;

pub use xml::{
    rsvg_xml_state_characters,
    rsvg_xml_state_end_element,
    rsvg_xml_state_entity_insert,
    rsvg_xml_state_entity_lookup,
    rsvg_xml_state_error,
    rsvg_xml_state_free,
    rsvg_xml_state_load_css_from_href,
    rsvg_xml_state_new,
    rsvg_xml_state_start_element,
    rsvg_xml_state_tree_is_valid,
};

#[macro_use]
mod log;

#[macro_use]
mod coord_units;

#[macro_use]
mod float_eq_cairo;

#[macro_use]
mod property_macros;

mod allowed_url;
mod aspect_ratio;
mod attributes;
mod bbox;
mod clip_path;
mod color;
mod cond;
mod create_node;
mod croco;
mod css;
mod defs;
mod drawing_ctx;
mod error;
pub mod filters;
mod font_props;
mod gradient;
mod handle;
mod image;
mod io;
mod iri;
mod length;
mod link;
mod marker;
mod mask;
mod node;
mod paint_server;
mod parsers;
mod path_builder;
mod path_parser;
mod pattern;
mod property_bag;
mod rect;
mod shapes;
mod space;
pub mod srgb;
mod state;
mod stop;
mod structure;
mod style;
pub mod surface_utils;
mod svg;
mod text;
mod transform;
mod tree;
mod unitinterval;
mod util;
mod viewbox;
mod viewport;
mod xml;
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Active_object
extern crate time;

use std::f64::consts::PI;
use std::io::timer::Timer;
use std::num::{Zero, zero};
use std::sync::{Arc, Mutex};
use std::time::duration::Duration;

// Rust supports both shared-memory and actor models of concurrency, and the Integrator utilizes
// both.  We use a Sender (actor model) to send the Integrator new functions, while we use a Mutex
// (shared-memory concurrency) to hold the result of the integration.
//
// Note that these are not the only options here--there are many, many ways you can deal with
// concurrent access.  But when in doubt, a plain old Mutex is often a good bet.  For example, this
// might look like a good situation for a RwLock--after all, there's no reason for a read in the
// main task to block writes.  Unfortunately, unless you have significantly more reads than
// writes (which is certainly not the case here), a Mutex will usually outperform a RwLock.
pub struct Integrator<S, T> {
    input: Sender<|i64|: Send -> S>,
    output: Arc<Mutex<T>>,
}

// In Rust, time durations are strongly typed.  This is usually exactly what you want, but for a
// problem like this--where the integrated value has unusual (unspecified?) units--it can actually
// be a bit tricky.  Right now, Durations can only be multiplied or divided by i32s, so in order to
// be able to actually do math with them we say that the type parameter S (the result of the
// function being integrated) must yield T (the type of the integrated value) when multiplied by
// f64.  We could possibly replace f64 with a generic as well, but it would make things a bit more
// complex.
impl<S: Mul<f64, T> + Zero,
     T: Clone + Send + Zero> Integrator<S, T> {
    pub fn new(frequency: Duration) -> Integrator<S, T> {
        // We create a pipe allowing functions to be sent from tx (the sending end) to input (the
        // receiving end).  In order to change the function we are integrating from the task in
        // which the Integrator lives, we simply send the function through tx.
        let (tx, input) = channel();
        // The easiest way to do shared-memory concurrency in Rust is to use atomic reference
        // counting, or Arc, around a synchronized type (like Mutex<T>).  Arc gives you a guarantee
        // that memory will not be freed as long as there is at least one reference to it.
        // It is similar to C++'s shared_ptr, but it is guaranteed to be safe and is never
        // incremented unless explicitly cloned (by default, it is moved).
        let s = Arc::new(Mutex::new(zero::<T>()));
        let integrator = Integrator {
            input: tx,
            // Here is the aforementioned clone.  We have to do it before s enters the closure,
            // because once that happens it is moved into the proc() (and later, the new task) and
            // becomes inaccessible to the outside world.
            output: s.clone(),
        };
        spawn(proc() {
            // There is a reasonable argument for failure on failure to initialize the Timer, but
            // it's essentially certain that if we return from the spawn this early main will
            // detect that something is amiss.
            let mut timer = match Timer::new() {
                Ok(timer) => timer,
                Err(_) => return
            };
            // The frequency is how often we want to "tick" as we update our integrated total.  In
            // Rust, timers can yield Receivers that are periodically notified with an empty
            // message (where the period is the frequency).  This is useful because it lets us wait
            // on either a tick or another type of message (in this case, a request to change the
            // function we are integrating).
            let periodic = timer.periodic(frequency);
            let frequency_ms = frequency.num_milliseconds();
            let mut t = 0;
            let mut k = |_| zero();
            let mut k_0: S = zero();
            loop {
                // Here's the selection we talked about above.  Note that we are careful to call
                // the *non*-failing function, recv_opt(), here.  The reason we do this is because
                // recv_opt() will return Err when the sending end of a channel is dropped.  While
                // this is unlikely to happen for the timer (so again, you could argue for failure
                // there), it's normal behavior for the sending end of input to be dropped, since
                // it just happens when the Integrator falls out of scope.  So we handle it cleanly
                // and break out of the loop, rather than failing.
                select! {
                    res = periodic.recv_opt() => match res {
                        Ok(_) => {
                            t += frequency_ms;
                            let k_1: S = k(t);
                            // Rust Mutexes are a bit different from Mutexes in many other
                            // languages, in that the protected data is actually encapsulated by
                            // the Mutex.  The reason for this is that Rust is actually capable of
                            // enforcing (via its borrow checker) the invariant that the contents
                            // of a Mutex may only be read when you have acquired its lock.  This
                            // is enforced by way of a MutexGuard, the return value of lock(),
                            // which implements some special traits (Deref and DerefMut) that allow
                            // access to the inner element "through" the guard.  The element so
                            // acquired has a lifetime bounded by that of the MutexGuard, the
                            // MutexGuard can only be acquired by taking a lock, and the only way
                            // to release the lock is by letting the MutexGuard fall out of scope,
                            // so it's impossible to access the data incorrectly.  There are some
                            // additional subtleties around the actual implementation, but that's
                            // the basic idea.
                            let mut s = s.lock();
                            *s = *s + (k_1 + k_0) * (frequency_ms as f64 / 2.);
                            k_0 = k_1;
                        }
                        Err(_) => break,
                    },
                    res = input.recv_opt() => match res {
                        Ok(k_new) => k = k_new,
                        Err(_) => break,
                    }
                }
            }
        });
        integrator
    }

    pub fn input(&self, k: |i64|: Send -> S) -> Result<(), |i64|: Send -> S> {
        // The meat of the work is done in the other thread, so to set the input we just send along
        // the Sender we set earlier...
        self.input.send_opt(k)
    }

    pub fn output(&self) -> T {
        // ...and to read the input, we simply acquire a lock on the output Mutex and return a
        // clone.  Why do we have to clone it?  Because, as mentioned above, Rust won't let us
        // retain access to the interior of the Mutex unless we have possession of its lock.  There
        // are ways and circumstances in which one can avoid this (e.g. by using atomic types) but
        // clone() is a perfectly reasonable solution as well, and a lot easier to reason about :)
        self.output.lock().clone()
    }
}

// This function is fairly straightforward.  We create the integrator, set its input function k(t)
// to 2pi * f * t, and then wait as described in the Rosetta stone problem.
fn integrate() -> f64 {
    let object = Integrator::new(Duration::milliseconds(10));
    let mut timer = Timer::new().unwrap();
    object.input(|t| {
        let f = 1. / Duration::seconds(2).num_milliseconds() as f64;
        (2. * PI * f * t as f64).sin()
    }).ok().expect("Failed to set input");
    timer.sleep(Duration::seconds(2));
    object.input(|_| 0.).ok().expect("Failed to set input");
    timer.sleep(Duration::seconds(1) / 2);
    object.output()
}

#[cfg(not(test))]
fn main() {
    println!("{}", integrate());
}

#[test]
fn solution() {
    assert_eq!(integrate() as i64, 0);
}
<commit_msg>Fixing the active_object test to test with 1/10th the duration for everything.<commit_after>// Implements http://rosettacode.org/wiki/Active_object
extern crate time;

use std::f64::consts::PI;
use std::io::timer::Timer;
use std::num::{Zero, zero};
use std::sync::{Arc, Mutex};
use std::time::duration::Duration;

// Rust supports both shared-memory and actor models of concurrency, and the Integrator utilizes
// both.  We use a Sender (actor model) to send the Integrator new functions, while we use a Mutex
// (shared-memory concurrency) to hold the result of the integration.
//
// Note that these are not the only options here--there are many, many ways you can deal with
// concurrent access.  But when in doubt, a plain old Mutex is often a good bet.  For example, this
// might look like a good situation for a RwLock--after all, there's no reason for a read in the
// main task to block writes.  Unfortunately, unless you have significantly more reads than
// writes (which is certainly not the case here), a Mutex will usually outperform a RwLock.
pub struct Integrator<S, T> {
    input: Sender<|i64|: Send -> S>,
    output: Arc<Mutex<T>>,
}

// In Rust, time durations are strongly typed.  This is usually exactly what you want, but for a
// problem like this--where the integrated value has unusual (unspecified?) units--it can actually
// be a bit tricky.  Right now, Durations can only be multiplied or divided by i32s, so in order to
// be able to actually do math with them we say that the type parameter S (the result of the
// function being integrated) must yield T (the type of the integrated value) when multiplied by
// f64.  We could possibly replace f64 with a generic as well, but it would make things a bit more
// complex.
impl<S: Mul<f64, T> + Zero,
     T: Clone + Send + Zero> Integrator<S, T> {
    pub fn new(frequency: Duration) -> Integrator<S, T> {
        // We create a pipe allowing functions to be sent from tx (the sending end) to input (the
        // receiving end).  In order to change the function we are integrating from the task in
        // which the Integrator lives, we simply send the function through tx.
        let (tx, input) = channel();
        // The easiest way to do shared-memory concurrency in Rust is to use atomic reference
        // counting, or Arc, around a synchronized type (like Mutex<T>).  Arc gives you a guarantee
        // that memory will not be freed as long as there is at least one reference to it.
        // It is similar to C++'s shared_ptr, but it is guaranteed to be safe and is never
        // incremented unless explicitly cloned (by default, it is moved).
        let s = Arc::new(Mutex::new(zero::<T>()));
        let integrator = Integrator {
            input: tx,
            // Here is the aforementioned clone.  We have to do it before s enters the closure,
            // because once that happens it is moved into the proc() (and later, the new task) and
            // becomes inaccessible to the outside world.
            output: s.clone(),
        };
        spawn(proc() {
            // There is a reasonable argument for failure on failure to initialize the Timer, but
            // it's essentially certain that if we return from the spawn this early main will
            // detect that something is amiss.
            let mut timer = match Timer::new() {
                Ok(timer) => timer,
                Err(_) => return
            };
            // The frequency is how often we want to "tick" as we update our integrated total.  In
            // Rust, timers can yield Receivers that are periodically notified with an empty
            // message (where the period is the frequency).  This is useful because it lets us wait
            // on either a tick or another type of message (in this case, a request to change the
            // function we are integrating).
            let periodic = timer.periodic(frequency);
            let frequency_ms = frequency.num_milliseconds();
            let mut t = 0;
            let mut k = |_| zero();
            let mut k_0: S = zero();
            loop {
                // Here's the selection we talked about above.  Note that we are careful to call
                // the *non*-failing function, recv_opt(), here.  The reason we do this is because
                // recv_opt() will return Err when the sending end of a channel is dropped.  While
                // this is unlikely to happen for the timer (so again, you could argue for failure
                // there), it's normal behavior for the sending end of input to be dropped, since
                // it just happens when the Integrator falls out of scope.  So we handle it cleanly
                // and break out of the loop, rather than failing.
                select! {
                    res = periodic.recv_opt() => match res {
                        Ok(_) => {
                            t += frequency_ms;
                            let k_1: S = k(t);
                            // Rust Mutexes are a bit different from Mutexes in many other
                            // languages, in that the protected data is actually encapsulated by
                            // the Mutex.  The reason for this is that Rust is actually capable of
                            // enforcing (via its borrow checker) the invariant that the contents
                            // of a Mutex may only be read when you have acquired its lock.  This
                            // is enforced by way of a MutexGuard, the return value of lock(),
                            // which implements some special traits (Deref and DerefMut) that allow
                            // access to the inner element "through" the guard.  The element so
                            // acquired has a lifetime bounded by that of the MutexGuard, the
                            // MutexGuard can only be acquired by taking a lock, and the only way
                            // to release the lock is by letting the MutexGuard fall out of scope,
                            // so it's impossible to access the data incorrectly.  There are some
                            // additional subtleties around the actual implementation, but that's
                            // the basic idea.
                            let mut s = s.lock();
                            *s = *s + (k_1 + k_0) * (frequency_ms as f64 / 2.);
                            k_0 = k_1;
                        }
                        Err(_) => break,
                    },
                    res = input.recv_opt() => match res {
                        Ok(k_new) => k = k_new,
                        Err(_) => break,
                    }
                }
            }
        });
        integrator
    }

    pub fn input(&self, k: |i64|: Send -> S) -> Result<(), |i64|: Send -> S> {
        // The meat of the work is done in the other thread, so to set the input we just send along
        // the Sender we set earlier...
        self.input.send_opt(k)
    }

    pub fn output(&self) -> T {
        // ...and to read the input, we simply acquire a lock on the output Mutex and return a
        // clone.  Why do we have to clone it?  Because, as mentioned above, Rust won't let us
        // retain access to the interior of the Mutex unless we have possession of its lock.  There
        // are ways and circumstances in which one can avoid this (e.g. by using atomic types) but
        // clone() is a perfectly reasonable solution as well, and a lot easier to reason about :)
        self.output.lock().clone()
    }
}

// This function is fairly straightforward.  We create the integrator, set its input function k(t)
// to 2pi * f * t, and then wait as described in the Rosetta stone problem.
#[cfg(not(test))]
fn integrate() -> f64 {
    let object = Integrator::new(Duration::milliseconds(10));
    let mut timer = Timer::new().unwrap();
    object.input(|t| {
        let f = 1. / Duration::seconds(2).num_milliseconds() as f64;
        (2. * PI * f * t as f64).sin()
    }).ok().expect("Failed to set input");
    timer.sleep(Duration::seconds(2));
    object.input(|_| 0.).ok().expect("Failed to set input");
    timer.sleep(Duration::seconds(1) / 2);
    object.output()
}

#[cfg(not(test))]
fn main() {
    println!("{}", integrate());
}

#[test]
fn solution() {
    // We should just be able to call integrate, but can't represent the closure properly due to
    // rust-lang/rust issue #17060 if we make frequency or period a variable.
    // FIXME(pythonesque): When unboxed closures are fixed, fix integrate() to take two arguments.
    let object = Integrator::new(Duration::milliseconds(1));
    let mut timer = Timer::new().unwrap();
    object.input(|t| {
        let f = 1. / (Duration::seconds(2) / 10).num_milliseconds() as f64;
        (2. * PI * f * t as f64).sin()
    }).ok().expect("Failed to set input");
    timer.sleep(Duration::seconds(2) / 10);
    object.input(|_| 0.).ok().expect("Failed to set input");
    timer.sleep(Duration::seconds(1) / 20);
    assert_eq!(object.output() as i64, 0)
}
<|endoftext|>