<commit_before>#![allow(missing_docs)]
///! This crate contains types only for working JWK and JWK Sets
///! This is only meant to be used to deal with public JWK, not generate ones.
///! Most of the code in this file is taken from https://github.com/lawliet89/biscuit but
/// tweaked to remove the private bits as it's not the goal for this crate currently.
///!
use crate::Algorithm;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;

/// The intended usage of the public `KeyType`. This enum is serialized `untagged`
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum PublicKeyUse {
    /// Indicates a public key is meant for signature verification
    Signature,
    /// Indicates a public key is meant for encryption
    Encryption,
    /// Other usage
    Other(String),
}

impl Serialize for PublicKeyUse {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let string = match *self {
            PublicKeyUse::Signature => "sig",
            PublicKeyUse::Encryption => "enc",
            PublicKeyUse::Other(ref other) => other,
        };

        serializer.serialize_str(string)
    }
}

impl<'de> Deserialize<'de> for PublicKeyUse {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct PublicKeyUseVisitor;
        impl<'de> de::Visitor<'de> for PublicKeyUseVisitor {
            type Value = PublicKeyUse;

            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
                write!(formatter, "a string")
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: de::Error,
            {
                Ok(match v {
                    "sig" => PublicKeyUse::Signature,
                    "enc" => PublicKeyUse::Encryption,
                    other => PublicKeyUse::Other(other.to_string()),
                })
            }
        }

        deserializer.deserialize_string(PublicKeyUseVisitor)
    }
}

/// Operations that the key is intended to be used for. This enum is serialized `untagged`
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum KeyOperations {
    /// Computer digital signature or MAC
    Sign,
    /// Verify digital signature or MAC
    Verify,
    /// Encrypt content
    Encrypt,
    /// Decrypt content and validate decryption, if applicable
    Decrypt,
    /// Encrypt key
    WrapKey,
    /// Decrypt key and validate decryption, if applicable
    UnwrapKey,
    /// Derive key
    DeriveKey,
    /// Derive bits not to be used as a key
    DeriveBits,
    /// Other operation
    Other(String),
}

impl Serialize for KeyOperations {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let string = match *self {
            KeyOperations::Sign => "sign",
            KeyOperations::Verify => "verify",
            KeyOperations::Encrypt => "encrypt",
            KeyOperations::Decrypt => "decrypt",
            KeyOperations::WrapKey => "wrapKey",
            KeyOperations::UnwrapKey => "unwrapKey",
            KeyOperations::DeriveKey => "deriveKey",
            KeyOperations::DeriveBits => "deriveBits",
            KeyOperations::Other(ref other) => other,
        };

        serializer.serialize_str(string)
    }
}

impl<'de> Deserialize<'de> for KeyOperations {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct KeyOperationsVisitor;
        impl<'de> de::Visitor<'de> for KeyOperationsVisitor {
            type Value = KeyOperations;

            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
                write!(formatter, "a string")
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: de::Error,
            {
                Ok(match v {
                    "sign" => KeyOperations::Sign,
                    "verify" => KeyOperations::Verify,
                    "encrypt" => KeyOperations::Encrypt,
                    "decrypt" => KeyOperations::Decrypt,
                    "wrapKey" => KeyOperations::WrapKey,
                    "unwrapKey" => KeyOperations::UnwrapKey,
                    "deriveKey" => KeyOperations::DeriveKey,
                    "deriveBits" => KeyOperations::DeriveBits,
                    other => KeyOperations::Other(other.to_string()),
                })
            }
        }

        deserializer.deserialize_string(KeyOperationsVisitor)
    }
}

/// Common JWK parameters
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Default, Hash)]
pub struct CommonParameters {
    /// The intended use of the public key. Should not be specified with `key_operations`.
    /// See sections 4.2 and 4.3 of [RFC7517](https://tools.ietf.org/html/rfc7517).
    #[serde(rename = "use", skip_serializing_if = "Option::is_none", default)]
    pub public_key_use: Option<PublicKeyUse>,

    /// The "key_ops" (key operations) parameter identifies the operation(s)
    /// for which the key is intended to be used.  The "key_ops" parameter is
    /// intended for use cases in which public, private, or symmetric keys
    /// may be present.
    /// Should not be specified with `public_key_use`.
    /// See sections 4.2 and 4.3 of [RFC7517](https://tools.ietf.org/html/rfc7517).
    #[serde(rename = "key_ops", skip_serializing_if = "Option::is_none", default)]
    pub key_operations: Option<Vec<KeyOperations>>,

    /// The algorithm intended for use with the key
    #[serde(rename = "alg", skip_serializing_if = "Option::is_none", default)]
    pub algorithm: Option<Algorithm>,

    /// The case sensitive Key ID for the key
    #[serde(rename = "kid", skip_serializing_if = "Option::is_none", default)]
    pub key_id: Option<String>,

    /// X.509 Public key cerfificate URL. This is currently not implemented (correctly).
    ///
    /// Serialized to `x5u`.
    #[serde(rename = "x5u", skip_serializing_if = "Option::is_none")]
    pub x509_url: Option<String>,

    /// X.509 public key certificate chain. This is currently not implemented (correctly).
    ///
    /// Serialized to `x5c`.
    #[serde(rename = "x5c", skip_serializing_if = "Option::is_none")]
    pub x509_chain: Option<Vec<String>>,

    /// X.509 Certificate SHA1 thumbprint. This is currently not implemented (correctly).
    ///
    /// Serialized to `x5t`.
    #[serde(rename = "x5t", skip_serializing_if = "Option::is_none")]
    pub x509_sha1_fingerprint: Option<String>,

    /// X.509 Certificate SHA256 thumbprint. This is currently not implemented (correctly).
    ///
    /// Serialized to `x5t#S256`.
    #[serde(rename = "x5t#S256", skip_serializing_if = "Option::is_none")]
    pub x509_sha256_fingerprint: Option<String>,
}

/// Key type value for an Elliptic Curve Key.
/// This single value enum is a workaround for Rust not supporting associated constants.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
pub enum EllipticCurveKeyType {
    /// Key type value for an Elliptic Curve Key.
    EC,
}

impl Default for EllipticCurveKeyType {
    fn default() -> Self {
        EllipticCurveKeyType::EC
    }
}

/// Type of cryptographic curve used by a key. This is defined in
/// [RFC 7518 #7.6](https://tools.ietf.org/html/rfc7518#section-7.6)
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
pub enum EllipticCurve {
    /// P-256 curve
    #[serde(rename = "P-256")]
    P256,
    /// P-384 curve
    #[serde(rename = "P-384")]
    P384,
    /// P-521 curve -- unsupported by `ring`.
    #[serde(rename = "P-521")]
    P521,
}

impl Default for EllipticCurve {
    fn default() -> Self {
        EllipticCurve::P256
    }
}

/// Parameters for an Elliptic Curve Key
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Default, Hash)]
pub struct EllipticCurveKeyParameters {
    /// Key type value for an Elliptic Curve Key.
    #[serde(rename = "kty")]
    pub key_type: EllipticCurveKeyType,
    /// The "crv" (curve) parameter identifies the cryptographic curve used
    /// with the key.
    #[serde(rename = "crv")]
    pub curve: EllipticCurve,
    /// The "x" (x coordinate) parameter contains the x coordinate for the
    /// Elliptic Curve point.
    pub x: String,
    /// The "y" (y coordinate) parameter contains the y coordinate for the
    /// Elliptic Curve point.
    pub y: String,
}

/// Key type value for an RSA Key.
/// This single value enum is a workaround for Rust not supporting associated constants.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
pub enum RSAKeyType {
    /// Key type value for an RSA Key.
    RSA,
}

impl Default for RSAKeyType {
    fn default() -> Self {
        RSAKeyType::RSA
    }
}

/// Parameters for a RSA Key
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Default, Hash)]
pub struct RSAKeyParameters {
    /// Key type value for a RSA Key
    #[serde(rename = "kty")]
    pub key_type: RSAKeyType,

    /// The "n" (modulus) parameter contains the modulus value for the RSA
    /// public key.
    pub n: String,

    /// The "e" (exponent) parameter contains the exponent value for the RSA
    /// public key.
    pub e: String,
}

/// Key type value for an Octet symmetric key.
/// This single value enum is a workaround for Rust not supporting associated constants.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
pub enum OctetKeyType {
    /// Key type value for an Octet symmetric key.
    #[serde(rename = "oct")]
    Octet,
}

impl Default for OctetKeyType {
    fn default() -> Self {
        OctetKeyType::Octet
    }
}

/// Parameters for an Octet Key
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Default, Hash)]
pub struct OctetKeyParameters {
    /// Key type value for an Octet Key
    #[serde(rename = "kty")]
    pub key_type: OctetKeyType,
    /// The octet key value
    pub value: String,
}

/// Key type value for an Octet Key Pair.
/// This single value enum is a workaround for Rust not supporting associated constants.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
pub enum OctetKeyPairType {
    /// Key type value for an Octet Key Pair.
    #[serde(rename = "OKP")]
    OctetKeyPair,
}

