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

// http://json.schemastore.org/swagger-2.0

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum Scheme {
    Http,
    Https,
    Ws,
    Wss,
}

impl Default for Scheme {
    fn default() -> Self {
        Scheme::Http
    }
}

/// top level document
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
pub struct Spec {
    /// The Swagger version of this document.
    pub swagger: String,
    pub info: Info,
    /// The host (name or ip) of the API. Example: 'swagger.io'
    /// ^[^{}/ :\\\\]+(?::\\d+)?$
    #[serde(skip_serializing_if = "Option::is_none")]
    pub host: Option<String>,
    /// The base path to the API. Example: '/api'.
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(rename = "basePath")]
    pub base_path: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub schemes: Option<Vec<Scheme>>,
    /// A list of MIME types accepted by the API.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub consumes: Option<Vec<String>>,
    /// A list of MIME types the API can produce.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub produces: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tags: Option<Vec<Tag>>,
    /// Relative paths to the individual endpoints. They must be relative
    /// to the 'basePath'.
    pub paths: BTreeMap<String, Operations>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub definitions: Option<BTreeMap<String, Schema>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub parameters: Option<BTreeMap<String, Parameter>>,
    /// mappings to http response codes or "default"
    #[serde(skip_serializing_if = "Option::is_none")]
    pub responses: Option<BTreeMap<String, Response>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub security_definitions: Option<BTreeMap<String, Security>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub security: Option<Vec<BTreeMap<String, Vec<String>>>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub external_docs: Option<Vec<ExternalDoc>>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