impl Default for OctetKeyPairType {
    fn default() -> Self {
        OctetKeyPairType::OctetKeyPair
    }
}

/// Parameters for an Octet Key Pair
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Default, Hash)]
pub struct OctetKeyPairParameters {
    /// Key type value for an Octet Key Pair
    #[serde(rename = "kty")]
    pub key_type: OctetKeyPairType,
    /// The "crv" (curve) parameter identifies the cryptographic curve used
    /// with the key.
    #[serde(rename = "crv")]
    pub curve: EllipticCurve,
    /// The "x" parameter contains the base64 encoded public key
    pub x: String,
}

/// Algorithm specific parameters
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
#[serde(untagged)]
pub enum AlgorithmParameters {
    EllipticCurve(EllipticCurveKeyParameters),
    RSA(RSAKeyParameters),
    OctetKey(OctetKeyParameters),
    OctetKeyPair(OctetKeyPairParameters),
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
pub struct Jwk {
    #[serde(flatten)]
    pub common: CommonParameters,
    /// Key algorithm specific parameters
    #[serde(flatten)]
    pub algorithm: AlgorithmParameters,
}

/// A JWK set
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct JwkSet {
    pub keys: Vec<Jwk>,
}

impl JwkSet {
    /// Find the key in the set that matches the given key id, if any.
    pub fn find(&self, kid: &str) -> Option<&Jwk> {
        self.keys
            .iter()
            .find(|jwk| jwk.common.key_id.is_some() && jwk.common.key_id.as_ref().unwrap() == kid)
    }
}
<commit_msg>Fix invalid field name on OctetKeyParameters (#256)<commit_after>#![allow(missing_docs)]
///! This crate contains types only for working JWK and JWK Sets
///! This is only meant to be used to deal with public JWK, not generate ones.
///! Most of the code in this file is taken from https://github.com/lawliet89/biscuit but
/// tweaked to remove the private bits as it's not the goal for this crate currently.
///!
use crate::Algorithm;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;

/// The intended usage of the public `KeyType`. This enum is serialized `untagged`
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum PublicKeyUse {
    /// Indicates a public key is meant for signature verification
    Signature,
    /// Indicates a public key is meant for encryption
    Encryption,
    /// Other usage
    Other(String),
}

impl Serialize for PublicKeyUse {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let string = match *self {
            PublicKeyUse::Signature => "sig",
            PublicKeyUse::Encryption => "enc",
            PublicKeyUse::Other(ref other) => other,
        };

        serializer.serialize_str(string)
    }
}

impl<'de> Deserialize<'de> for PublicKeyUse {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct PublicKeyUseVisitor;
        impl<'de> de::Visitor<'de> for PublicKeyUseVisitor {
            type Value = PublicKeyUse;

            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
                write!(formatter, "a string")
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: de::Error,
            {
                Ok(match v {
                    "sig" => PublicKeyUse::Signature,
                    "enc" => PublicKeyUse::Encryption,
                    other => PublicKeyUse::Other(other.to_string()),
                })
            }
        }

        deserializer.deserialize_string(PublicKeyUseVisitor)
    }
}

/// Operations that the key is intended to be used for. This enum is serialized `untagged`
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum KeyOperations {
    /// Computer digital signature or MAC
    Sign,
    /// Verify digital signature or MAC
    Verify,
    /// Encrypt content
    Encrypt,
    /// Decrypt content and validate decryption, if applicable
    Decrypt,
    /// Encrypt key
    WrapKey,
    /// Decrypt key and validate decryption, if applicable
    UnwrapKey,
    /// Derive key
    DeriveKey,
    /// Derive bits not to be used as a key
    DeriveBits,
    /// Other operation
    Other(String),
}

impl Serialize for KeyOperations {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let string = match *self {
            KeyOperations::Sign => "sign",
            KeyOperations::Verify => "verify",
            KeyOperations::Encrypt => "encrypt",
            KeyOperations::Decrypt => "decrypt",
            KeyOperations::WrapKey => "wrapKey",
            KeyOperations::UnwrapKey => "unwrapKey",
            KeyOperations::DeriveKey => "deriveKey",
            KeyOperations::DeriveBits => "deriveBits",
            KeyOperations::Other(ref other) => other,
        };

        serializer.serialize_str(string)
    }
}

impl<'de> Deserialize<'de> for KeyOperations {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct KeyOperationsVisitor;
        impl<'de> de::Visitor<'de> for KeyOperationsVisitor {
            type Value = KeyOperations;

            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
                write!(formatter, "a string")
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: de::Error,
            {
                Ok(match v {
                    "sign" => KeyOperations::Sign,
                    "verify" => KeyOperations::Verify,
                    "encrypt" => KeyOperations::Encrypt,
                    "decrypt" => KeyOperations::Decrypt,
                    "wrapKey" => KeyOperations::WrapKey,
                    "unwrapKey" => KeyOperations::UnwrapKey,
                    "deriveKey" => KeyOperations::DeriveKey,
                    "deriveBits" => KeyOperations::DeriveBits,
                    other => KeyOperations::Other(other.to_string()),
                })
            }
        }

        deserializer.deserialize_string(KeyOperationsVisitor)
    }
}

/// Common JWK parameters
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Default, Hash)]
pub struct CommonParameters {
    /// The intended use of the public key. Should not be specified with `key_operations`.
    /// See sections 4.2 and 4.3 of [RFC7517](https://tools.ietf.org/html/rfc7517).
    #[serde(rename = "use", skip_serializing_if = "Option::is_none", default)]
    pub public_key_use: Option<PublicKeyUse>,

    /// The "key_ops" (key operations) parameter identifies the operation(s)
    /// for which the key is intended to be used.  The "key_ops" parameter is
    /// intended for use cases in which public, private, or symmetric keys
    /// may be present.
    /// Should not be specified with `public_key_use`.
    /// See sections 4.2 and 4.3 of [RFC7517](https://tools.ietf.org/html/rfc7517).
    #[serde(rename = "key_ops", skip_serializing_if = "Option::is_none", default)]
    pub key_operations: Option<Vec<KeyOperations>>,

    /// The algorithm intended for use with the key
    #[serde(rename = "alg", skip_serializing_if = "Option::is_none", default)]
    pub algorithm: Option<Algorithm>,

    /// The case sensitive Key ID for the key
    #[serde(rename = "kid", skip_serializing_if = "Option::is_none", default)]
    pub key_id: Option<String>,

    /// X.509 Public key cerfificate URL. This is currently not implemented (correctly).
    ///
    /// Serialized to `x5u`.
    #[serde(rename = "x5u", skip_serializing_if = "Option::is_none")]
    pub x509_url: Option<String>,

    /// X.509 public key certificate chain. This is currently not implemented (correctly).
    ///
    /// Serialized to `x5c`.
    #[serde(rename = "x5c", skip_serializing_if = "Option::is_none")]
    pub x509_chain: Option<Vec<String>>,

    /// X.509 Certificate SHA1 thumbprint. This is currently not implemented (correctly).
    ///
    /// Serialized to `x5t`.
    #[serde(rename = "x5t", skip_serializing_if = "Option::is_none")]
    pub x509_sha1_fingerprint: Option<String>,

    /// X.509 Certificate SHA256 thumbprint. This is currently not implemented (correctly).
    ///
    /// Serialized to `x5t#S256`.
    #[serde(rename = "x5t#S256", skip_serializing_if = "Option::is_none")]
    pub x509_sha256_fingerprint: Option<String>,
}

/// Key type value for an Elliptic Curve Key.
/// This single value enum is a workaround for Rust not supporting associated constants.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
pub enum EllipticCurveKeyType {
    /// Key type value for an Elliptic Curve Key.
    EC,
}

impl Default for EllipticCurveKeyType {
    fn default() -> Self {
        EllipticCurveKeyType::EC
    }
}

/// Type of cryptographic curve used by a key. This is defined in
/// [RFC 7518 #7.6](https://tools.ietf.org/html/rfc7518#section-7.6)
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
pub enum EllipticCurve {
    /// P-256 curve
    #[serde(rename = "P-256")]
    P256,
    /// P-384 curve
    #[serde(rename = "P-384")]
    P384,
    /// P-521 curve -- unsupported by `ring`.
    #[serde(rename = "P-521")]
    P521,
}

impl Default for EllipticCurve {
    fn default() -> Self {
        EllipticCurve::P256
    }
}

/// Parameters for an Elliptic Curve Key
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Default, Hash)]
pub struct EllipticCurveKeyParameters {
    /// Key type value for an Elliptic Curve Key.
    #[serde(rename = "kty")]
    pub key_type: EllipticCurveKeyType,
    /// The "crv" (curve) parameter identifies the cryptographic curve used
    /// with the key.
    #[serde(rename = "crv")]
    pub curve: EllipticCurve,
    /// The "x" (x coordinate) parameter contains the x coordinate for the
    /// Elliptic Curve point.
    pub x: String,
    /// The "y" (y coordinate) parameter contains the y coordinate for the
    /// Elliptic Curve point.
    pub y: String,
}

/// Key type value for an RSA Key.
/// This single value enum is a workaround for Rust not supporting associated constants.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
pub enum RSAKeyType {
    /// Key type value for an RSA Key.
    RSA,
}

impl Default for RSAKeyType {
    fn default() -> Self {
        RSAKeyType::RSA
    }
}

/// Parameters for a RSA Key
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Default, Hash)]
pub struct RSAKeyParameters {
    /// Key type value for a RSA Key
    #[serde(rename = "kty")]
    pub key_type: RSAKeyType,

    /// The "n" (modulus) parameter contains the modulus value for the RSA
    /// public key.
    pub n: String,

    /// The "e" (exponent) parameter contains the exponent value for the RSA
    /// public key.
    pub e: String,
}

/// Key type value for an Octet symmetric key.
/// This single value enum is a workaround for Rust not supporting associated constants.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
pub enum OctetKeyType {
    /// Key type value for an Octet symmetric key.
    #[serde(rename = "oct")]
    Octet,
}

impl Default for OctetKeyType {
    fn default() -> Self {
        OctetKeyType::Octet
    }
}

/// Parameters for an Octet Key
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Default, Hash)]
pub struct OctetKeyParameters {
    /// Key type value for an Octet Key
    #[serde(rename = "kty")]
    pub key_type: OctetKeyType,
    /// The octet key value
    #[serde(rename = "k")]
    pub value: String,
}

/// Key type value for an Octet Key Pair.
/// This single value enum is a workaround for Rust not supporting associated constants.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
pub enum OctetKeyPairType {
    /// Key type value for an Octet Key Pair.
    #[serde(rename = "OKP")]
    OctetKeyPair,
}

impl Default for OctetKeyPairType {
    fn default() -> Self {
        OctetKeyPairType::OctetKeyPair
    }
}

/// Parameters for an Octet Key Pair
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Default, Hash)]
pub struct OctetKeyPairParameters {
    /// Key type value for an Octet Key Pair
    #[serde(rename = "kty")]
    pub key_type: OctetKeyPairType,
    /// The "crv" (curve) parameter identifies the cryptographic curve used
    /// with the key.
    #[serde(rename = "crv")]
    pub curve: EllipticCurve,
    /// The "x" parameter contains the base64 encoded public key
    pub x: String,
}

/// Algorithm specific parameters
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
#[serde(untagged)]
pub enum AlgorithmParameters {
    EllipticCurve(EllipticCurveKeyParameters),
    RSA(RSAKeyParameters),
    OctetKey(OctetKeyParameters),
    OctetKeyPair(OctetKeyPairParameters),
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
pub struct Jwk {
    #[serde(flatten)]
    pub common: CommonParameters,
    /// Key algorithm specific parameters
    #[serde(flatten)]
    pub algorithm: AlgorithmParameters,
}

/// A JWK set
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct JwkSet {
    pub keys: Vec<Jwk>,
}

impl JwkSet {
    /// Find the key in the set that matches the given key id, if any.
    pub fn find(&self, kid: &str) -> Option<&Jwk> {
        self.keys
            .iter()
            .find(|jwk| jwk.common.key_id.is_some() && jwk.common.key_id.as_ref().unwrap() == kid)
    }
}

#[cfg(test)]
mod tests {
    use crate::jwk::{AlgorithmParameters, JwkSet, OctetKeyType};
    use crate::Algorithm;
    use serde_json::json;

    #[test]
    fn check_hs256() {
        let key =
            base64::encode_config("abcdefghijklmnopqrstuvwxyz012345", base64::URL_SAFE_NO_PAD);
        let jwks_json = json!({
            "keys": [
                {
                    "kty": "oct",
                    "alg": "HS256",
                    "kid": "abc123",
                    "k": key
                }
            ]
        });

        let set: JwkSet = serde_json::from_value(jwks_json).expect("Failed HS256 check");
        assert_eq!(set.keys.len(), 1);
        let key = &set.keys[0];
        assert_eq!(key.common.key_id, Some("abc123".to_string()));
        assert_eq!(key.common.algorithm, Some(Algorithm::HS256));
        match &key.algorithm {
            AlgorithmParameters::OctetKey(key) => {
                assert_eq!(key.key_type, OctetKeyType::Octet);
                assert_eq!(key.value, key.value)
            }
            _ => panic!("Unexpected key algorithm"),
        }
    }
}
<|endoftext|>


<commit_before>// Claxon -- A FLAC decoding library in Rust
// Copyright (C) 2014-2015 Ruud van Asseldonk
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! Claxon, a FLAC decoding library.
//!
//! TODO: Add some examples here.

#![warn(missing_docs)]
#![allow(dead_code)] // TODO: Remove for v0.1
#![feature(io)]

use std::num::UnsignedInt;
use error::{Error, FlacResult};
use frame::{FrameReader};
use metadata::{MetadataBlock, MetadataBlockReader, StreamInfo};

mod bitstream;
mod crc;
pub mod error;
pub mod frame;
pub mod subframe;
pub mod metadata;

/// A FLAC decoder that can decode the stream from the underlying reader.
///
/// TODO: Is stream a good name? Should it be called reader/decoder?
/// TODO: Add an example.
pub struct FlacStream<'r> {
    streaminfo: StreamInfo,
    metadata_blocks: Vec<MetadataBlock>,
    input: &'r mut (Reader + 'r)
}

fn read_stream_header(input: &mut Reader) -> FlacResult<()> {
    // A FLAC stream starts with a 32-bit header 'fLaC' (big endian).
    const HEADER: u32 = 0x66_4c_61_43;
    let header = try!(input.read_be_u32());
    if header != HEADER { return Err(Error::InvalidStreamHeader); }
    Ok(())
}

impl<'r> FlacStream<'r> {
    /// Constructs a flac stream from the given input.
    ///
    /// This will read all metadata and stop at the first audio frame.
    pub fn new<R>(input: &mut R) -> FlacResult<FlacStream> where R: Reader {
        // A flac stream first of all starts with a stream header.
        try!(read_stream_header(input));

        // Start a new scope, because the input reader must be available again
        // for the frame reader next.
        let (streaminfo, metadata_blocks) = {
            // Next are one or more metadata blocks. The flac specification
            // dictates that the streaminfo block is the first block. The metadata
            // block reader will yield at least one element, so the unwrap is safe.
            let mut metadata_iter = MetadataBlockReader::new(input);
            let streaminfo_block = try!(metadata_iter.next().unwrap());
            let streaminfo = match streaminfo_block {
                MetadataBlock::StreamInfo(info) => info,
                _ => return Err(Error::MissingStreamInfoBlock)
            };

            // There might be more metadata blocks, read and store them.
            let mut metadata_blocks = Vec::new();
            for block_result in metadata_iter {
                match block_result {
                    Err(error) => return Err(error),
                    Ok(block) => metadata_blocks.push(block)
                }
            }

            (streaminfo, metadata_blocks)
        };

        // The flac stream will contain the reader that will read frames.
        let flac_stream = FlacStream {
            streaminfo: streaminfo,
            metadata_blocks: metadata_blocks,
            input: input
        };

        Ok(flac_stream)
    }

    /// Returns the streaminfo metadata.
    pub fn streaminfo(&self) -> &StreamInfo {
        &self.streaminfo
    }

    /// Returns an iterator that decodes a single frame on every iteration.
    pub fn blocks<Sample>(&'r mut self) -> FrameReader<'r, Sample>
        where Sample: UnsignedInt {
        FrameReader::new(&mut self.input)
    }
}
<commit_msg>silence warnings about core being unstable for now<commit_after>// Claxon -- A FLAC decoding library in Rust
// Copyright (C) 2014-2015 Ruud van Asseldonk
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! Claxon, a FLAC decoding library.
//!
//! TODO: Add some examples here.

#![warn(missing_docs)]
#![allow(dead_code)] // TODO: Remove for v0.1
#![feature(core, io)]

use std::num::UnsignedInt;
use error::{Error, FlacResult};
use frame::{FrameReader};
use metadata::{MetadataBlock, MetadataBlockReader, StreamInfo};

mod bitstream;
mod crc;
pub mod error;
pub mod frame;
pub mod subframe;
pub mod metadata;

/// A FLAC decoder that can decode the stream from the underlying reader.
///
/// TODO: Is stream a good name? Should it be called reader/decoder?
/// TODO: Add an example.
pub struct FlacStream<'r> {
    streaminfo: StreamInfo,
    metadata_blocks: Vec<MetadataBlock>,
    input: &'r mut (Reader + 'r)
}

fn read_stream_header(input: &mut Reader) -> FlacResult<()> {
    // A FLAC stream starts with a 32-bit header 'fLaC' (big endian).
    const HEADER: u32 = 0x66_4c_61_43;
    let header = try!(input.read_be_u32());
    if header != HEADER { return Err(Error::InvalidStreamHeader); }
    Ok(())
}