#[serde(rename_all = "lowercase")]
pub struct Tag {
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub external_docs: Option<Vec<ExternalDoc>>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct ExternalDoc {
    pub url: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
}

/// General information about the API.
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
#[serde(rename_all = "lowercase")]
pub struct Info {
    /// A unique and precise title of the API.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub title: Option<String>,
    /// A semantic version number of the API.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub terms_of_service: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub contact: Option<Contact>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub license: Option<License>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub version: Option<String>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Contact {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    // TODO: Make sure the url is a valid URL
    #[serde(skip_serializing_if = "Option::is_none")]
    pub url: Option<String>,
    // TODO: Make sure the email is a valid email
    #[serde(skip_serializing_if = "Option::is_none")]
    pub email: Option<String>,
}

/// todo x-* properties
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct License {
    /// The name of the license type. It's encouraged to use an OSI
    /// compatible license.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    /// The URL pointing to the license.
    // TODO: Make sure the url is a valid URL
    #[serde(skip_serializing_if = "Option::is_none")]
    pub url: Option<String>,
}

/// todo support x-* properties
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct PathItem {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub get: Option<Operation>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub post: Option<Operation>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub put: Option<Operation>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub patch: Option<Operation>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub delete: Option<Operation>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub options: Option<Operation>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub head: Option<Operation>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub parameters: Option<Vec<ParameterOrRef>>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
#[serde(rename_all = "lowercase")]
pub struct Operation {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub summary: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub consumes: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub produces: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub schemes: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tags: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub operation_id: Option<String>,
    pub responses: BTreeMap<String, Response>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub parameters: Option<Vec<ParameterOrRef>>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
pub struct Parameter {
    pub name: String,
    #[serde(rename = "in")]
    pub location: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub required: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub schema: Option<Schema>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub unique_items: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(rename = "type")]
    pub param_type: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub format: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Response {
    pub description: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub schema: Option<Schema>,
}

// todo: support x-* fields
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[serde(untagged)]
pub enum ParameterOrRef {
    /// both bodyParameter and nonBodyParameter in one for now
    #[derive(Default)]
    Parameter {
        /// The name of the parameter.
        name: String,
        /// values depend on parameter type
        /// may be `header`, `query`, 'path`, `formData`
        #[serde(rename = "in")]
        location: String,
        #[serde(skip_serializing_if = "Option::is_none")]
        required: Option<bool>,
        #[serde(skip_serializing_if = "Option::is_none")]
        schema: Option<Schema>,
        #[serde(skip_serializing_if = "Option::is_none")]
        #[serde(rename = "uniqueItems")]
        unique_items: Option<bool>,
        /// string, number, boolean, integer, array, file ( only for formData )
        #[serde(skip_serializing_if = "Option::is_none")]
        #[serde(rename = "type")]
        param_type: Option<String>,
        #[serde(skip_serializing_if = "Option::is_none")]
        format: Option<String>,
        /// A brief description of the parameter. This could contain examples
        /// of use.  GitHub Flavored Markdown is allowed.
        #[serde(skip_serializing_if = "Option::is_none")]
        description: Option<String>,
        // collectionFormat: ???
        // default: ???
        // maximum ?
        // exclusiveMaximum ??
        // minimum ??
        // exclusiveMinimum ??
        // maxLength ??
        // minLength ??
        // pattern ??
        // maxItems ??
        // minItems ??
        // enum ??
        // multipleOf ??
        // allowEmptyValue ( for query / body params )
    },
    Ref {
        #[serde(rename = "$ref")]
        ref_path: String,
    },
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[serde(tag = "type")]
pub enum Security {
    #[serde(rename = "apiKey")]
    ApiKey {
        name: String,
        #[serde(rename = "in")]
        location: String,
    },
    #[serde(rename = "oauth2")]
    Oauth2 {
        flow: String,
        #[serde(rename = "authorizationUrl")]
        authorization_url: String,
        #[serde(rename = "tokenUrl")]
        #[serde(skip_serializing_if = "Option::is_none")]
        token_url: Option<String>,
        scopes: BTreeMap<String, String>,
    },
    #[serde(rename = "basic")]
    Basic,
}

/// A [JSON schema](http://json-schema.org/) definition describing
/// the shape and properties of an object.
///
/// This may also contain a `$ref` to another definition
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Schema {
    #[serde(skip_serializing_if = "Option::is_none")]
    /// [JSON reference](https://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03)
    /// path to another defintion
    #[serde(rename = "$ref")]
    pub ref_path: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(rename = "type")]
    pub schema_type: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub format: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(rename = "enum")]
    pub enum_values: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub required: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub items: Option<Box<Schema>>,
    // implies object
    #[serde(skip_serializing_if = "Option::is_none")]
    pub properties: Option<BTreeMap<String, Schema>>,
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde_json;
    use serde_yaml;
    use std::collections::BTreeMap;

    #[test]
    fn security_api_deserializes() {
        let json = r#"{"type":"apiKey", "name":"foo", "in": "query"}"#;
        assert_eq!(
            serde_yaml::from_str::<Security>(&json).unwrap(),
            Security::ApiKey {
                name: "foo".into(),
                location: "query".into(),
            }
        );
    }

    #[test]
    fn security_api_serializes() {
        let json = r#"{"type":"apiKey","name":"foo","in":"query"}"#;
        assert_eq!(
            serde_json::to_string(&Security::ApiKey {
                name: "foo".into(),
                location: "query".into(),
            }).unwrap(),
            json
        );
    }

    #[test]
    fn security_basic_deserializes() {
        let json = r#"{"type":"basic"}"#;
        assert_eq!(
            serde_yaml::from_str::<Security>(&json).unwrap(),
            Security::Basic
        );
    }

    #[test]
    fn security_basic_serializes() {
        let json = r#"{"type":"basic"}"#;
        assert_eq!(json, serde_json::to_string(&Security::Basic).unwrap());
    }

    #[test]
    fn security_oauth_deserializes() {
        let json = r#"{"type":"oauth2","flow":"implicit","authorizationUrl":"foo/bar","scopes":{"foo":"bar"}}"#;
        let mut scopes = BTreeMap::new();
        scopes.insert("foo".into(), "bar".into());
        assert_eq!(
            serde_yaml::from_str::<Security>(&json).unwrap(),
            Security::Oauth2 {
                flow: "implicit".into(),
                authorization_url: "foo/bar".into(),
                token_url: None,
                scopes: scopes,
            }
        );
    }

    #[test]
    fn security_oauth_serializes() {
        let json = r#"{"type":"oauth2","flow":"implicit","authorizationUrl":"foo/bar","scopes":{"foo":"bar"}}"#;
        let mut scopes = BTreeMap::new();
        scopes.insert("foo".into(), "bar".into());
        assert_eq!(
            json,
            serde_json::to_string(&Security::Oauth2 {
                flow: "implicit".into(),
                authorization_url: "foo/bar".into(),
                token_url: None,
                scopes: scopes,
            }).unwrap()
        );
    }

    #[test]
    fn parameter_or_ref_deserializes_ref() {
        let json = r#"{"$ref":"foo/bar"}"#;
        assert_eq!(
            serde_yaml::from_str::<ParameterOrRef>(&json).unwrap(),
            ParameterOrRef::Ref { ref_path: "foo/bar".into() }
        );
    }

    #[test]
    fn parameter_or_ref_serializes_pref() {
        let json = r#"{"$ref":"foo/bar"}"#;
        assert_eq!(
            json,
            serde_json::to_string(
                &ParameterOrRef::Ref { ref_path: "foo/bar".into() },
            ).unwrap()
        );
    }
}
<commit_msg>Fix compilation issue from a33e084 (`Operations` -> `PathItem`)<commit_after>use std::collections::BTreeMap;

// http://json.schemastore.org/swagger-2.0

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum Scheme {
    Http,
    Https,
    Ws,
    Wss,
}

impl Default for Scheme {
    fn default() -> Self {
        Scheme::Http
    }
}

/// top level document
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
pub struct Spec {
    /// The Swagger version of this document.
    pub swagger: String,
    pub info: Info,
    /// The host (name or ip) of the API. Example: 'swagger.io'
    /// ^[^{}/ :\\\\]+(?::\\d+)?$
    #[serde(skip_serializing_if = "Option::is_none")]
    pub host: Option<String>,
    /// The base path to the API. Example: '/api'.
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(rename = "basePath")]
    pub base_path: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub schemes: Option<Vec<Scheme>>,
    /// A list of MIME types accepted by the API.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub consumes: Option<Vec<String>>,
    /// A list of MIME types the API can produce.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub produces: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tags: Option<Vec<Tag>>,
    /// Relative paths to the individual endpoints. They must be relative
    /// to the 'basePath'.
    pub paths: BTreeMap<String, PathItem>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub definitions: Option<BTreeMap<String, Schema>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub parameters: Option<BTreeMap<String, Parameter>>,
    /// mappings to http response codes or "default"
    #[serde(skip_serializing_if = "Option::is_none")]
    pub responses: Option<BTreeMap<String, Response>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub security_definitions: Option<BTreeMap<String, Security>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub security: Option<Vec<BTreeMap<String, Vec<String>>>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub external_docs: Option<Vec<ExternalDoc>>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
#[serde(rename_all = "lowercase")]
pub struct Tag {
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub external_docs: Option<Vec<ExternalDoc>>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct ExternalDoc {
    pub url: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
}

/// General information about the API.
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
#[serde(rename_all = "lowercase")]
pub struct Info {
    /// A unique and precise title of the API.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub title: Option<String>,
    /// A semantic version number of the API.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub terms_of_service: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub contact: Option<Contact>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub license: Option<License>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub version: Option<String>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Contact {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    // TODO: Make sure the url is a valid URL
    #[serde(skip_serializing_if = "Option::is_none")]
    pub url: Option<String>,
    // TODO: Make sure the email is a valid email
    #[serde(skip_serializing_if = "Option::is_none")]
    pub email: Option<String>,
}

/// todo x-* properties
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct License {
    /// The name of the license type. It's encouraged to use an OSI
    /// compatible license.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    /// The URL pointing to the license.
    // TODO: Make sure the url is a valid URL
    #[serde(skip_serializing_if = "Option::is_none")]
    pub url: Option<String>,
}

/// todo support x-* properties
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct PathItem {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub get: Option<Operation>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub post: Option<Operation>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub put: Option<Operation>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub patch: Option<Operation>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub delete: Option<Operation>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub options: Option<Operation>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub head: Option<Operation>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub parameters: Option<Vec<ParameterOrRef>>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
#[serde(rename_all = "lowercase")]
pub struct Operation {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub summary: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub consumes: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub produces: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub schemes: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tags: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub operation_id: Option<String>,
    pub responses: BTreeMap<String, Response>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub parameters: Option<Vec<ParameterOrRef>>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
pub struct Parameter {
    pub name: String,
    #[serde(rename = "in")]
    pub location: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub required: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub schema: Option<Schema>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub unique_items: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(rename = "type")]
    pub param_type: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub format: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Response {
    pub description: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub schema: Option<Schema>,
}

// todo: support x-* fields
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[serde(untagged)]
pub enum ParameterOrRef {
    /// both bodyParameter and nonBodyParameter in one for now
    #[derive(Default)]
    Parameter {
        /// The name of the parameter.
        name: String,
        /// values depend on parameter type
        /// may be `header`, `query`, 'path`, `formData`
        #[serde(rename = "in")]
        location: String,
        #[serde(skip_serializing_if = "Option::is_none")]
        required: Option<bool>,
        #[serde(skip_serializing_if = "Option::is_none")]
        schema: Option<Schema>,
        #[serde(skip_serializing_if = "Option::is_none")]
        #[serde(rename = "uniqueItems")]
        unique_items: Option<bool>,
        /// string, number, boolean, integer, array, file ( only for formData )
        #[serde(skip_serializing_if = "Option::is_none")]
        #[serde(rename = "type")]
        param_type: Option<String>,
        #[serde(skip_serializing_if = "Option::is_none")]
        format: Option<String>,
        /// A brief description of the parameter. This could contain examples
        /// of use.  GitHub Flavored Markdown is allowed.
        #[serde(skip_serializing_if = "Option::is_none")]
        description: Option<String>,
        // collectionFormat: ???
        // default: ???
        // maximum ?
        // exclusiveMaximum ??
        // minimum ??
        // exclusiveMinimum ??
        // maxLength ??
        // minLength ??
        // pattern ??
        // maxItems ??
        // minItems ??
        // enum ??
        // multipleOf ??
        // allowEmptyValue ( for query / body params )
    },
    Ref {
        #[serde(rename = "$ref")]
        ref_path: String,
    },
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[serde(tag = "type")]
pub enum Security {
    #[serde(rename = "apiKey")]
    ApiKey {
        name: String,
        #[serde(rename = "in")]
        location: String,
    },
    #[serde(rename = "oauth2")]
    Oauth2 {
        flow: String,
        #[serde(rename = "authorizationUrl")]
        authorization_url: String,
        #[serde(rename = "tokenUrl")]
        #[serde(skip_serializing_if = "Option::is_none")]
        token_url: Option<String>,
        scopes: BTreeMap<String, String>,
    },
    #[serde(rename = "basic")]
    Basic,
}

/// A [JSON schema](http://json-schema.org/) definition describing
/// the shape and properties of an object.
///
/// This may also contain a `$ref` to another definition
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Schema {
    #[serde(skip_serializing_if = "Option::is_none")]
    /// [JSON reference](https://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03)
    /// path to another defintion
    #[serde(rename = "$ref")]
    pub ref_path: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(rename = "type")]
    pub schema_type: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub format: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(rename = "enum")]
    pub enum_values: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub required: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub items: Option<Box<Schema>>,
    // implies object
    #[serde(skip_serializing_if = "Option::is_none")]
    pub properties: Option<BTreeMap<String, Schema>>,
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde_json;
    use serde_yaml;
    use std::collections::BTreeMap;

    #[test]
    fn security_api_deserializes() {
        let json = r#"{"type":"apiKey", "name":"foo", "in": "query"}"#;
        assert_eq!(
            serde_yaml::from_str::<Security>(&json).unwrap(),
            Security::ApiKey {
                name: "foo".into(),
                location: "query".into(),
            }
        );
    }

    #[test]
    fn security_api_serializes() {
        let json = r#"{"type":"apiKey","name":"foo","in":"query"}"#;
        assert_eq!(
            serde_json::to_string(&Security::ApiKey {
                name: "foo".into(),
                location: "query".into(),
            }).unwrap(),
            json
        );
    }

    #[test]
    fn security_basic_deserializes() {
        let json = r#"{"type":"basic"}"#;
        assert_eq!(
            serde_yaml::from_str::<Security>(&json).unwrap(),
            Security::Basic
        );
    }

    #[test]
    fn security_basic_serializes() {
        let json = r#"{"type":"basic"}"#;
        assert_eq!(json, serde_json::to_string(&Security::Basic).unwrap());
    }

    #[test]
    fn security_oauth_deserializes() {
        let json = r#"{"type":"oauth2","flow":"implicit","authorizationUrl":"foo/bar","scopes":{"foo":"bar"}}"#;
        let mut scopes = BTreeMap::new();
        scopes.insert("foo".into(), "bar".into());
        assert_eq!(
            serde_yaml::from_str::<Security>(&json).unwrap(),
            Security::Oauth2 {
                flow: "implicit".into(),
                authorization_url: "foo/bar".into(),
                token_url: None,
                scopes: scopes,
            }
        );
    }

    #[test]
    fn security_oauth_serializes() {
        let json = r#"{"type":"oauth2","flow":"implicit","authorizationUrl":"foo/bar","scopes":{"foo":"bar"}}"#;
        let mut scopes = BTreeMap::new();
        scopes.insert("foo".into(), "bar".into());
        assert_eq!(
            json,
            serde_json::to_string(&Security::Oauth2 {
                flow: "implicit".into(),
                authorization_url: "foo/bar".into(),
                token_url: None,
                scopes: scopes,
            }).unwrap()
        );
    }

    #[test]
    fn parameter_or_ref_deserializes_ref() {
        let json = r#"{"$ref":"foo/bar"}"#;
        assert_eq!(
            serde_yaml::from_str::<ParameterOrRef>(&json).unwrap(),
            ParameterOrRef::Ref { ref_path: "foo/bar".into() }
        );
    }

    #[test]
    fn parameter_or_ref_serializes_pref() {
        let json = r#"{"$ref":"foo/bar"}"#;
        assert_eq!(
            json,
            serde_json::to_string(
                &ParameterOrRef::Ref { ref_path: "foo/bar".into() },
            ).unwrap()
        );
    }
}
<|endoftext|>


<commit_before>//! Continuous time signals

use std::sync::{ Arc, Mutex };
use std::ops::Deref;
use source::{ Source, with_weak, CallbackError };
use stream::{ self, BoxClone, Stream };
use transaction::{ commit, register_callback };
use pending::Pending;

enum SignalFn {
    Const(A),
    Func(Box<Fn() -> A + Send + Sync + 'static>),
}

impl SignalFn {
    pub fn from_fn<F: Fn() -> A + Send + Sync + 'static>(f: F) -> SignalFn {
        SignalFn::Func(Box::new(f))
    }
}

impl SignalFn {
    pub fn call(&self) -> A {
        match *self {
            SignalFn::Const(ref a) => a.clone(),
            SignalFn::Func(ref f) => f(),
        }
    }
}

/// Helper function to register callback handlers related to signal construction.
fn reg_signal(parent_source: &mut Source, signal: &Signal, handler: F)
    where A: Send + Sync + 'static,
          B: Send + Sync + 'static,
          F: Fn(A) -> SignalFn + Send + Sync + 'static,
{
    let weak_source = signal.source.downgrade();
    let weak_current = signal.current.downgrade();
    parent_source.register(move |a|
        weak_current.upgrade().map(|cur| register_callback(
            move || { let _ = cur.lock().map(|mut cur| cur.update()); }))
            .ok_or(CallbackError::Disappeared)
        .and(with_weak(&weak_current, |cur| cur.queue(handler(a))))
        .and(with_weak(&weak_source, |src| src.send(())))
    );
}

/// A continuous signal.
pub struct Signal {
    current: Arc<Mutex<Pending<SignalFn>>>,
    source: Arc<Mutex<Source<()>>>,
    #[allow(dead_code)]
    keep_alive: Box<BoxClone>,
}

impl Clone for Signal {
    fn clone(&self) -> Signal {
        Signal {
            current: self.current.clone(),
            source: self.source.clone(),
            keep_alive: self.keep_alive.box_clone(),
        }
    }
}

impl Signal {
    /// Create a constant signal.
    pub fn new(a: A) -> Signal {
        Signal {
            current: Arc::new(Mutex::new(Pending::new(SignalFn::Const(a)))),
            source: Arc::new(Mutex::new(Source::new())),
            keep_alive: Box::new(()),
        }
    }

    /// Sample the current value of a signal.
    pub fn sample(&self) -> A {
        commit((), |_| self.current.lock().unwrap().call())
    }
}

impl Signal {
    /// stub
    pub fn snapshot(&self, stream: &Stream) -> Stream<(A, B)>
        where B: Clone + Send + Sync + 'static,
    {
        stream::snapshot(self, stream)
    }
}

impl Signal<Signal> {
    /// stub
    pub fn switch(&self) -> Signal {
        fn make_callback(parent: &Signal<Signal>) -> SignalFn
            where A: Send + Clone + Sync + 'static,
        {
            // TODO: use information on inner value
            let current_signal = parent.current.clone();
            SignalFn::from_fn(move ||
                current_signal.lock().unwrap().call().sample()
            )
        }
        commit((), |_| {
            let signal = Signal {
                current: Arc::new(Mutex::new(Pending::new(make_callback(self)))),
                source: Arc::new(Mutex::new(Source::new())),
                keep_alive: Box::new(()),
            };
            let parent = self.clone();
            reg_signal(&mut self.source.lock().unwrap(), &signal,
                move |_| make_callback(&parent));
            signal
        })
    }
}

/// stub
pub struct SignalCycle {
    signal: Signal,
}

impl SignalCycle {
    /// stub
    pub fn new() -> SignalCycle {
        SignalCycle { signal: Signal {
            current: Arc::new(Mutex::new(Pending::new(SignalFn::from_fn(
                || panic!("sampled on forward-declaration of signal")
            )))),
            source: Arc::new(Mutex::new(Source::new())),
            keep_alive: Box::new(()),
        } }
    }

    /// stub
    pub fn define(self, definition: Signal) -> Signal {
        /// Generate a callback from the signal definition's current value.
        fn make_callback(current_def: &Arc<Mutex<Pending<SignalFn>>>) -> SignalFn
            where A: Send + Sync + Clone + 'static
        {
            match *current_def.lock().unwrap().future() {
                SignalFn::Const(ref a) => SignalFn::Const(a.clone()),
                SignalFn::Func(_) => SignalFn::from_fn({
                    let sig = current_def.downgrade();
                    move || {
                        let strong = sig.upgrade().unwrap();
                        let ret = strong.lock().unwrap().call();
                        ret
                    }
                }),
            }
        }
        commit((), move |_| {
            *self.signal.current.lock().unwrap() = Pending::new(make_callback(&definition.current));
            let weak_parent = definition.current.downgrade();
            reg_signal(&mut definition.source.lock().unwrap(), &self.signal,
                move |_| make_callback(&weak_parent.upgrade().unwrap()));
            Signal { keep_alive: Box::new(definition), ..self.signal }
        })
    }
}

impl Deref for SignalCycle {
    type Target = Signal;
    fn deref(&self) -> &Signal { &self.signal }
}

/// Hold a stream as a signal.
pub fn hold(initial: A, stream: &Stream) -> Signal
    where A: Send + Sync + 'static,
{
    commit((), |_| {
        let signal = Signal {
            source: Arc::new(Mutex::new(Source::new())),
            current: Arc::new(Mutex::new(Pending::new(SignalFn::Const(initial)))),
            keep_alive: Box::new(stream.clone()),
        };
        reg_signal(&mut stream::source(&stream).lock().unwrap(), &signal, SignalFn::Const);
        signal
    })
}

/// Lift a 0-ary function to a signal.
pub fn lift0(f: F) -> Signal
    where F: Fn() -> A + Send + Sync + 'static
{
    Signal {
        current: Arc::new(Mutex::new(Pending::new(SignalFn::from_fn(f)))),
        source: Arc::new(Mutex::new(Source::new())),
        keep_alive: Box::new(()),
    }
}

/// Unary lift
pub fn lift1(f: F, sa: &Signal) -> Signal
    where A: Send + Sync + Clone + 'static,
          B: Send + Sync + Clone + 'static,
          F: Fn(A) -> B + Send + Sync + 'static,
{
    fn make_callback(f: &Arc<F>, parent: &Signal) -> SignalFn
        where A: Send + Sync + Clone + 'static,
              B: Send + Sync + Clone + 'static,
              F: Fn(A) -> B + Send + Sync + 'static,
    {
        let pclone = parent.clone();
        let f = f.clone();
        match *parent.current.lock().unwrap().future() {
            SignalFn::Const(ref a) => SignalFn::Const(f(a.clone())),
            SignalFn::Func(_) => SignalFn::from_fn(move || f(pclone.sample())),
        }
    }

    let f = Arc::new(f);
    let source = Arc::new(Mutex::new(Source::new()));
    let current = Arc::new(Mutex::new(Pending::new(make_callback(&f, &sa))));
    let weak_source = source.downgrade();
    let weak_current = current.downgrade();
    let sa_2 = sa.clone();
    sa.source.lock().unwrap().register(move |()| {
        weak_current.upgrade().map(|cur| register_callback(
            move || { let _ = cur.lock().map(|mut cur| cur.update()); }))
            .ok_or(CallbackError::Disappeared)
        .and(with_weak(&weak_current, |cur| cur.queue(make_callback(&f, &sa_2))))
        .and(with_weak(&weak_source, |src| src.send(())))
    });
    Signal {
        source: source,
        current: current,
        keep_alive: Box::new(()),
    }
}

#[cfg(test)]
mod test {
    use ::stream::Sink;
    use ::signal::{ self, Signal, SignalCycle };

    #[test]
    fn clone() {
        let b = Signal::new(3);
        assert_eq!(b.clone().sample(), 3);
    }

    #[test]
    fn lift0() {
        let signal = signal::lift0(|| 3);
        assert_eq!(signal.sample(), 3);
    }

    #[test]
    fn lift1() {
        let sig2 = signal::lift1(|n| n + 2, &Signal::new(3));
        assert_eq!(sig2.sample(), 5);
    }

    #[test]
    fn hold() {
        let sink = Sink::new();
        let signal = sink.stream().hold(3);
        assert_eq!(signal.sample(), 3);
        sink.send(4);
        assert_eq!(signal.sample(), 4);
    }

    #[test]
    fn hold_implicit_stream() {
        let sink = Sink::new();
        let signal = signal::hold(0, &sink.stream().map(|n| 2 * n));
        assert_eq!(signal.sample(), 0);
        sink.send(4);
        assert_eq!(signal.sample(), 8);
    }

    #[test]
    fn snapshot() {
        let sink1: Sink<i32> = Sink::new();
        let sink2: Sink<f64> = Sink::new();
        let mut snap_events = sink1.stream().hold(1).snapshot(&sink2.stream().map(|x| x + 3.0)).events();
        sink2.send(4.0);
        assert_eq!(snap_events.next(), Some((1, 7.0)));
    }

    #[test]
    fn snapshot_2() {
        let ev1 = Sink::new();
        let beh1 = ev1.stream().hold(5);
        let ev2 = Sink::new();
        let snap = beh1.snapshot(&ev2.stream());
        let mut events = snap.events();
        ev2.send(4);
        assert_eq!(events.next(), Some((5, 4)));
        ev1.send(-2);
        ev2.send(6);
        assert_eq!(events.next(), Some((-2, 6)));
    }

    #[test]
    fn switch() {
        let stream1 = Sink::<Option<i32>>::new();
        let stream2 = Sink::<Option<i32>>::new();
        let button1 = Sink::<()>::new();
        let button2 = Sink::<()>::new();
        let output = {
            let stream1 = stream1.stream().hold(Some(-1));
            let stream2 = stream2.stream().hold(Some(-2));
            button1.stream()
                .map(move |_| stream1.clone())
                .merge(&button2.stream()
                    .map(move |_| stream2.clone())
                )
                .hold(Sink::new().stream().hold(Some(-3)))
                .switch()
        };
        let fn_output = signal::lift1(|x| x.map_or(0, |x| 2*x), &output);
        assert_eq!(output.sample(), Some(-3));
        assert_eq!(fn_output.sample(), -6);
        button1.send(());
        assert_eq!(output.sample(), Some(-1));
        button2.send(());
        assert_eq!(output.sample(), Some(-2));
        button1.send(());
        stream1.send(Some(6));
        assert_eq!(output.sample(), Some(6));
        assert_eq!(fn_output.sample(), 12);
        stream1.send(Some(12));
        assert_eq!(output.sample(), Some(12));
        assert_eq!(fn_output.sample(), 24);
    }

    #[test]
    fn cyclic_snapshot_accum() {
        let sink = Sink::new();
        let stream = sink.stream();
        let accum = SignalCycle::new();
        let def = accum.snapshot(&stream).map(|(a, s)| a + s).hold(0);
        let accum = accum.define(def);
        assert_eq!(accum.sample(), 0);
        sink.send(3);
        assert_eq!(accum.sample(), 3);
        sink.send(7);
        assert_eq!(accum.sample(), 10);
        sink.send(-21);
        assert_eq!(accum.sample(), -11);
    }

    #[test]
    fn snapshot_order_standard() {
        let sink = Sink::new();
        let cell = sink.stream().hold(0);
        let mut events = cell.snapshot(&sink.stream()).events();
        sink.send(1);
        assert_eq!(events.next(), Some((0, 1)));
    }

    #[test]
    fn snapshot_lift_order_standard() {
        let sink = Sink::new();
        let cell = sink.stream().hold(0);
        let mut events = signal::lift1(|x| x, &cell)
            .snapshot(&sink.stream())
            .events();
        sink.send(1);
        assert_eq!(events.next(), Some((0, 1)));
    }

    #[test]
    fn snapshot_order_alternative() {
        let sink = Sink::new();
        // Invert the "natural" order of the registry by declaring the stream before
        // the cell, which are both used by the snapshot.
        let first = sink.stream().map(|x| x);
        let cell = sink.stream().hold(0);
        let mut events = cell.snapshot(&first).events();
        sink.send(1);
        assert_eq!(events.next(), Some((0, 1)));
    }
}
<commit_msg>Factor out primitive signal construction<commit_after>//! Continuous time signals

use std::sync::{ Arc, Mutex };
use std::ops::Deref;
use source::{ Source, with_weak, CallbackError };
use stream::{ self, BoxClone, Stream };
use transaction::{ commit, register_callback };
use pending::Pending;

enum SignalFn {
    Const(A),
    Func(Box<Fn() -> A + Send + Sync + 'static>),
}

impl SignalFn {
    pub fn from_fn<F: Fn() -> A + Send + Sync + 'static>(f: F) -> SignalFn {
        SignalFn::Func(Box::new(f))
    }
}

impl SignalFn {
    pub fn call(&self) -> A {
        match *self {
            SignalFn::Const(ref a) => a.clone(),
            SignalFn::Func(ref f) => f(),
        }
    }
}

/// Helper function to register callback handlers related to signal construction.
fn reg_signal(parent_source: &mut Source, signal: &Signal, handler: F)
    where A: Send + Sync + 'static,
          B: Send + Sync + 'static,
          F: Fn(A) -> SignalFn + Send + Sync + 'static,
{
    let weak_source = signal.source.downgrade();
    let weak_current = signal.current.downgrade();
    parent_source.register(move |a|
        weak_current.upgrade().map(|cur| register_callback(
            move || { let _ = cur.lock().map(|mut cur| cur.update()); }))
            .ok_or(CallbackError::Disappeared)
        .and(with_weak(&weak_current, |cur| cur.queue(handler(a))))
        .and(with_weak(&weak_source, |src| src.send(())))
    );
}

/// A continuous signal.
pub struct Signal {
    current: Arc<Mutex<Pending<SignalFn>>>,
    source: Arc<Mutex<Source<()>>>,
    #[allow(dead_code)]
    keep_alive: Box<BoxClone>,
}

impl Clone for Signal {
    fn clone(&self) -> Signal {
        Signal {
            current: self.current.clone(),
            source: self.source.clone(),
            keep_alive: self.keep_alive.box_clone(),
        }
    }
}

impl Signal {
    fn build<K>(func: SignalFn, keep_alive: K) -> Signal
        where K: Send + Sync + Clone + 'static
    {
        Signal {
            current: Arc::new(Mutex::new(Pending::new(func))),
            source: Arc::new(Mutex::new(Source::new())),
            keep_alive: Box::new(keep_alive),
        }
    }
}

impl Signal {
    /// Create a constant signal.
    pub fn new(a: A) -> Signal {
        Signal::build(SignalFn::Const(a), ())
    }

    /// Sample the current value of a signal.
    pub fn sample(&self) -> A {
        commit((), |_| self.current.lock().unwrap().call())
    }
}

impl Signal {
    /// stub
    pub fn snapshot(&self, stream: &Stream) -> Stream<(A, B)>
        where B: Clone + Send + Sync + 'static,
    {
        stream::snapshot(self, stream)
    }
}

impl Signal<Signal> {
    /// stub
    pub fn switch(&self) -> Signal {
        fn make_callback(parent: &Signal<Signal>) -> SignalFn
            where A: Send + Clone + Sync + 'static,
        {
            // TODO: use information on inner value
            let current_signal = parent.current.clone();
            SignalFn::from_fn(move ||
                current_signal.lock().unwrap().call().sample()
            )
        }
        commit((), |_| {
            let signal = Signal::build(make_callback(self), ());
            let parent = self.clone();
            reg_signal(&mut self.source.lock().unwrap(), &signal,
                move |_| make_callback(&parent));
            signal
        })
    }
}

/// stub
pub struct SignalCycle {
    signal: Signal,
}

impl SignalCycle {
    /// stub
    pub fn new() -> SignalCycle {
        const ERR: &'static str = "sampled on forward-declaration of signal";
        SignalCycle { signal: Signal::build(SignalFn::from_fn(|| panic!(ERR)), ()) }
    }

    /// stub
    pub fn define(self, definition: Signal) -> Signal {
        /// Generate a callback from the signal definition's current value.
        fn make_callback(current_def: &Arc<Mutex<Pending<SignalFn>>>) -> SignalFn
            where A: Send + Sync + Clone + 'static
        {
            match *current_def.lock().unwrap().future() {
                SignalFn::Const(ref a) => SignalFn::Const(a.clone()),
                SignalFn::Func(_) => SignalFn::from_fn({
                    let sig = current_def.downgrade();
                    move || {
                        let strong = sig.upgrade().unwrap();
                        let ret = strong.lock().unwrap().call();
                        ret
                    }
                }),
            }
        }
        commit((), move |_| {
            *self.signal.current.lock().unwrap() = Pending::new(make_callback(&definition.current));
            let weak_parent = definition.current.downgrade();
            reg_signal(&mut definition.source.lock().unwrap(), &self.signal,
                move |_| make_callback(&weak_parent.upgrade().unwrap()));
            Signal { keep_alive: Box::new(definition), ..self.signal }
        })
    }
}

impl Deref for SignalCycle {
    type Target = Signal;
    fn deref(&self) -> &Signal { &self.signal }
}

/// Hold a stream as a signal.
pub fn hold(initial: A, stream: &Stream) -> Signal
    where A: Send + Sync + 'static,
{
    commit((), |_| {
        let signal = Signal::build(SignalFn::Const(initial), stream.clone());
        reg_signal(&mut stream::source(&stream).lock().unwrap(), &signal, SignalFn::Const);
        signal
    })
}

/// Lift a 0-ary function to a signal.
pub fn lift0(f: F) -> Signal
    where F: Fn() -> A + Send + Sync + 'static
{
    Signal::build(SignalFn::from_fn(f), ())
}

/// Unary lift
pub fn lift1(f: F, sa: &Signal) -> Signal
    where A: Send + Sync + Clone + 'static,
          B: Send + Sync + Clone + 'static,
          F: Fn(A) -> B + Send + Sync + 'static,
{
    fn make_callback(f: &Arc<F>, parent: &Signal) -> SignalFn
        where A: Send + Sync + Clone + 'static,
              B: Send + Sync + Clone + 'static,
              F: Fn(A) -> B + Send + Sync + 'static,
    {
        let pclone = parent.clone();
        let f = f.clone();
        match *parent.current.lock().unwrap().future() {
            SignalFn::Const(ref a) => SignalFn::Const(f(a.clone())),
            SignalFn::Func(_) => SignalFn::from_fn(move || f(pclone.sample())),
        }
    }

    let f = Arc::new(f);
    let signal = Signal::build(make_callback(&f, &sa), ());
    let sa_clone = sa.clone();
    reg_signal(&mut sa.source.lock().unwrap(), &signal,
        move |_| make_callback(&f, &sa_clone));
    signal
}

#[cfg(test)]
mod test {
    use ::stream::Sink;
    use ::signal::{ self, Signal, SignalCycle };

    #[test]
    fn clone() {
        let b = Signal::new(3);
        assert_eq!(b.clone().sample(), 3);
    }

    #[test]
    fn lift0() {
        let signal = signal::lift0(|| 3);
        assert_eq!(signal.sample(), 3);
    }

    #[test]
    fn lift1() {
        let sig2 = signal::lift1(|n| n + 2, &Signal::new(3));
        assert_eq!(sig2.sample(), 5);
    }

    #[test]
    fn hold() {
        let sink = Sink::new();
        let signal = sink.stream().hold(3);
        assert_eq!(signal.sample(), 3);
        sink.send(4);
        assert_eq!(signal.sample(), 4);
    }

    #[test]
    fn hold_implicit_stream() {
        let sink = Sink::new();
        let signal = signal::hold(0, &sink.stream().map(|n| 2 * n));
        assert_eq!(signal.sample(), 0);
        sink.send(4);
        assert_eq!(signal.sample(), 8);
    }

    #[test]
    fn snapshot() {
        let sink1: Sink<i32> = Sink::new();
        let sink2: Sink<f64> = Sink::new();
        let mut snap_events = sink1.stream().hold(1).snapshot(&sink2.stream().map(|x| x + 3.0)).events();
        sink2.send(4.0);
        assert_eq!(snap_events.next(), Some((1, 7.0)));
    }

    #[test]
    fn snapshot_2() {
        let ev1 = Sink::new();
        let beh1 = ev1.stream().hold(5);
        let ev2 = Sink::new();
        let snap = beh1.snapshot(&ev2.stream());
        let mut events = snap.events();
        ev2.send(4);
        assert_eq!(events.next(), Some((5, 4)));
        ev1.send(-2);
        ev2.send(6);
        assert_eq!(events.next(), Some((-2, 6)));
    }

    #[test]
    fn switch() {
        let stream1 = Sink::<Option<i32>>::new();
        let stream2 = Sink::<Option<i32>>::new();
        let button1 = Sink::<()>::new();
        let button2 = Sink::<()>::new();
        let output = {
            let stream1 = stream1.stream().hold(Some(-1));
            let stream2 = stream2.stream().hold(Some(-2));
            button1.stream()
                .map(move |_| stream1.clone())
                .merge(&button2.stream()
                    .map(move |_| stream2.clone())
                )
                .hold(Sink::new().stream().hold(Some(-3)))
                .switch()
        };
        let fn_output = signal::lift1(|x| x.map_or(0, |x| 2*x), &output);
        assert_eq!(output.sample(), Some(-3));
        assert_eq!(fn_output.sample(), -6);
        button1.send(());
        assert_eq!(output.sample(), Some(-1));
        button2.send(());
        assert_eq!(output.sample(), Some(-2));
        button1.send(());
        stream1.send(Some(6));
        assert_eq!(output.sample(), Some(6));
        assert_eq!(fn_output.sample(), 12);
        stream1.send(Some(12));
        assert_eq!(output.sample(), Some(12));
        assert_eq!(fn_output.sample(), 24);
    }

    #[test]
    fn cyclic_snapshot_accum() {
        let sink = Sink::new();
        let stream = sink.stream();
        let accum = SignalCycle::new();
        let def = accum.snapshot(&stream).map(|(a, s)| a + s).hold(0);
        let accum = accum.define(def);
        assert_eq!(accum.sample(), 0);
        sink.send(3);
        assert_eq!(accum.sample(), 3);
        sink.send(7);
        assert_eq!(accum.sample(), 10);
        sink.send(-21);
        assert_eq!(accum.sample(), -11);
    }

    #[test]
    fn snapshot_order_standard() {
        let sink = Sink::new();
        let cell = sink.stream().hold(0);
        let mut events = cell.snapshot(&sink.stream()).events();
        sink.send(1);
        assert_eq!(events.next(), Some((0, 1)));
    }

    #[test]
    fn snapshot_lift_order_standard() {
        let sink = Sink::new();
        let cell = sink.stream().hold(0);
        let mut events = signal::lift1(|x| x, &cell)
            .snapshot(&sink.stream())
            .events();
        sink.send(1);
        assert_eq!(events.next(), Some((0, 1)));
    }

    #[test]
    fn snapshot_order_alternative() {
        let sink = Sink::new();
        // Invert the "natural" order of the registry by declaring the stream before
        // the cell, which are both used by the snapshot.
        let first = sink.stream().map(|x| x);
        let cell = sink.stream().hold(0);
        let mut events = cell.snapshot(&first).events();
        sink.send(1);
        assert_eq!(events.next(), Some((0, 1)));
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::error::Error;
use std::io::ErrorKind::{WouldBlock, BrokenPipe, WriteZero, ConnectionReset};

use rotor::{Response, Scope, Machine, EventSet, PollOpt, Time};
use rotor::void::{Void, unreachable};

use substr::find_substr;
use extensions::{ScopeExt, ResponseExt};
use {Expectation, Protocol, StreamSocket, Stream, StreamImpl};
use {Buf, Transport, Accepted, Exception, Intent};
use {ProtocolStop};

#[derive(Debug)]
enum IoOp {
    Done,
    NoOp,
    Eos,
    Error(io::Error),
}

fn to_result
(intent: Intent
)
    -> Result<(P, Expectation, Option<Time>), Option<Box<Error>>>
{
    match intent.0 {
        Ok(x) => Ok((x, intent.1, intent.2)),
        Err(e) => Err(e),
    }
}

impl<S: StreamSocket> StreamImpl<S> {
    fn transport(&mut self) -> Transport<S> {
        Transport {
            sock: &mut self.socket,
            inbuf: &mut self.inbuf,
            outbuf: &mut self.outbuf,
        }
    }
    fn action<M>(self, intent: Intent<M>,
        scope: &mut Scope<M::Context>)
        -> Response<Stream<M>, Void>
        where M: Protocol<Socket=S>
    {
        match self._action(intent, scope) {
            Ok(stream) => {
                let dline = stream.deadline;
                Response::ok(stream).deadline_opt(dline)
            }
            Err(Some(e)) => Response::error(e),
            Err(None) => Response::done(),
        }
    }
    fn _action
(mut self, intent: Intent
,
        scope: &mut Scope
)
        -> Result<Stream
, Option<Box<Error>>>
        where P: Protocol<Socket=S>
    {
        use Expectation::*;
        let mut intent = try!(to_result(intent));
        let mut can_write = match self.write() {
            IoOp::Done => true,
            IoOp::NoOp => false,
            IoOp::Eos => {
                intent = try!(to_result(intent.0.exception(
                    &mut self.transport(),
                    Exception::WriteError(io::Error::new(
                        WriteZero, "failed to write whole buffer")),
                    scope)));
                self.outbuf.remove_range(..);
                false
            }
            IoOp::Error(e) => {
                intent = try!(to_result(intent.0.exception(
                    &mut self.transport(),
                    Exception::WriteError(e),
                    scope)));
                false
            }
        };
        'outer: loop {
            if can_write {
                can_write = match self.write() {
                    IoOp::Done => true,
                    IoOp::NoOp => false,
                    IoOp::Eos => {
                        intent = try!(to_result(intent.0.exception(
                            &mut self.transport(),
                            Exception::WriteError(io::Error::new(
                                WriteZero, "failed to write whole buffer")),
                            scope)));
                        self.outbuf.remove_range(..);
                        false
                    }
                    IoOp::Error(e) => {
                        intent = try!(to_result(intent.0.exception(
                            &mut self.transport(),
                            Exception::WriteError(e),
                            scope)));
                        false
                    }
                };
            }
            match intent.1 {
                Bytes(num) => {
                    loop {
                        if self.inbuf.len() >= num {
                            intent = try!(to_result(intent.0.bytes_read(
                                &mut self.transport(),
                                num, scope)));
                            continue 'outer;
                        }
                        match self.read() {
                            IoOp::Done => {}
                            IoOp::NoOp => {
                                return Ok(Stream::compose(self, intent));
                            }
                            IoOp::Eos => {
                                intent = try!(to_result(intent.0.exception(
                                    &mut self.transport(),
                                    Exception::EndOfStream,
                                    scope)));
                                continue 'outer;
                            }
                            IoOp::Error(e) => {
                                intent = try!(to_result(intent.0.exception(
                                    &mut self.transport(),
                                    Exception::ReadError(e),
                                    scope)));
                                continue 'outer;
                            }
                        }
                    }
                }
                Delimiter(min, delim, max) => {
                    loop {
                        if self.inbuf.len() > min {
                            let opt = find_substr(&self.inbuf[min..], delim);
                            if let Some(num) = opt {
                                intent = try!(to_result(intent.0.bytes_read(
                                    &mut self.transport(),
                                    num, scope)));
                                continue 'outer;
                            }
                        }
                        if self.inbuf.len() > max {
                            intent = try!(to_result(intent.0.exception(
                                &mut self.transport(),
                                Exception::LimitReached,
                                scope)));
                            continue 'outer;
                        }
                        match self.read() {
                            IoOp::Done => {}
                            IoOp::NoOp => {
                                return Ok(Stream::compose(self, intent));
                            }
                            IoOp::Eos => {
                                intent = try!(to_result(intent.0.exception(
                                    &mut self.transport(),
                                    Exception::EndOfStream,
                                    scope)));
                                continue 'outer;
                            }
                            IoOp::Error(e) => {
                                intent = try!(to_result(intent.0.exception(
                                    &mut self.transport(),
                                    Exception::ReadError(e),
                                    scope)));
                                continue 'outer;
                            }
                        }
                    }
                }
                Flush(num) => {
                    if self.outbuf.len() <= num {
                        intent = try!(to_result(intent.0.bytes_flushed(
                            &mut self.transport(), scope)));
                    } else {
                        return Ok(Stream::compose(self, intent));
                    }
                }
                Sleep => {
                    return Ok(Stream::compose(self, intent));
                }
            }
        }
    }
    // Returns Ok(true) to if we have read something, does not loop for reading
    // because this might use whole memory, and we may parse and consume the
    // input instead of buffering it whole.
    fn read(&mut self) -> IoOp {
        match self.inbuf.read_from(&mut self.socket) {
            Ok(0) => IoOp::Eos,
            Ok(_) => IoOp::Done,
            Err(ref e) if e.kind() == BrokenPipe
                       || e.kind() == ConnectionReset
            => return IoOp::Eos,
            Err(ref e) if e.kind() == WouldBlock => IoOp::NoOp,
            Err(e) => IoOp::Error(e),
        }
    }
    fn write(&mut self) -> IoOp {
        loop {
            if self.outbuf.len() == 0 {
                return IoOp::Done;
            }
            match self.outbuf.write_to(&mut self.socket) {
                Ok(0) => return IoOp::Eos,
                Ok(_) => continue,
                Err(ref e) if e.kind() == BrokenPipe
                           || e.kind() == ConnectionReset
                => return IoOp::Eos,
                Err(ref e) if e.kind() == WouldBlock => return IoOp::NoOp,
                Err(e) => return IoOp::Error(e),
            }
        }
    }
}

impl
 Accepted
 for Stream

    where P: Protocol<Seed=()>
{
    fn accepted(sock: P::Socket, scope: &mut Scope<Self::Context>)
        -> Response<Self, Void>
    {
        Self::new(sock, (), scope)
    }
}

impl
 Stream
 {
    fn decompose(self) -> (P, Expectation, StreamImpl
) {
        (self.fsm, self.expectation, StreamImpl {
            socket: self.socket,
            inbuf: self.inbuf,
            outbuf: self.outbuf,
        })
    }
    fn compose(implem: StreamImpl
,
        (fsm, exp, dline): (P, Expectation, Option<Time>))
        -> Stream

    {
        Stream {
            fsm: fsm,
            socket: implem.socket,
            expectation: exp,
            deadline: dline,
            inbuf: implem.inbuf,
            outbuf: implem.outbuf,
        }
    }
    pub fn new(mut sock: P::Socket, seed: P::Seed,
        scope: &mut Scope
)
        -> Response<Self, Void>
    {
        // Always register everything in edge-triggered mode.
        // This allows to never reregister socket.
        //
        // The no-reregister strategy is not a goal (although, it's expected
        // to lower number of syscalls for many request-reply-like protocols)
        // but it allows to have single source of truth for
        // readable()/writable() mask (no duplication in kernel space)
        if let Err(e) = scope.register(&sock,
            EventSet::readable() | EventSet::writable(), PollOpt::edge())
        {
            // TODO(tailhook) wrap it to more clear error
            return Response::error(Box::new(e));
        }
        let Intent(m, exp, dline) = P::create(seed, &mut sock, scope);
        match m {
            Err(None) => Response::error(Box::new(ProtocolStop)),
            Err(Some(e)) => Response::error(e),
            Ok(m) => {
                Response::ok(Stream {
                    socket: sock,
                    expectation: exp,
                    deadline: dline,
                    fsm: m,
                    inbuf: Buf::new(),
                    outbuf: Buf::new(),
                }).deadline_opt(dline)
            }
        }
    }
    pub fn connected(mut sock: P::Socket, seed: P::Seed,
        scope: &mut Scope
)
        -> Response<Self, Void>
    {
        // Always register everything in edge-triggered mode.
        // This allows to never reregister socket.
        //
        // The no-reregister strategy is not a goal (although, it's expected
        // to lower number of syscalls for many request-reply-like protocols)
        // but it allows to have single source of truth for
        // readable()/writable() mask (no duplication in kernel space)
        //
        // We reregister here, because we assume that higher level abstraction
        // has the socket already registered (perhaps `Persistent` machine)
        if let Err(e) = scope.reregister(&sock,
            EventSet::readable() | EventSet::writable(), PollOpt::edge())
        {
            // TODO(tailhook) wrap it to more clear error
            return Response::error(Box::new(e));
        }
        let Intent(m, exp, dline) = P::create(seed, &mut sock, scope);
        match m {
            Err(None) => Response::error(Box::new(ProtocolStop)),
            Err(Some(e)) => Response::error(e),
            Ok(m) => {
                Response::ok(Stream {
                    socket: sock,
                    expectation: exp,
                    deadline: dline,
                    fsm: m,
                    inbuf: Buf::new(),
                    outbuf: Buf::new(),
                }).deadline_opt(dline)
            }
        }
    }
}

impl
 Machine for Stream

{
    type Context = P::Context;
    type Seed = Void;
    fn create(void: Void, _scope: &mut Scope<Self::Context>)
        -> Response<Self, Void>
    {
        unreachable(void);
    }
    fn ready(self, _events: EventSet, scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        // TODO(tailhook) use `events` to optimize reading
        let (fsm, exp, imp) = self.decompose();
        imp.action(Intent(Ok(fsm), exp, None), scope)
    }
    fn spawned(self, _scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        unreachable!();
    }
    fn timeout(self, scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        if scope.reached(self.deadline) {
            let (fsm, _exp, mut imp) = self.decompose();
            let res = fsm.timeout(&mut imp.transport(), scope);
            imp.action(res, scope)
        } else {
            // TODO(tailhook) in rotor 0.6 should be no spurious timeouts
            // anymore, but let's keep it until we remove Scope::timeout_ms()
            Response::ok(self)
        }
    }
    fn wakeup(self, scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        let (fsm, _exp, mut imp) = self.decompose();
        let res = fsm.wakeup(&mut imp.transport(), scope);
        imp.action(res, scope)
    }
}
<commit_msg>Fix incorrect bookkeeping of timeout<commit_after>use std::io;
use std::error::Error;
use std::io::ErrorKind::{WouldBlock, BrokenPipe, WriteZero, ConnectionReset};

use rotor::{Response, Scope, Machine, EventSet, PollOpt, Time};
use rotor::void::{Void, unreachable};

use substr::find_substr;
use extensions::{ScopeExt, ResponseExt};
use {Expectation, Protocol, StreamSocket, Stream, StreamImpl};
use {Buf, Transport, Accepted, Exception, Intent};
use {ProtocolStop};

#[derive(Debug)]
enum IoOp {
    Done,
    NoOp,
    Eos,
    Error(io::Error),
}

fn to_result
(intent: Intent
)
    -> Result<(P, Expectation, Option<Time>), Option<Box<Error>>>
{
    match intent.0 {
        Ok(x) => Ok((x, intent.1, intent.2)),
        Err(e) => Err(e),
    }
}

impl<S: StreamSocket> StreamImpl<S> {
    fn transport(&mut self) -> Transport<S> {
        Transport {
            sock: &mut self.socket,
            inbuf: &mut self.inbuf,
            outbuf: &mut self.outbuf,
        }
    }
    fn action<M>(self, intent: Intent<M>,
        scope: &mut Scope<M::Context>)
        -> Response<Stream<M>, Void>
        where M: Protocol<Socket=S>
    {
        match self._action(intent, scope) {
            Ok(stream) => {
                let dline = stream.deadline;
                Response::ok(stream).deadline_opt(dline)
            }
            Err(Some(e)) => Response::error(e),
            Err(None) => Response::done(),
        }
    }
    fn _action
(mut self, intent: Intent
,
        scope: &mut Scope
)
        -> Result<Stream
, Option<Box<Error>>>
        where P: Protocol<Socket=S>
    {
        use Expectation::*;
        let mut intent = try!(to_result(intent));
        let mut can_write = match self.write() {
            IoOp::Done => true,
            IoOp::NoOp => false,
            IoOp::Eos => {
                intent = try!(to_result(intent.0.exception(
                    &mut self.transport(),
                    Exception::WriteError(io::Error::new(
                        WriteZero, "failed to write whole buffer")),
                    scope)));
                self.outbuf.remove_range(..);
                false
            }
            IoOp::Error(e) => {
                intent = try!(to_result(intent.0.exception(
                    &mut self.transport(),
                    Exception::WriteError(e),
                    scope)));
                false
            }
        };
        'outer: loop {
            if can_write {
                can_write = match self.write() {
                    IoOp::Done => true,
                    IoOp::NoOp => false,
                    IoOp::Eos => {
                        intent = try!(to_result(intent.0.exception(
                            &mut self.transport(),
                            Exception::WriteError(io::Error::new(
                                WriteZero, "failed to write whole buffer")),
                            scope)));
                        self.outbuf.remove_range(..);
                        false
                    }
                    IoOp::Error(e) => {
                        intent = try!(to_result(intent.0.exception(
                            &mut self.transport(),
                            Exception::WriteError(e),
                            scope)));
                        false
                    }
                };
            }
            match intent.1 {
                Bytes(num) => {
                    loop {
                        if self.inbuf.len() >= num {
                            intent = try!(to_result(intent.0.bytes_read(
                                &mut self.transport(),
                                num, scope)));
                            continue 'outer;
                        }
                        match self.read() {
                            IoOp::Done => {}
                            IoOp::NoOp => {
                                return Ok(Stream::compose(self, intent));
                            }
                            IoOp::Eos => {
                                intent = try!(to_result(intent.0.exception(
                                    &mut self.transport(),
                                    Exception::EndOfStream,
                                    scope)));
                                continue 'outer;
                            }
                            IoOp::Error(e) => {
                                intent = try!(to_result(intent.0.exception(
                                    &mut self.transport(),
                                    Exception::ReadError(e),
                                    scope)));
                                continue 'outer;
                            }
                        }
                    }
                }
                Delimiter(min, delim, max) => {
                    loop {
                        if self.inbuf.len() > min {
                            let opt = find_substr(&self.inbuf[min..], delim);
                            if let Some(num) = opt {
                                intent = try!(to_result(intent.0.bytes_read(
                                    &mut self.transport(),
                                    num, scope)));
                                continue 'outer;
                            }
                        }
                        if self.inbuf.len() > max {
                            intent = try!(to_result(intent.0.exception(
                                &mut self.transport(),
                                Exception::LimitReached,
                                scope)));
                            continue 'outer;
                        }
                        match self.read() {
                            IoOp::Done => {}
                            IoOp::NoOp => {
                                return Ok(Stream::compose(self, intent));
                            }
                            IoOp::Eos => {
                                intent = try!(to_result(intent.0.exception(
                                    &mut self.transport(),
                                    Exception::EndOfStream,
                                    scope)));
                                continue 'outer;
                            }
                            IoOp::Error(e) => {
                                intent = try!(to_result(intent.0.exception(
                                    &mut self.transport(),
                                    Exception::ReadError(e),
                                    scope)));
                                continue 'outer;
                            }
                        }
                    }
                }
                Flush(num) => {
                    if self.outbuf.len() <= num {
                        intent = try!(to_result(intent.0.bytes_flushed(
                            &mut self.transport(), scope)));
                    } else {
                        return Ok(Stream::compose(self, intent));
                    }
                }
                Sleep => {
                    return Ok(Stream::compose(self, intent));
                }
            }
        }
    }
    // Returns Ok(true) to if we have read something, does not loop for reading
    // because this might use whole memory, and we may parse and consume the
    // input instead of buffering it whole.
    fn read(&mut self) -> IoOp {
        match self.inbuf.read_from(&mut self.socket) {
            Ok(0) => IoOp::Eos,
            Ok(_) => IoOp::Done,
            Err(ref e) if e.kind() == BrokenPipe
                       || e.kind() == ConnectionReset
            => return IoOp::Eos,
            Err(ref e) if e.kind() == WouldBlock => IoOp::NoOp,
            Err(e) => IoOp::Error(e),
        }
    }
    fn write(&mut self) -> IoOp {
        loop {
            if self.outbuf.len() == 0 {
                return IoOp::Done;
            }
            match self.outbuf.write_to(&mut self.socket) {
                Ok(0) => return IoOp::Eos,
                Ok(_) => continue,
                Err(ref e) if e.kind() == BrokenPipe
                           || e.kind() == ConnectionReset
                => return IoOp::Eos,
                Err(ref e) if e.kind() == WouldBlock => return IoOp::NoOp,
                Err(e) => return IoOp::Error(e),
            }
        }
    }
}

impl
 Accepted
 for Stream

    where P: Protocol<Seed=()>
{
    fn accepted(sock: P::Socket, scope: &mut Scope<Self::Context>)
        -> Response<Self, Void>
    {
        Self::new(sock, (), scope)
    }
}

impl
 Stream
 {
    fn decompose(self) -> (P, Expectation, Option<Time>, StreamImpl
)
    {
        (self.fsm, self.expectation, self.deadline, StreamImpl {
            socket: self.socket,
            inbuf: self.inbuf,
            outbuf: self.outbuf,
        })
    }
    fn compose(implem: StreamImpl
,
        (fsm, exp, dline): (P, Expectation, Option<Time>))
        -> Stream

    {
        Stream {
            fsm: fsm,
            socket: implem.socket,
            expectation: exp,
            deadline: dline,
            inbuf: implem.inbuf,
            outbuf: implem.outbuf,
        }
    }
    pub fn new(mut sock: P::Socket, seed: P::Seed,
        scope: &mut Scope
)
        -> Response<Self, Void>
    {
        // Always register everything in edge-triggered mode.
        // This allows to never reregister socket.
        //
        // The no-reregister strategy is not a goal (although, it's expected
        // to lower number of syscalls for many request-reply-like protocols)
        // but it allows to have single source of truth for
        // readable()/writable() mask (no duplication in kernel space)
        if let Err(e) = scope.register(&sock,
            EventSet::readable() | EventSet::writable(), PollOpt::edge())
        {
            // TODO(tailhook) wrap it to more clear error
            return Response::error(Box::new(e));
        }
        let Intent(m, exp, dline) = P::create(seed, &mut sock, scope);
        match m {
            Err(None) => Response::error(Box::new(ProtocolStop)),
            Err(Some(e)) => Response::error(e),
            Ok(m) => {
                Response::ok(Stream {
                    socket: sock,
                    expectation: exp,
                    deadline: dline,
                    fsm: m,
                    inbuf: Buf::new(),
                    outbuf: Buf::new(),
                }).deadline_opt(dline)
            }
        }
    }
    pub fn connected(mut sock: P::Socket, seed: P::Seed,
        scope: &mut Scope
)
        -> Response<Self, Void>
    {
        // Always register everything in edge-triggered mode.
        // This allows to never reregister socket.
        //
        // The no-reregister strategy is not a goal (although, it's expected
        // to lower number of syscalls for many request-reply-like protocols)
        // but it allows to have single source of truth for
        // readable()/writable() mask (no duplication in kernel space)
        //
        // We reregister here, because we assume that higher level abstraction
        // has the socket already registered (perhaps `Persistent` machine)
        if let Err(e) = scope.reregister(&sock,
            EventSet::readable() | EventSet::writable(), PollOpt::edge())
        {
            // TODO(tailhook) wrap it to more clear error
            return Response::error(Box::new(e));
        }
        let Intent(m, exp, dline) = P::create(seed, &mut sock, scope);
        match m {
            Err(None) => Response::error(Box::new(ProtocolStop)),
            Err(Some(e)) => Response::error(e),
            Ok(m) => {
                Response::ok(Stream {
                    socket: sock,
                    expectation: exp,
                    deadline: dline,
                    fsm: m,
                    inbuf: Buf::new(),
                    outbuf: Buf::new(),
                }).deadline_opt(dline)
            }
        }
    }
}

impl
 Machine for Stream

{
    type Context = P::Context;
    type Seed = Void;
    fn create(void: Void, _scope: &mut Scope<Self::Context>)
        -> Response<Self, Void>
    {
        unreachable(void);
    }
    fn ready(self, _events: EventSet, scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        // TODO(tailhook) use `events` to optimize reading
        let (fsm, exp, dline, imp) = self.decompose();
        imp.action(Intent(Ok(fsm), exp, dline), scope)
    }
    fn spawned(self, _scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        unreachable!();
    }
    fn timeout(self, scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        if scope.reached(self.deadline) {
            let (fsm, _exp, _dline, mut imp) = self.decompose();
            let res = fsm.timeout(&mut imp.transport(), scope);
            imp.action(res, scope)
        } else {
            // TODO(tailhook) in rotor 0.6 should be no spurious timeouts
            // anymore, but let's keep it until we remove Scope::timeout_ms()
            Response::ok(self)
        }
    }
    fn wakeup(self, scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>
    {
        let (fsm, _exp, _dline, mut imp) = self.decompose();
        let res = fsm.wakeup(&mut imp.transport(), scope);
        imp.action(res, scope)
    }
}
<|endoftext|>