impl<'r> FlacStream<'r> {
    /// Constructs a flac stream from the given input.
    ///
    /// This will read all metadata and stop at the first audio frame.
    pub fn new<R>(input: &mut R) -> FlacResult<FlacStream> where R: Reader {
        // A flac stream first of all starts with a stream header.
        try!(read_stream_header(input));

        // Start a new scope, because the input reader must be available again
        // for the frame reader next.
        let (streaminfo, metadata_blocks) = {
            // Next are one or more metadata blocks. The flac specification
            // dictates that the streaminfo block is the first block. The metadata
            // block reader will yield at least one element, so the unwrap is safe.
            let mut metadata_iter = MetadataBlockReader::new(input);
            let streaminfo_block = try!(metadata_iter.next().unwrap());
            let streaminfo = match streaminfo_block {
                MetadataBlock::StreamInfo(info) => info,
                _ => return Err(Error::MissingStreamInfoBlock)
            };

            // There might be more metadata blocks, read and store them.
            let mut metadata_blocks = Vec::new();
            for block_result in metadata_iter {
                match block_result {
                    Err(error) => return Err(error),
                    Ok(block) => metadata_blocks.push(block)
                }
            }

            (streaminfo, metadata_blocks)
        };

        // The flac stream will contain the reader that will read frames.
        let flac_stream = FlacStream {
            streaminfo: streaminfo,
            metadata_blocks: metadata_blocks,
            input: input
        };

        Ok(flac_stream)
    }

    /// Returns the streaminfo metadata.
    pub fn streaminfo(&self) -> &StreamInfo {
        &self.streaminfo
    }

    /// Returns an iterator that decodes a single frame on every iteration.
    pub fn blocks<Sample>(&'r mut self) -> FrameReader<'r, Sample>
        where Sample: UnsignedInt {
        FrameReader::new(&mut self.input)
    }
}
<|endoftext|>


<commit_before>#![feature(associated_consts)]
#![feature(core_intrinsics)]
#![feature(thread_sleep)]
#![feature(convert)]
#![feature(core)]

extern crate libc;
extern crate mmap;
extern crate mio;
extern crate spidev;
extern crate core;
extern crate nix;
#[macro_use] extern crate bitflags;

mod result;
mod map;
mod logic;
mod board;
mod cupi;

pub use cupi::{
    CuPi
};

pub use logic::{
    Logic,
    Logic3,
    DigitalLogic,
    DigitalWrite,
    DigitalRead,
    AnalogWrite,
    AnalogRead,
};

pub use result::{
    Result,
    Error
};

pub use board::{
    Board,
    Hardware,
    CPU,
    RaspberryModel,
    RaspberryRevision,
    RaspberryMaker,
    board
};

pub mod bcm270x;
pub mod sys;

pub use bcm270x::{
    PinOptions,
    PinInput,
    PinOutput
};

use std::thread;
use std::time::Duration;
use nix::sys::ioctl::libc::geteuid;

pub trait RegisterDesc {
    fn offset(&self) -> usize;
}

pub trait RegisterOperations<T> {
    fn write(&self, data: T);
    fn read(&self) -> T;
    fn bitand(&self, data: T);
    fn bitor(&self, data: T);
    fn bitxor(&self, data: T);
}

pub struct Register<R: RegisterDesc> {
    pub ptr: *mut u32,
    pub desc: R
}

impl<R: RegisterDesc> RegisterOperations<u32> for Register<R> {
    #[inline(always)]
    fn write(&self, data: u32) {
        unsafe { *self.ptr = data; }
    }

    #[inline(always)]
    fn read(&self) -> u32 {
        unsafe { *self.ptr }
    }

    #[inline(always)]
    fn bitand(&self, data: u32) {
        unsafe { *self.ptr &= data; }
    }

    #[inline(always)]
    fn bitor(&self, data: u32) {
        unsafe { *self.ptr |= data; }
    }

    #[inline(always)]
    fn bitxor(&self, data: u32) {
        unsafe { *self.ptr ^= data; }
    }
}

#[inline(always)]
pub fn delay(dur: Duration) {
    // FIXME: todo sleep hard if < 100
    thread::sleep(dur);
}

#[inline(always)]
pub fn delay_ms(ms: u64) {
    delay(Duration::from_millis(ms));
}

pub fn is_root() -> bool {
    unsafe { geteuid() == 0 }
}
<commit_msg>add feature 'duration'<commit_after>#![feature(associated_consts)]
#![feature(core_intrinsics)]
#![feature(duration)]
#![feature(thread_sleep)]
#![feature(convert)]
#![feature(core)]

extern crate libc;
extern crate mmap;
extern crate mio;
extern crate spidev;
extern crate core;
extern crate nix;
#[macro_use] extern crate bitflags;

mod result;
mod map;
mod logic;
mod board;
mod cupi;

pub use cupi::{
    CuPi
};

pub use logic::{
    Logic,
    Logic3,
    DigitalLogic,
    DigitalWrite,
    DigitalRead,
    AnalogWrite,
    AnalogRead,
};

pub use result::{
    Result,
    Error
};

pub use board::{
    Board,
    Hardware,
    CPU,
    RaspberryModel,
    RaspberryRevision,
    RaspberryMaker,
    board
};

pub mod bcm270x;
pub mod sys;

pub use bcm270x::{
    PinOptions,
    PinInput,
    PinOutput
};

use std::thread;
use std::time::Duration;
use nix::sys::ioctl::libc::geteuid;

pub trait RegisterDesc {
    fn offset(&self) -> usize;
}

pub trait RegisterOperations<T> {
    fn write(&self, data: T);
    fn read(&self) -> T;
    fn bitand(&self, data: T);
    fn bitor(&self, data: T);
    fn bitxor(&self, data: T);
}

pub struct Register<R: RegisterDesc> {
    pub ptr: *mut u32,
    pub desc: R
}

impl<R: RegisterDesc> RegisterOperations<u32> for Register<R> {
    #[inline(always)]
    fn write(&self, data: u32) {
        unsafe { *self.ptr = data; }
    }

    #[inline(always)]
    fn read(&self) -> u32 {
        unsafe { *self.ptr }
    }

    #[inline(always)]
    fn bitand(&self, data: u32) {
        unsafe { *self.ptr &= data; }
    }

    #[inline(always)]
    fn bitor(&self, data: u32) {
        unsafe { *self.ptr |= data; }
    }

    #[inline(always)]
    fn bitxor(&self, data: u32) {
        unsafe { *self.ptr ^= data; }
    }
}

#[inline(always)]
pub fn delay(dur: Duration) {
    // FIXME: todo sleep hard if < 100
    thread::sleep(dur);
}

#[inline(always)]
pub fn delay_ms(ms: u64) {
    delay(Duration::from_millis(ms));
}

pub fn is_root() -> bool {
    unsafe { geteuid() == 0 }
}
<|endoftext|>


<commit_before>#![feature(collections)]
#![feature(core)]
#![feature(test)]

//! Txtdist is small utility crate for calculating the distance between two strings.

extern crate test;

use std::collections::VecMap;
use std::iter::range_inclusive;
use std::cmp::min;

/// Calculate the distance between two strings using the damerau levenshtein algorithm.
///
///
///
/// > The Damerau–Levenshtein distance (named after Frederick J. Damerau and Vladimir I. Levenshtein)
/// > is a distance (string metric) between two strings, i.e., finite sequence of symbols,
/// > given by counting the minimum number of operations needed to transform one string into the other,
/// > where an operation is defined as an insertion, deletion, or substitution of a single character,
/// > or a transposition of two adjacent characters.
/// [wikipedia](http://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance)
///
/// # Example
///
/// ```rust
/// use txtdist::damerau_levenshtein;
///
/// let distance = damerau_levenshtein("some string", "some other string");
/// assert_eq!(distance, 6)
/// ```
pub fn damerau_levenshtein(source: &str, target: &str) -> u32 {
    let (n, m) = (source.len(), target.len());

    if n == 0 { return m as u32; }
    if m == 0 { return n as u32; }

    if n == m && source == target {
        return 0;
    }

    let inf = n + m;

    let mut matrix = vec![vec![0; m+2]; n+2];

    matrix[0][0] = inf;
    for i in range_inclusive(0, n) {
        matrix[i+1][0] = inf;
        matrix[i+1][1] = i;
    }
    for j in range_inclusive(0, m) {
        matrix[0][j+1] = inf;
        matrix[1][j+1] = j;
    };

    let mut last_row = VecMap::new();

    for row in range_inclusive(1, n) {
        let char_s = source.char_at(row-1);
        let mut last_match_col = 0;

        for col in range_inclusive(1, m) {
            let char_t = target.char_at(col-1);
            let last_match_row = *last_row.get(&(char_t as usize)).unwrap_or(&0);
            let cost = if char_s == char_t { 0 } else { 1 };

            let dist_add = matrix[row][col+1] + 1;
            let dist_del = matrix[row+1][col] + 1;
            let dist_sub = matrix[row][col] + cost;
            let dist_trans = matrix[last_match_row][last_match_col]
                            + (row - last_match_row - 1) + 1
                            + (col - last_match_col - 1);

            let dist = min(min(dist_add, dist_del),
                           min(dist_sub, dist_trans));

            matrix[row+1][col+1] = dist;

            if cost == 0 {
                last_match_col = col;
            }
        }

        last_row.insert(char_s as usize, row);
    }

    matrix[n+1][m+1] as u32
}

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

    #[test]
    fn test_damerau_levenschtein() {
        let distance = damerau_levenshtein("CA", "ABC");
        assert_eq!(distance, 2);

        let distance = damerau_levenshtein("an act", "a cat");
        assert_eq!(distance, 2);

        let distance = damerau_levenshtein("", "a cat");
        assert_eq!(distance, 5);

        let distance = damerau_levenshtein("MERCEDES-BENS", "MERCEDES-BENZ");
        assert_eq!(distance, 1);

        let distance = damerau_levenshtein("", "");
        assert_eq!(distance, 0);

        let distance = damerau_levenshtein("some string", "some string");
        assert_eq!(distance, 0);
    }

    #[bench]
    fn bench_damerau_levenschtein(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("one string", "other string"));
    }

    #[bench]
    fn bench_damerau_levenschtein_same_length(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("one string12", "other string"));
    }

    #[bench]
    fn bench_damerau_levenschtein_empty(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("", "other string"));
    }

    #[bench]
    fn bench_damerau_levenschtein_same(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("some string", "some string"));
    }
}
<commit_msg>Updated to Rust 1.0.0-beta<commit_after>//! Txtdist is small utility crate for calculating the distance between two strings.

use std::collections::BTreeMap;
use std::cmp::min;

/// Calculate the distance between two strings using the damerau levenshtein algorithm.
///
///
///
/// > The Damerau–Levenshtein distance (named after Frederick J. Damerau and Vladimir I. Levenshtein)
/// > is a distance (string metric) between two strings, i.e., finite sequence of symbols,
/// > given by counting the minimum number of operations needed to transform one string into the other,
/// > where an operation is defined as an insertion, deletion, or substitution of a single character,
/// > or a transposition of two adjacent characters.
/// [wikipedia](http://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance)
///
/// # Example
///
/// ```rust
/// use txtdist::damerau_levenshtein;
///
/// let distance = damerau_levenshtein("some string", "some other string");
/// assert_eq!(distance, 6)
/// ```
pub fn damerau_levenshtein(source: &str, target: &str) -> u32 {
    let (n, m) = (source.len(), target.len());

    if n == 0 { return m as u32; }
    if m == 0 { return n as u32; }

    if n == m && source == target {
        return 0;
    }

    let inf = n + m;

    let mut matrix = vec![vec![0; m+2]; n+2];

    matrix[0][0] = inf;
    for i in 0..n+1 {
        matrix[i+1][0] = inf;
        matrix[i+1][1] = i;
    }
    for j in 0..m+1 {
        matrix[0][j+1] = inf;
        matrix[1][j+1] = j;
    };

    let mut last_row = BTreeMap::new();

    for (row, char_s) in source.chars().enumerate() {
        let mut last_match_col = 0;
        let row = row + 1;

        for (col, char_t) in target.chars().enumerate() {
            let col = col + 1;
            let last_match_row = *last_row.get(&(char_t as usize)).unwrap_or(&0);
            let cost = if char_s == char_t { 0 } else { 1 };

            let dist_add = matrix[row][col+1] + 1;
            let dist_del = matrix[row+1][col] + 1;
            let dist_sub = matrix[row][col] + cost;
            let dist_trans = matrix[last_match_row][last_match_col]
                            + (row - last_match_row - 1) + 1
                            + (col - last_match_col - 1);

            let dist = min(min(dist_add, dist_del),
                           min(dist_sub, dist_trans));

            matrix[row+1][col+1] = dist;

            if cost == 0 {
                last_match_col = col;
            }
        }

        last_row.insert(char_s as usize, row);
    }

    matrix[n+1][m+1] as u32
}

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

    #[test]
    fn test_damerau_levenschtein() {
        let distance = damerau_levenshtein("CA", "ABC");
        assert_eq!(distance, 2);

        let distance = damerau_levenshtein("an act", "a cat");
        assert_eq!(distance, 2);

        let distance = damerau_levenshtein("", "a cat");
        assert_eq!(distance, 5);

        let distance = damerau_levenshtein("MERCEDES-BENS", "MERCEDES-BENZ");
        assert_eq!(distance, 1);

        let distance = damerau_levenshtein("", "");
        assert_eq!(distance, 0);

        let distance = damerau_levenshtein("some string", "some string");
        assert_eq!(distance, 0);
    }

    /*
    #[bench]
    fn bench_damerau_levenschtein(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("one string", "other string"));
    }

    #[bench]
    fn bench_damerau_levenschtein_same_length(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("one string12", "other string"));
    }

    #[bench]
    fn bench_damerau_levenschtein_empty(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("", "other string"));
    }

    #[bench]
    fn bench_damerau_levenschtein_same(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("some string", "some string"));
    }
    */
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! A [Fleetspeak] client connector library.
//!
//! This library exposes a set of functions for writing client-side Fleetspeak
//! services. Each of these functions operates on a global connection object
//! that is lazily established. If this global connection cannot be established,
//! the library will panic (because without this connection Fleetspeak will shut
//! the service down anyway).
//!
//! Note that each service should send startup information upon its inception
//! and continue to heartbeat from time to time to notify the Fleetspeak client
//! that it did not get stuck.
//!
//! [Fleetspeak]: https://github.com/google/fleetspeak

mod connection;
mod error;

use std::fs::File;
use std::sync::Mutex;
use std::time::{Duration, Instant};

use lazy_static::lazy_static;
use log::{info, error};

pub use self::connection::Message;
pub use self::error::{ReadError, WriteError};

/// Sends a heartbeat signal to the Fleetspeak client.
///
/// All client services should heartbeat from time to time. Otherwise, from the
/// Fleetspeak perspective, the service is unresponsive and should be restarted.
///
/// The exact frequency of the required heartbeat is defined in the service
/// configuration file.
pub fn heartbeat() -> Result<(), WriteError> {
    locked(&CONNECTION.output, |buf| self::connection::heartbeat(buf))
}

/// Sends a heartbeat signal to the Fleetspeak client but no more frequently
/// than the specified `rate`.
///
/// Note that the specified `rate` should be at least the rate defined in the
/// Fleetspeak service configuration file. Because of potential slowdowns, some
/// margin of error should be left.
///
/// See documentation for the [`heartbeat`] function for more details.
///
/// [`heartbeat`]: heartbeat
pub fn heartbeat_with_throttle(rate: Duration) -> Result<(), WriteError> {
    lazy_static! {
        static ref LAST_HEARTBEAT: Mutex<Option<Instant>> = Mutex::new(None);
    }

    let mut last_heartbeat = LAST_HEARTBEAT.lock()
        .expect("poisoned heartbeat mutex");

    match *last_heartbeat {
        Some(last_heartbeat) if last_heartbeat.elapsed() < rate => {
            // Do nothing if the last heartbeat happened more recently than the
            // specified heartbeat rate.
            return Ok(());
        }
        _ => (),
    }

    heartbeat()?;
    *last_heartbeat = Some(Instant::now());

    Ok(())
}

/// Sends a system message with startup information to the Fleetspeak client.
///
/// All clients are required to send this information on startup. If the client
/// does not receive this information quickly enough, the service will be
/// killed.
///
/// The `version` string should contain a self-reported version of the service.
/// This data is used primarily for statistics.
pub fn startup(version: &str) -> Result<(), WriteError> {
    locked(&CONNECTION.output, |buf| self::connection::startup(buf, version))
}

/// Sends the message to the Fleetspeak server.
///
/// The data is delivered to the server-side service as specified by the message
/// and optionally tagged with a type if specified. This optional message type
/// is irrelevant for Fleetspeak but might be useful for the service the message
/// is delivered to.
///
/// In case of any I/O failure or malformed message (e.g. due to encoding
/// problems), an error is reported.
///
/// # Examples
///
/// ```no_run
/// use fleetspeak::Message;
/// use protobuf::well_known_types::StringValue;
///
/// let mut message = StringValue::new();
/// message.set_value(String::from("Hello, World!"));
///
/// fleetspeak::send(Message {
///     service: String::from("example"),
///     kind: None,
///     data: message,
/// }).expect("failed to send the message");
/// ```
pub fn send<M>(message: Message<M>) -> Result<(), WriteError>
where
    M: protobuf::Message,
{
    locked(&CONNECTION.output, |buf| self::connection::send(buf, message))
}

/// Receives a message from the Fleetspeak server.
///
/// This function will block until there is a message to be read from the input.
/// Note that in particular it means your service will be unable to heartbeat
/// properly. If you are not expecting the message to arrive quickly, you should
/// use [`receive_with_heartbeat`] instead.
///
/// In case of any I/O failure or malformed message (e.g. due to parsing issues
/// or when some fields are not being present), an error is reported.
///
/// [`receive_with_heartbeat`]: fn.receive_with_heartbeat.html
///
/// # Examples
///
/// ```no_run
/// use protobuf::well_known_types::StringValue;
///
/// match fleetspeak::receive::<StringValue>() {
///     Ok(message) => println!("Hello, {}!", message.data.get_value()),
///     Err(error) => eprintln!("failed to receive the message: {}", error),
/// }
/// ```
pub fn receive<M>() -> Result<Message<M>, ReadError>
where
    M: protobuf::Message,
{
    locked(&CONNECTION.input, |buf| self::connection::receive(buf))
}

/// Receive a message from the Fleetspeak server, heartbeating in background.
///
/// Unlike [`receive`], `collect` will send heartbeat signals at the specified
/// `rate` while waiting for the message.
///
/// This function is useful in the main loop of your service when it is not
/// supposed to do anything until a request from the server arrives. If your
/// service is actually awaiting for a specific message to come, you should
/// use [`receive`] instead.
///
/// In case of any I/O failure or malformed message (e.g. due to parsing issues
/// or when some fields are not being present), an error is reported.
///
/// [`receive`]: fn.receive.html
///
/// # Examples
///
/// ```no_run
/// use std::time::Duration;
///
/// use protobuf::well_known_types::StringValue;
///
/// match fleetspeak::receive_with_heartbeat::<StringValue>(Duration::from_secs(1)) {
///     Ok(message) => println!("Hello, {}!", message.data.get_value()),
///     Err(error) => eprintln!("failed to collected the message: {}", error),
/// }
/// ```
pub fn receive_with_heartbeat<M>(rate: Duration) -> Result<Message<M>, ReadError>
where
    M: protobuf::Message + 'static,
{
    // TODO: Refactor this code once `!` stabilizes.
    let (sender, receiver) = std::sync::mpsc::channel();

    std::thread::spawn(move || {
        loop {
            use std::sync::mpsc::TryRecvError::*;

            // The heartbeat thread should stop itself when it receives a signal
            // to do so (or when the channel is closed). Otherwise, it should
            // keep heartbeating.
            match receiver.try_recv() {
                Ok(()) => return,
                Err(Empty) => (),
                Err(Disconnected) => return,
            }

            // Ignoring heartbeat errors is not great, but they can occur only
            // in very rare cases and any subsequent write operations are going
            // to fail soon anyway. Hence, we drop the error on the floor and
            // shut the thread down, hoping that the main thread will notice the
            // problem as soon as it tries to write something. In case the main
            // thread blocks indefinitely, Fleetspeak should figure out that the
            // service is unresponsive and kill it eventually.
            match heartbeat() {
                Ok(()) => (),
                Err(error) => {
                    error!(target: "fleetspeak", "heartbeat error: {}", error);
                    return;
                },
            }

            std::thread::sleep(rate);
        }
    });

    let message = receive()?;

    // Notify the heartbeat thread to shut down. We do not really care whether
    // the message was really delivered as this can fail only if the channel
    // disconnected (and this can happen only if the thread is already dead).
    let _ = sender.send(());

    Ok(message)
}

/// A connection to the Fleetspeak client.
///
/// The connection is realized through two files (specified by descriptors given
/// by the Fleetspeak client as environment variables): input and output. Each
/// of these files is guarded by a separate mutex to allow writing (e.g. for
/// sending heartbeat signals) when another thread might be busy with reading
/// messages.
struct Connection {
    input: Mutex<File>,
    output: Mutex<File>,
}

lazy_static! {
    static ref CONNECTION: Connection = {
        let mut input = open("FLEETSPEAK_COMMS_CHANNEL_INFD");
        let mut output = open("FLEETSPEAK_COMMS_CHANNEL_OUTFD");

        use self::connection::handshake;
        handshake(&mut input, &mut output).expect("handshake failure");

        info!(target: "fleetspeak", "handshake successful");

        Connection {
            input: Mutex::new(input),
            output: Mutex::new(output),
        }
    };
}

/// Executes the given function with a file extracted from the mutex.
///
/// It might happen that the mutex becomes poisoned and this call will panic in
/// result. This should not be a problem in practice, because mutex poisoning
/// is a result of one of the threads being aborted. In case of a such scenario,
/// it is likely the service needs to be restarted anyway.
fn locked<F, T, E>(mutex: &Mutex<File>, f: F) -> Result<T, E>
where
    F: FnOnce(&mut File) -> Result<T, E>
{
    let mut file = mutex.lock().expect("poisoned connection mutex");
    f(&mut file)
}

/// Opens a file object pointed by an environment variable.
///
/// Note that this function will panic if the environment variable `var` is not
/// a valid file descriptor (in which case the library cannot be initialized and
/// the service is unlikely to work anyway).
fn open(var: &str) -> File {
    let fd = std::env::var(var)
        .expect(&format!("invalid variable `{}`", var))
        .parse()
        .expect(&format!("failed to parse file descriptor"));

    #[cfg(target_family = "unix")]
    unsafe {
        std::os::unix::io::FromRawFd::from_raw_fd(fd)
    }

    #[cfg(target_family = "windows")]
    unsafe {
        // We use `identity` to specify the type for the `parse` call above and
        // then cast it to an appropriate Windows-specific pointer type.
        let handle = std::convert::identity::<usize>(fd) as _;
        std::os::windows::io::FromRawHandle::from_raw_handle(handle)
    }
}
<commit_msg>Use documentation comment item link syntax.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! A [Fleetspeak] client connector library.
//!
//! This library exposes a set of functions for writing client-side Fleetspeak
//! services. Each of these functions operates on a global connection object
//! that is lazily established. If this global connection cannot be established,
//! the library will panic (because without this connection Fleetspeak will shut
//! the service down anyway).
//!
//! Note that each service should send startup information upon its inception
//! and continue to heartbeat from time to time to notify the Fleetspeak client
//! that it did not get stuck.
//!
//! [Fleetspeak]: https://github.com/google/fleetspeak

mod connection;
mod error;

use std::fs::File;
use std::sync::Mutex;
use std::time::{Duration, Instant};

use lazy_static::lazy_static;
use log::{info, error};

pub use self::connection::Message;
pub use self::error::{ReadError, WriteError};

/// Sends a heartbeat signal to the Fleetspeak client.
///
/// All client services should heartbeat from time to time. Otherwise, from the
/// Fleetspeak perspective, the service is unresponsive and should be restarted.
///
/// The exact frequency of the required heartbeat is defined in the service
/// configuration file.
pub fn heartbeat() -> Result<(), WriteError> {
    locked(&CONNECTION.output, |buf| self::connection::heartbeat(buf))
}

/// Sends a heartbeat signal to the Fleetspeak client but no more frequently
/// than the specified `rate`.
///
/// Note that the specified `rate` should be at least the rate defined in the
/// Fleetspeak service configuration file. Because of potential slowdowns, some
/// margin of error should be left.
///
/// See documentation for the [`heartbeat`] function for more details.
///
/// [`heartbeat`]: crate::heartbeat
pub fn heartbeat_with_throttle(rate: Duration) -> Result<(), WriteError> {
    lazy_static! {
        static ref LAST_HEARTBEAT: Mutex<Option<Instant>> = Mutex::new(None);
    }

    let mut last_heartbeat = LAST_HEARTBEAT.lock()
        .expect("poisoned heartbeat mutex");

    match *last_heartbeat {
        Some(last_heartbeat) if last_heartbeat.elapsed() < rate => {
            // Do nothing if the last heartbeat happened more recently than the
            // specified heartbeat rate.
            return Ok(());
        }
        _ => (),
    }

    heartbeat()?;
    *last_heartbeat = Some(Instant::now());

    Ok(())
}

/// Sends a system message with startup information to the Fleetspeak client.
///
/// All clients are required to send this information on startup. If the client
/// does not receive this information quickly enough, the service will be
/// killed.
///
/// The `version` string should contain a self-reported version of the service.
/// This data is used primarily for statistics.
pub fn startup(version: &str) -> Result<(), WriteError> {
    locked(&CONNECTION.output, |buf| self::connection::startup(buf, version))
}

/// Sends the message to the Fleetspeak server.
///
/// The data is delivered to the server-side service as specified by the message
/// and optionally tagged with a type if specified. This optional message type
/// is irrelevant for Fleetspeak but might be useful for the service the message
/// is delivered to.
///
/// In case of any I/O failure or malformed message (e.g. due to encoding
/// problems), an error is reported.
///
/// # Examples
///
/// ```no_run
/// use fleetspeak::Message;
/// use protobuf::well_known_types::StringValue;
///
/// let mut message = StringValue::new();
/// message.set_value(String::from("Hello, World!"));
///
/// fleetspeak::send(Message {
///     service: String::from("example"),
///     kind: None,
///     data: message,
/// }).expect("failed to send the message");
/// ```
pub fn send<M>(message: Message<M>) -> Result<(), WriteError>
where
    M: protobuf::Message,
{
    locked(&CONNECTION.output, |buf| self::connection::send(buf, message))
}

/// Receives a message from the Fleetspeak server.
///
/// This function will block until there is a message to be read from the input.
/// Note that in particular it means your service will be unable to heartbeat
/// properly. If you are not expecting the message to arrive quickly, you should
/// use [`receive_with_heartbeat`] instead.
///
/// In case of any I/O failure or malformed message (e.g. due to parsing issues
/// or when some fields are not being present), an error is reported.
///
/// [`receive_with_heartbeat`]: crate::receive_with_heartbeat
///
/// # Examples
///
/// ```no_run
/// use protobuf::well_known_types::StringValue;
///
/// match fleetspeak::receive::<StringValue>() {
///     Ok(message) => println!("Hello, {}!", message.data.get_value()),
///     Err(error) => eprintln!("failed to receive the message: {}", error),
/// }
/// ```
pub fn receive<M>() -> Result<Message<M>, ReadError>
where
    M: protobuf::Message,
{
    locked(&CONNECTION.input, |buf| self::connection::receive(buf))
}

/// Receive a message from the Fleetspeak server, heartbeating in background.
///
/// Unlike [`receive`], `collect` will send heartbeat signals at the specified
/// `rate` while waiting for the message.
///
/// This function is useful in the main loop of your service when it is not
/// supposed to do anything until a request from the server arrives. If your
/// service is actually awaiting for a specific message to come, you should
/// use [`receive`] instead.
///
/// In case of any I/O failure or malformed message (e.g. due to parsing issues
/// or when some fields are not being present), an error is reported.
///
/// [`receive`]: crate::receive
///
/// # Examples
///
/// ```no_run
/// use std::time::Duration;
///
/// use protobuf::well_known_types::StringValue;
///
/// match fleetspeak::receive_with_heartbeat::<StringValue>(Duration::from_secs(1)) {
///     Ok(message) => println!("Hello, {}!", message.data.get_value()),
///     Err(error) => eprintln!("failed to collected the message: {}", error),
/// }
/// ```
pub fn receive_with_heartbeat<M>(rate: Duration) -> Result<Message<M>, ReadError>
where
    M: protobuf::Message + 'static,
{
    // TODO: Refactor this code once `!` stabilizes.
    let (sender, receiver) = std::sync::mpsc::channel();

    std::thread::spawn(move || {
        loop {
            use std::sync::mpsc::TryRecvError::*;

            // The heartbeat thread should stop itself when it receives a signal
            // to do so (or when the channel is closed). Otherwise, it should
            // keep heartbeating.
            match receiver.try_recv() {
                Ok(()) => return,
                Err(Empty) => (),
                Err(Disconnected) => return,
            }

            // Ignoring heartbeat errors is not great, but they can occur only
            // in very rare cases and any subsequent write operations are going
            // to fail soon anyway. Hence, we drop the error on the floor and
            // shut the thread down, hoping that the main thread will notice the
            // problem as soon as it tries to write something. In case the main
            // thread blocks indefinitely, Fleetspeak should figure out that the
            // service is unresponsive and kill it eventually.
            match heartbeat() {
                Ok(()) => (),
                Err(error) => {
                    error!(target: "fleetspeak", "heartbeat error: {}", error);
                    return;
                },
            }

            std::thread::sleep(rate);
        }
    });

    let message = receive()?;

    // Notify the heartbeat thread to shut down. We do not really care whether
    // the message was really delivered as this can fail only if the channel
    // disconnected (and this can happen only if the thread is already dead).
    let _ = sender.send(());

    Ok(message)
}

/// A connection to the Fleetspeak client.
///
/// The connection is realized through two files (specified by descriptors given
/// by the Fleetspeak client as environment variables): input and output. Each
/// of these files is guarded by a separate mutex to allow writing (e.g. for
/// sending heartbeat signals) when another thread might be busy with reading
/// messages.
struct Connection {
    input: Mutex<File>,
    output: Mutex<File>,
}

lazy_static! {
    static ref CONNECTION: Connection = {
        let mut input = open("FLEETSPEAK_COMMS_CHANNEL_INFD");
        let mut output = open("FLEETSPEAK_COMMS_CHANNEL_OUTFD");

        use self::connection::handshake;
        handshake(&mut input, &mut output).expect("handshake failure");

        info!(target: "fleetspeak", "handshake successful");

        Connection {
            input: Mutex::new(input),
            output: Mutex::new(output),
        }
    };
}

/// Executes the given function with a file extracted from the mutex.
///
/// It might happen that the mutex becomes poisoned and this call will panic in
/// result. This should not be a problem in practice, because mutex poisoning
/// is a result of one of the threads being aborted. In case of a such scenario,
/// it is likely the service needs to be restarted anyway.
fn locked<F, T, E>(mutex: &Mutex<File>, f: F) -> Result<T, E>
where
    F: FnOnce(&mut File) -> Result<T, E>
{
    let mut file = mutex.lock().expect("poisoned connection mutex");
    f(&mut file)
}

/// Opens a file object pointed by an environment variable.
///
/// Note that this function will panic if the environment variable `var` is not
/// a valid file descriptor (in which case the library cannot be initialized and
/// the service is unlikely to work anyway).
fn open(var: &str) -> File {
    let fd = std::env::var(var)
        .expect(&format!("invalid variable `{}`", var))
        .parse()
        .expect(&format!("failed to parse file descriptor"));

    #[cfg(target_family = "unix")]
    unsafe {
        std::os::unix::io::FromRawFd::from_raw_fd(fd)
    }

    #[cfg(target_family = "windows")]
    unsafe {
        // We use `identity` to specify the type for the `parse` call above and
        // then cast it to an appropriate Windows-specific pointer type.
        let handle = std::convert::identity::<usize>(fd) as _;
        std::os::windows::io::FromRawHandle::from_raw_handle(handle)
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

extern crate mio;

use std::cell::RefCell;
use private::{promise_node, Event, BoolEvent, PromiseAndFulfillerHub,
              EVENT_LOOP, with_current_event_loop, PromiseNode};

pub mod io;

mod private;

pub type Error = Box<::std::error::Error>;
pub type Result<T> = ::std::result::Result<T, Error>;

/// The basic primitive of asynchronous computation in GJ.
pub struct Promise<T> where T: 'static {
    node : Box<PromiseNode<T>>,
}

impl <T> Promise <T> where T: 'static {
    pub fn then<F, R>(self, func: F) -> Promise<R>
        where F: 'static + FnOnce(T) -> Result<Promise<R>>,
              R: 'static {
                  self.then_else(func, |e| { return Err(e); })
        }

    pub fn then_else<F, G, R>(self, func: F, error_handler: G) -> Promise<R>
        where F: 'static + FnOnce(T) -> Result<Promise<R>>,
              G: 'static + FnOnce(Error) -> Result<Promise<R>>,
              R: 'static {
            let intermediate = Box::new(promise_node::Transform::new(self.node, func, error_handler));
            Promise { node: Box::new(promise_node::Chain::new(intermediate)) }
        }

    pub fn map<F, R>(self, func: F) -> Promise<R>
        where F: 'static + FnOnce(T) -> Result<R>,
              R: 'static {
            self.map_else(func, |e| { return Err(e); })
        }

    pub fn map_else<F, G, R>(self, func: F, error_handler: G) -> Promise<R>
        where F: 'static + FnOnce(T) -> Result<R>,
              G: 'static + FnOnce(Error) -> Result<R>,
              R: 'static {
            Promise { node: Box::new(promise_node::Transform::new(self.node, func, error_handler)) }
        }

    pub fn wait(mut self, _wait_scope: &WaitScope) -> Result<T> {
        with_current_event_loop(move |event_loop| {
            let fired = ::std::rc::Rc::new(::std::cell::Cell::new(false));
            let done_event = BoolEvent::new(fired.clone());
            self.node.on_ready(Box::new(done_event));

            //event_loop.running = true;

            while !fired.get() {
                if !event_loop.turn() {
                    // No events in the queue.
                    event_loop.event_port.borrow_mut().wait();
                }
            }

            self.node.get()
        })
    }

    pub fn fulfilled(value: T) -> Promise<T> {
        return Promise { node: Box::new(promise_node::Immediate::new(Ok(value))) };
    }

    pub fn rejected(error: Error) -> Promise<T> {
        return Promise { node: Box::new(promise_node::Immediate::new(Err(error))) };
    }
}

pub struct WaitScope(());

/// Interface between an `EventLoop` and events originating from outside of the loop's thread.
pub trait EventPort {
    /// Waits for an external event to arrive, sleeping if necessary.
    /// Returns true if wake() has been called from another thread.
    fn wait(&mut self) -> bool;

    /// Checks whether any external events have arrived, but does not sleep.
    /// Returns true if wake() has been called from another thread.
    fn poll(&mut self) -> bool;

    /// Called to notify the `EventPort` when the `EventLoop` has work to do; specifically when it
    /// transitions from empty -> runnable or runnable -> empty. This is typically useful when
    /// intergrating with an external event loop; if the loop is currently runnable then you should
    /// arrange to call run() on it soon. The default implementation does nothing.
    fn set_runnable(&mut self, _runnable: bool) { }

    fn wake(&mut self) { unimplemented!(); }
}

/// A queue of events being executed in a loop.
pub struct EventLoop {
//    daemons: TaskSetImpl,
    event_port: RefCell<io::MioEventPort>,
    running: bool,
    _last_runnable_state: bool,
    events: RefCell<::std::collections::VecDeque<Box<Event>>>,
    depth_first_events: RefCell<::std::collections::VecDeque<Box<Event>>>,
}

impl EventLoop {
    pub fn init<F>(f: F) where F: FnOnce(&WaitScope) {
        EVENT_LOOP.with(|maybe_event_loop| {
            let event_loop = EventLoop {
                event_port: RefCell::new(io::MioEventPort::new().unwrap()),
                running: false,
                _last_runnable_state: false,
                events: RefCell::new(::std::collections::VecDeque::new()),
                depth_first_events: RefCell::new(::std::collections::VecDeque::new()) };

            assert!(maybe_event_loop.borrow().is_none());
            *maybe_event_loop.borrow_mut() = Some(event_loop);
        });
        let wait_scope = WaitScope(());
        f(&wait_scope);
    }

    fn arm_depth_first(&self, event: Box<Event>) {
        self.depth_first_events.borrow_mut().push_front(event);
    }

    fn arm_breadth_first(&self, event: Box<Event>) {
        self.events.borrow_mut().push_back(event);
    }

    /// Run the event loop for `max_turn_count` turns or until there is nothing left to be done,
    /// whichever comes first. This never calls the `EventPort`'s `sleep()` or `poll()`. It will
    /// call the `EventPort`'s `set_runnable(false)` if the queue becomes empty.
    pub fn run(&mut self, max_turn_count : u32) {
        self.running = true;

        for _ in 0..max_turn_count {
            if !self.turn() {
                break;
            }
        }
    }

    fn turn(&self) -> bool {

        while !self.depth_first_events.borrow().is_empty() {
            let event = self.depth_first_events.borrow_mut().pop_front().unwrap();
            self.events.borrow_mut().push_front(event);
        }

        assert!(self.depth_first_events.borrow().is_empty());

        let mut event = match self.events.borrow_mut().pop_front() {
            None => return false,
            Some(event) => { event }
        };
        event.fire();

        return true;
    }
}

/// A callback which can be used to fulfill a promise.
pub trait PromiseFulfiller<T> where T: 'static {
    fn fulfill(self: Box<Self>, value: T);
    fn reject(self: Box<Self>, error: Error);
}

pub fn new_promise_and_fulfiller<T>() -> (Promise<T>, Box<PromiseFulfiller<T>>) where T: 'static {
    let result = ::std::rc::Rc::new(::std::cell::RefCell::new(PromiseAndFulfillerHub::new()));
    let result_promise : Promise<T> = Promise { node: Box::new(result.clone())};
    (result_promise, Box::new(result))
}
<commit_msg>Make sure that WaitScope does not implement Sync.<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

extern crate mio;

use std::cell::RefCell;
use private::{promise_node, Event, BoolEvent, PromiseAndFulfillerHub,
              EVENT_LOOP, with_current_event_loop, PromiseNode};

pub mod io;

mod private;

pub type Error = Box<::std::error::Error>;
pub type Result<T> = ::std::result::Result<T, Error>;

/// The basic primitive of asynchronous computation in GJ.
pub struct Promise<T> where T: 'static {
    node : Box<PromiseNode<T>>,
}

impl <T> Promise <T> where T: 'static {
    pub fn then<F, R>(self, func: F) -> Promise<R>
        where F: 'static + FnOnce(T) -> Result<Promise<R>>,
              R: 'static {
                  self.then_else(func, |e| { return Err(e); })
        }

    pub fn then_else<F, G, R>(self, func: F, error_handler: G) -> Promise<R>
        where F: 'static + FnOnce(T) -> Result<Promise<R>>,
              G: 'static + FnOnce(Error) -> Result<Promise<R>>,
              R: 'static {
            let intermediate = Box::new(promise_node::Transform::new(self.node, func, error_handler));
            Promise { node: Box::new(promise_node::Chain::new(intermediate)) }
        }

    pub fn map<F, R>(self, func: F) -> Promise<R>
        where F: 'static + FnOnce(T) -> Result<R>,
              R: 'static {
            self.map_else(func, |e| { return Err(e); })
        }

    pub fn map_else<F, G, R>(self, func: F, error_handler: G) -> Promise<R>
        where F: 'static + FnOnce(T) -> Result<R>,
              G: 'static + FnOnce(Error) -> Result<R>,
              R: 'static {
            Promise { node: Box::new(promise_node::Transform::new(self.node, func, error_handler)) }
        }

    pub fn wait(mut self, _wait_scope: &WaitScope) -> Result<T> {
        with_current_event_loop(move |event_loop| {
            let fired = ::std::rc::Rc::new(::std::cell::Cell::new(false));
            let done_event = BoolEvent::new(fired.clone());
            self.node.on_ready(Box::new(done_event));

            //event_loop.running = true;

            while !fired.get() {
                if !event_loop.turn() {
                    // No events in the queue.
                    event_loop.event_port.borrow_mut().wait();
                }
            }

            self.node.get()
        })
    }

    pub fn fulfilled(value: T) -> Promise<T> {
        return Promise { node: Box::new(promise_node::Immediate::new(Ok(value))) };
    }

    pub fn rejected(error: Error) -> Promise<T> {
        return Promise { node: Box::new(promise_node::Immediate::new(Err(error))) };
    }
}

pub struct WaitScope(::std::marker::PhantomData<*mut u8>); // impl !Sync for WaitScope {}

/// Interface between an `EventLoop` and events originating from outside of the loop's thread.
pub trait EventPort {
    /// Waits for an external event to arrive, sleeping if necessary.
    /// Returns true if wake() has been called from another thread.
    fn wait(&mut self) -> bool;

    /// Checks whether any external events have arrived, but does not sleep.
    /// Returns true if wake() has been called from another thread.
    fn poll(&mut self) -> bool;

    /// Called to notify the `EventPort` when the `EventLoop` has work to do; specifically when it
    /// transitions from empty -> runnable or runnable -> empty. This is typically useful when
    /// intergrating with an external event loop; if the loop is currently runnable then you should
    /// arrange to call run() on it soon. The default implementation does nothing.
    fn set_runnable(&mut self, _runnable: bool) { }

    fn wake(&mut self) { unimplemented!(); }
}

/// A queue of events being executed in a loop.
pub struct EventLoop {
//    daemons: TaskSetImpl,
    event_port: RefCell<io::MioEventPort>,
    running: bool,
    _last_runnable_state: bool,
    events: RefCell<::std::collections::VecDeque<Box<Event>>>,
    depth_first_events: RefCell<::std::collections::VecDeque<Box<Event>>>,
}

impl EventLoop {
    pub fn init<F>(f: F) where F: FnOnce(&WaitScope) {
        EVENT_LOOP.with(|maybe_event_loop| {
            let event_loop = EventLoop {
                event_port: RefCell::new(io::MioEventPort::new().unwrap()),
                running: false,
                _last_runnable_state: false,
                events: RefCell::new(::std::collections::VecDeque::new()),
                depth_first_events: RefCell::new(::std::collections::VecDeque::new()) };

            assert!(maybe_event_loop.borrow().is_none());
            *maybe_event_loop.borrow_mut() = Some(event_loop);
        });
        let wait_scope = WaitScope(::std::marker::PhantomData);
        f(&wait_scope);
    }

    fn arm_depth_first(&self, event: Box<Event>) {
        self.depth_first_events.borrow_mut().push_front(event);
    }

    fn arm_breadth_first(&self, event: Box<Event>) {
        self.events.borrow_mut().push_back(event);
    }

    /// Run the event loop for `max_turn_count` turns or until there is nothing left to be done,
    /// whichever comes first. This never calls the `EventPort`'s `sleep()` or `poll()`. It will
    /// call the `EventPort`'s `set_runnable(false)` if the queue becomes empty.
    pub fn run(&mut self, max_turn_count : u32) {
        self.running = true;

        for _ in 0..max_turn_count {
            if !self.turn() {
                break;
            }
        }
    }

    fn turn(&self) -> bool {

        while !self.depth_first_events.borrow().is_empty() {
            let event = self.depth_first_events.borrow_mut().pop_front().unwrap();
            self.events.borrow_mut().push_front(event);
        }

        assert!(self.depth_first_events.borrow().is_empty());

        let mut event = match self.events.borrow_mut().pop_front() {
            None => return false,
            Some(event) => { event }
        };
        event.fire();

        return true;
    }
}

/// A callback which can be used to fulfill a promise.
pub trait PromiseFulfiller<T> where T: 'static {
    fn fulfill(self: Box<Self>, value: T);
    fn reject(self: Box<Self>, error: Error);
}

pub fn new_promise_and_fulfiller<T>() -> (Promise<T>, Box<PromiseFulfiller<T>>) where T: 'static {
    let result = ::std::rc::Rc::new(::std::cell::RefCell::new(PromiseAndFulfillerHub::new()));
    let result_promise : Promise<T> = Promise { node: Box::new(result.clone())};
    (result_promise, Box::new(result))
}
<|endoftext|>