<commit_before>use serde_json;
use std::collections::HashMap;

/// Permitted JSON-API values (all JSON Values)
pub type JsonApiValue = serde_json::Value;

/// Vector of `Resource`
pub type Resources = Vec<Resource>;
/// Vector of `ResourceIdentifiers`
pub type ResourceIdentifiers = Vec<ResourceIdentifier>;
pub type Links = HashMap<String, JsonApiValue>;
/// Meta-data object, can contain any data
pub type Meta = HashMap<String, JsonApiValue>;
/// Resource Attributes, can be any JSON value
pub type ResourceAttributes = HashMap<String, JsonApiValue>;
/// Map of relationships with other objects
pub type Relationships = HashMap<String, Relationship>;
/// Side-loaded Resources
pub type Included = Vec<Resource>;
/// Data-related errors
pub type JsonApiErrors = Vec<JsonApiError>;

pub type JsonApiId = String;
pub type JsonApiIds<'a> = Vec<&'a JsonApiId>;

/// Resource Identifier
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct ResourceIdentifier {
    #[serde(rename = "type")]
    pub _type: String,
    pub id: JsonApiId,
}

/// JSON-API Resource
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Resource {
    #[serde(rename = "type")]
    pub _type: String,
    pub id: JsonApiId,
    pub attributes: ResourceAttributes,
    pub relationships: Option<Relationships>,
    pub links: Option<Links>,
    pub meta: Option<Meta>,
}

/// Relationship with another object
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Relationship {
    pub data: IdentifierData,
    pub links: Option<Links>,
}

/// Valid data Resource (can be None)
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(untagged)]
pub enum PrimaryData {
    None,
    Single(Resource),
    Multiple(Resources),
}

/// Valid Resource Identifier (can be None)
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(untagged)]
pub enum IdentifierData {
    None,
    Single(ResourceIdentifier),
    Multiple(ResourceIdentifiers),
}

/// The specification refers to this as a top-level `document`
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct JsonApiDocument {
    pub data: Option<PrimaryData>,
    pub included: Option<Resources>,
    pub links: Option<Links>,
    pub meta: Option<Meta>,
    pub errors: Option<JsonApiErrors>,
    pub jsonapi: Option<JsonApiInfo>,
}

/// Error location
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct ErrorSource {
    pub pointer: Option<String>,
    pub parameter: Option<String>,
}

/// JSON-API Error
/// All fields are optional
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct JsonApiError {
    pub id: Option<String>,
    pub links: Option<Links>,
    pub status: Option<String>,
    pub code: Option<String>,
    pub title: Option<String>,
    pub detail: Option<String>,
    pub source: Option<ErrorSource>,
    pub meta: Option<Meta>,
}

/// Optional `JsonApiDocument` payload identifying the JSON-API version the server implements
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct JsonApiInfo {
    pub version: Option<String>,
    pub meta: Option<Meta>,
}

/// Pagination links
#[derive(Serialize, Deserialize, Debug)]
pub struct Pagination {
    pub first: Option<String>,
    pub prev: Option<String>,
    pub next: Option<String>,
    pub last: Option<String>,
}

#[derive(Debug)]
pub struct Patch {
    pub patch_type: PatchType,
    pub subject: String,
    pub previous: JsonApiValue,
    pub next: JsonApiValue,
}

#[derive(Debug)]
pub struct PatchSet {
    pub resource_type: String,
    pub resource_id: String,
    pub patches: Vec<Patch>,
}

impl PatchSet {
    pub fn new_for(resource: &Resource) -> Self {
        PatchSet {
            resource_type: resource._type.clone(),
            resource_id: resource.id.clone(),
            patches: Vec::<Patch>::new(),
        }
    }

    pub fn push(&mut self, patch: Patch) -> () {
        self.patches.push(patch);
    }
}

impl Pagination {
    pub fn has_first(&self) -> bool {
        !self.first.is_none()
    }
    pub fn has_prev(&self) -> bool {
        !self.prev.is_none()
    }
    pub fn has_next(&self) -> bool {
        !self.next.is_none()
    }
    pub fn has_last(&self) -> bool {
        !self.last.is_none()
    }
}

/// Top-level JSON-API Document
impl JsonApiDocument {
    fn has_errors(&self) -> bool {
        !self.errors.is_none()
    }
    fn has_meta(&self) -> bool {
        !self.errors.is_none()
    }
    fn has_included(&self) -> bool {
        !self.included.is_none()
    }
    fn has_data(&self) -> bool {
        !self.data.is_none()
    }
    /// This function returns `false` if the `JsonApiDocument` contains any violations of the
    /// specification. See `DocumentValidationError`
    ///
    /// The spec dictates that the document must have least one of `data`, `errors` or `meta`.
    /// Of these, `data` and `errors` must not co-exist.
    /// The optional field `included` may only be present if the `data` field is present too.
    ///
    /// ```
    /// use jsonapi::api::{JsonApiDocument, PrimaryData, JsonApiErrors};
    /// let doc = JsonApiDocument {
    ///     data: Some(PrimaryData::None),
    ///     errors: Some(JsonApiErrors::new()),
    ///     meta: None,
    ///     included: None,
    ///     links: None,
    ///     jsonapi: None,
    /// };
    ///
    /// assert_eq!(doc.is_valid(), false);
    /// ```
    pub fn is_valid(&self) -> bool {
        match self.validate() {
            Some(_) => false,
            None => true,
        }
    }

    /// This function returns a `Vec` with identified specification violations enumerated in
    /// `DocumentValidationError`
    ///
    /// ```
    /// use jsonapi::api::{JsonApiDocument, PrimaryData, JsonApiErrors, DocumentValidationError};
    ///
    /// let doc = JsonApiDocument {
    ///     data: Some(PrimaryData::None),
    ///     errors: Some(JsonApiErrors::new()),
    ///     meta: None,
    ///     included: None,
    ///     links: None,
    ///     jsonapi: None,
    /// };
    ///
    /// match doc.validate() {
    ///   Some(errors) => {
    ///     assert!(
    ///       errors.contains(
    ///         &DocumentValidationError::DataWithErrors
    ///       )
    ///     )
    ///   }
    ///   None => assert!(false)
    /// }
    /// ```
    pub fn validate(&self) -> Option<Vec<DocumentValidationError>> {

        let mut errors = Vec::<DocumentValidationError>::new();

        if self.has_data() && self.has_errors() {
            errors.push(DocumentValidationError::DataWithErrors);
        }

        if self.has_included() && !self.has_data() {
            errors.push(DocumentValidationError::IncludedWithoutData);
        }

        if !(self.has_data() || self.has_meta() || self.has_errors()) {
            errors.push(DocumentValidationError::MissingContent);
        }

        match errors.len() {
            0 => None,
            _ => Some(errors),
        }

    }

    /// Instantiate from string
    ///
    /// ```
    /// use jsonapi::api::JsonApiDocument;
    ///
    /// let serialized = r#"{
    ///   "data" : [
    ///     { "id":"1", "type":"post", "attributes":{}, "relationships":{}, "links" :{} },
    ///     { "id":"2", "type":"post", "attributes":{}, "relationships":{}, "links" :{} },
    ///     { "id":"3", "type":"post", "attributes":{}, "relationships":{}, "links" :{} }
    ///   ]
    /// }"#;
    /// let doc = JsonApiDocument::from_str(&serialized);
    /// assert_eq!(doc.is_ok(), true);
    /// ```
    pub fn from_str(s: &str) -> Result<Self, serde_json::Error> {
        serde_json::from_str(s)
    }
}

impl Resource {
    /// Instantiate from string
    ///
    /// ```
    /// use jsonapi::api::Resource;
    ///
    /// let serialized = r#"{
    ///   "id":"1",
    ///   "type":"post",
    ///   "attributes":{
    ///     "title": "Rails is Omakase",
    ///     "likes": 250
    ///   },
    ///   "relationships":{},
    ///   "links" :{}
    /// }"#;
    ///
    /// let data = Resource::from_str(&serialized);
    /// assert_eq!(data.is_ok(), true);
    /// ```
    pub fn from_str(s: &str) -> Result<Self, serde_json::Error> {
        serde_json::from_str(s)
    }

    pub fn get_relationship(&self, name: &str) -> Option<&Relationship> {
        match self.relationships {
            None => None,
            Some(ref relationships) => {
                match relationships.get(name) {
                    None => None,
                    Some(rel) => Some(rel),
                }
            }
        }
    }

    /// Get an attribute `JsonApiValue`
    ///
    /// ```
    /// use jsonapi::api::Resource;
    ///
    /// let serialized = r#"{
    ///   "id":"1",
    ///   "type":"post",
    ///   "attributes":{
    ///     "title": "Rails is Omakase",
    ///     "likes": 250
    ///   },
    ///   "relationships":{},
    ///   "links" :{}
    /// }"#;
    ///
    /// match Resource::from_str(&serialized) {
    ///   Err(_)=> assert!(false),
    ///   Ok(resource)=> {
    ///     match resource.get_attribute("title") {
    ///       None => assert!(false),
    ///       Some(attr) => {
    ///         match attr.as_str() {
    ///           None => assert!(false),
    ///           Some(s) => {
    ///               assert_eq!(s, "Rails is Omakase");
    ///           }
    ///         }
    ///       }
    ///     }
    ///   }
    /// }
    pub fn get_attribute(&self, name: &str) -> Option<&JsonApiValue> {
        match self.attributes.get(name) {
            None => None,
            Some(val) => Some(val),
        }
    }

    pub fn diff(&self, other: Resource) -> Result<PatchSet, DiffPatchError> {
        if self._type != other._type {
            Err(DiffPatchError::IncompatibleTypes(self._type.clone(), other._type.clone()))
        } else {

            let mut self_keys: Vec<String> =
                self.attributes.iter().map(|(key, _)| key.clone()).collect();

            self_keys.sort();

            let mut other_keys: Vec<String> =
                other.attributes.iter().map(|(key, _)| key.clone()).collect();

            other_keys.sort();

            let matching = self_keys.iter().zip(other_keys.iter()).filter(|&(a, b)| a == b).count();

            if matching != self_keys.len() {
                Err(DiffPatchError::DifferentAttributeKeys)
            } else {
                let mut patchset = PatchSet::new_for(self);

                for (attr, self_value) in &self.attributes {
                    match other.attributes.get(attr) {
                        None => {
                            error!("Resource::diff unable to find attribute {:?} in {:?}",
                                   attr,
                                   other);
                        }
                        Some(other_value) => {
                            if self_value.to_string() != other_value.to_string() {
                                patchset.push(Patch {
                                    patch_type: PatchType::Attribute,
                                    subject: attr.clone(),
                                    previous: self_value.clone(),
                                    next: other_value.clone(),
                                });
                            }
                        }
                    }

                }

                Ok(patchset)
            }
        }
    }

    pub fn patch(&mut self, patchset: PatchSet) -> Result<Resource, DiffPatchError> {
        let mut res = self.clone();
        for patch in &patchset.patches {
            res.attributes.insert(patch.subject.clone(), patch.next.clone());
        }
        Ok(res)
    }
}

impl Relationship {
    pub fn as_id(&self) -> Result<Option<&JsonApiId>, RelationshipAssumptionError> {
        match self.data {
            IdentifierData::None => Ok(None),
            IdentifierData::Multiple(_) => Err(RelationshipAssumptionError::RelationshipIsAList),
            IdentifierData::Single(ref data) => Ok(Some(&data.id)),
        }
    }

    pub fn as_ids(&self) -> Result<Option<JsonApiIds>, RelationshipAssumptionError> {
        match self.data {
            IdentifierData::None => Ok(None),
            IdentifierData::Single(_) => Err(RelationshipAssumptionError::RelationshipIsNotAList),
            IdentifierData::Multiple(ref data) => Ok(Some(data.iter().map(|x| &x.id).collect())),
        }
    }
}

/// Top-level (Document) JSON-API specification violations
#[derive(Debug, Clone, PartialEq, Copy)]
pub enum DocumentValidationError {
    IncludedWithoutData,
    DataWithErrors,
    MissingContent,
}

#[derive(Debug, Clone, PartialEq, Copy)]
pub enum JsonApiDataError {
    AttributeNotFound,
    IncompatibleAttributeType,
}

#[derive(Debug, Clone, PartialEq, Copy)]
pub enum RelationshipAssumptionError {
    RelationshipIsAList,
    RelationshipIsNotAList,
}

#[derive(Debug, Clone, PartialEq)]
pub enum DiffPatchError {
    IncompatibleTypes(String, String),
    DifferentAttributeKeys,
    NonExistentProperty(String),
    IncorrectPropertyValue(String),
}

#[derive(Debug, Clone, PartialEq, Copy)]
pub enum PatchType {
    Relationship,
    Attribute,
}
<commit_msg>feature: Remove superfluous Pagination impl<commit_after>use serde_json;
use std::collections::HashMap;

/// Permitted JSON-API values (all JSON Values)
pub type JsonApiValue = serde_json::Value;

/// Vector of `Resource`
pub type Resources = Vec<Resource>;
/// Vector of `ResourceIdentifiers`
pub type ResourceIdentifiers = Vec<ResourceIdentifier>;
pub type Links = HashMap<String, JsonApiValue>;
/// Meta-data object, can contain any data
pub type Meta = HashMap<String, JsonApiValue>;
/// Resource Attributes, can be any JSON value
pub type ResourceAttributes = HashMap<String, JsonApiValue>;
/// Map of relationships with other objects
pub type Relationships = HashMap<String, Relationship>;
/// Side-loaded Resources
pub type Included = Vec<Resource>;
/// Data-related errors
pub type JsonApiErrors = Vec<JsonApiError>;

pub type JsonApiId = String;
pub type JsonApiIds<'a> = Vec<&'a JsonApiId>;

/// Resource Identifier
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct ResourceIdentifier {
    #[serde(rename = "type")]
    pub _type: String,
    pub id: JsonApiId,
}

/// JSON-API Resource
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Resource {
    #[serde(rename = "type")]
    pub _type: String,
    pub id: JsonApiId,
    pub attributes: ResourceAttributes,
    pub relationships: Option<Relationships>,
    pub links: Option<Links>,
    pub meta: Option<Meta>,
}

/// Relationship with another object
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Relationship {
    pub data: IdentifierData,
    pub links: Option<Links>,
}

/// Valid data Resource (can be None)
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(untagged)]
pub enum PrimaryData {
    None,
    Single(Resource),
    Multiple(Resources),
}

/// Valid Resource Identifier (can be None)
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(untagged)]
pub enum IdentifierData {
    None,
    Single(ResourceIdentifier),
    Multiple(ResourceIdentifiers),
}

/// The specification refers to this as a top-level `document`
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct JsonApiDocument {
    pub data: Option<PrimaryData>,
    pub included: Option<Resources>,
    pub links: Option<Links>,
    pub meta: Option<Meta>,
    pub errors: Option<JsonApiErrors>,
    pub jsonapi: Option<JsonApiInfo>,
}

/// Error location
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct ErrorSource {
    pub pointer: Option<String>,
    pub parameter: Option<String>,
}

/// JSON-API Error
/// All fields are optional
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct JsonApiError {
    pub id: Option<String>,
    pub links: Option<Links>,
    pub status: Option<String>,
    pub code: Option<String>,
    pub title: Option<String>,
    pub detail: Option<String>,
    pub source: Option<ErrorSource>,
    pub meta: Option<Meta>,
}

/// Optional `JsonApiDocument` payload identifying the JSON-API version the server implements
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct JsonApiInfo {
    pub version: Option<String>,
    pub meta: Option<Meta>,
}

/// Pagination links
#[derive(Serialize, Deserialize, Debug)]
pub struct Pagination {
    pub first: Option<String>,
    pub prev: Option<String>,
    pub next: Option<String>,
    pub last: Option<String>,
}

#[derive(Debug)]
pub struct Patch {
    pub patch_type: PatchType,
    pub subject: String,
    pub previous: JsonApiValue,
    pub next: JsonApiValue,
}

#[derive(Debug)]
pub struct PatchSet {
    pub resource_type: String,
    pub resource_id: String,
    pub patches: Vec<Patch>,
}

impl PatchSet {
    pub fn new_for(resource: &Resource) -> Self {
        PatchSet {
            resource_type: resource._type.clone(),
            resource_id: resource.id.clone(),
            patches: Vec::<Patch>::new(),
        }
    }

    pub fn push(&mut self, patch: Patch) -> () {
        self.patches.push(patch);
    }
}

/// Top-level JSON-API Document
impl JsonApiDocument {
    fn has_errors(&self) -> bool {
        !self.errors.is_none()
    }
    fn has_meta(&self) -> bool {
        !self.errors.is_none()
    }
    fn has_included(&self) -> bool {
        !self.included.is_none()
    }
    fn has_data(&self) -> bool {
        !self.data.is_none()
    }
    /// This function returns `false` if the `JsonApiDocument` contains any violations of the
    /// specification. See `DocumentValidationError`
    ///
    /// The spec dictates that the document must have least one of `data`, `errors` or `meta`.
    /// Of these, `data` and `errors` must not co-exist.
    /// The optional field `included` may only be present if the `data` field is present too.
    ///
    /// ```
    /// use jsonapi::api::{JsonApiDocument, PrimaryData, JsonApiErrors};
    /// let doc = JsonApiDocument {
    ///     data: Some(PrimaryData::None),
    ///     errors: Some(JsonApiErrors::new()),
    ///     meta: None,
    ///     included: None,
    ///     links: None,
    ///     jsonapi: None,
    /// };
    ///
    /// assert_eq!(doc.is_valid(), false);
    /// ```
    pub fn is_valid(&self) -> bool {
        match self.validate() {
            Some(_) => false,
            None => true,
        }
    }

    /// This function returns a `Vec` with identified specification violations enumerated in
    /// `DocumentValidationError`
    ///
    /// ```
    /// use jsonapi::api::{JsonApiDocument, PrimaryData, JsonApiErrors, DocumentValidationError};
    ///
    /// let doc = JsonApiDocument {
    ///     data: Some(PrimaryData::None),
    ///     errors: Some(JsonApiErrors::new()),
    ///     meta: None,
    ///     included: None,
    ///     links: None,
    ///     jsonapi: None,
    /// };
    ///
    /// match doc.validate() {
    ///   Some(errors) => {
    ///     assert!(
    ///       errors.contains(
    ///         &DocumentValidationError::DataWithErrors
    ///       )
    ///     )
    ///   }
    ///   None => assert!(false)
    /// }
    /// ```
    pub fn validate(&self) -> Option<Vec<DocumentValidationError>> {

        let mut errors = Vec::<DocumentValidationError>::new();

        if self.has_data() && self.has_errors() {
            errors.push(DocumentValidationError::DataWithErrors);
        }

        if self.has_included() && !self.has_data() {
            errors.push(DocumentValidationError::IncludedWithoutData);
        }

        if !(self.has_data() || self.has_meta() || self.has_errors()) {
            errors.push(DocumentValidationError::MissingContent);
        }

        match errors.len() {
            0 => None,
            _ => Some(errors),
        }

    }

    /// Instantiate from string
    ///
    /// ```
    /// use jsonapi::api::JsonApiDocument;
    ///
    /// let serialized = r#"{
    ///   "data" : [
    ///     { "id":"1", "type":"post", "attributes":{}, "relationships":{}, "links" :{} },
    ///     { "id":"2", "type":"post", "attributes":{}, "relationships":{}, "links" :{} },
    ///     { "id":"3", "type":"post", "attributes":{}, "relationships":{}, "links" :{} }
    ///   ]
    /// }"#;
    /// let doc = JsonApiDocument::from_str(&serialized);
    /// assert_eq!(doc.is_ok(), true);
    /// ```
    pub fn from_str(s: &str) -> Result<Self, serde_json::Error> {
        serde_json::from_str(s)
    }
}

impl Resource {
    /// Instantiate from string
    ///
    /// ```
    /// use jsonapi::api::Resource;
    ///
    /// let serialized = r#"{
    ///   "id":"1",
    ///   "type":"post",
    ///   "attributes":{
    ///     "title": "Rails is Omakase",
    ///     "likes": 250
    ///   },
    ///   "relationships":{},
    ///   "links" :{}
    /// }"#;
    ///
    /// let data = Resource::from_str(&serialized);
    /// assert_eq!(data.is_ok(), true);
    /// ```
    pub fn from_str(s: &str) -> Result<Self, serde_json::Error> {
        serde_json::from_str(s)
    }

    pub fn get_relationship(&self, name: &str) -> Option<&Relationship> {
        match self.relationships {
            None => None,
            Some(ref relationships) => {
                match relationships.get(name) {
                    None => None,
                    Some(rel) => Some(rel),
                }
            }
        }
    }

    /// Get an attribute `JsonApiValue`
    ///
    /// ```
    /// use jsonapi::api::Resource;
    ///
    /// let serialized = r#"{
    ///   "id":"1",
    ///   "type":"post",
    ///   "attributes":{
    ///     "title": "Rails is Omakase",
    ///     "likes": 250
    ///   },
    ///   "relationships":{},
    ///   "links" :{}
    /// }"#;
    ///
    /// match Resource::from_str(&serialized) {
    ///   Err(_)=> assert!(false),
    ///   Ok(resource)=> {
    ///     match resource.get_attribute("title") {
    ///       None => assert!(false),
    ///       Some(attr) => {
    ///         match attr.as_str() {
    ///           None => assert!(false),
    ///           Some(s) => {
    ///               assert_eq!(s, "Rails is Omakase");
    ///           }
    ///         }
    ///       }
    ///     }
    ///   }
    /// }
    pub fn get_attribute(&self, name: &str) -> Option<&JsonApiValue> {
        match self.attributes.get(name) {
            None => None,
            Some(val) => Some(val),
        }
    }

    pub fn diff(&self, other: Resource) -> Result<PatchSet, DiffPatchError> {
        if self._type != other._type {
            Err(DiffPatchError::IncompatibleTypes(self._type.clone(), other._type.clone()))
        } else {

            let mut self_keys: Vec<String> =
                self.attributes.iter().map(|(key, _)| key.clone()).collect();

            self_keys.sort();

            let mut other_keys: Vec<String> =
                other.attributes.iter().map(|(key, _)| key.clone()).collect();

            other_keys.sort();

            let matching = self_keys.iter().zip(other_keys.iter()).filter(|&(a, b)| a == b).count();

            if matching != self_keys.len() {
                Err(DiffPatchError::DifferentAttributeKeys)
            } else {
                let mut patchset = PatchSet::new_for(self);

                for (attr, self_value) in &self.attributes {
                    match other.attributes.get(attr) {
                        None => {
                            error!("Resource::diff unable to find attribute {:?} in {:?}",
                                   attr,
                                   other);
                        }
                        Some(other_value) => {
                            if self_value.to_string() != other_value.to_string() {
                                patchset.push(Patch {
                                    patch_type: PatchType::Attribute,
                                    subject: attr.clone(),
                                    previous: self_value.clone(),
                                    next: other_value.clone(),
                                });
                            }
                        }
                    }

                }

                Ok(patchset)
            }
        }
    }

    pub fn patch(&mut self, patchset: PatchSet) -> Result<Resource, DiffPatchError> {
        let mut res = self.clone();
        for patch in &patchset.patches {
            res.attributes.insert(patch.subject.clone(), patch.next.clone());
        }
        Ok(res)
    }
}

impl Relationship {
    pub fn as_id(&self) -> Result<Option<&JsonApiId>, RelationshipAssumptionError> {
        match self.data {
            IdentifierData::None => Ok(None),
            IdentifierData::Multiple(_) => Err(RelationshipAssumptionError::RelationshipIsAList),
            IdentifierData::Single(ref data) => Ok(Some(&data.id)),
        }
    }

    pub fn as_ids(&self) -> Result<Option<JsonApiIds>, RelationshipAssumptionError> {
        match self.data {
            IdentifierData::None => Ok(None),
            IdentifierData::Single(_) => Err(RelationshipAssumptionError::RelationshipIsNotAList),
            IdentifierData::Multiple(ref data) => Ok(Some(data.iter().map(|x| &x.id).collect())),
        }
    }
}

/// Top-level (Document) JSON-API specification violations
#[derive(Debug, Clone, PartialEq, Copy)]
pub enum DocumentValidationError {
    IncludedWithoutData,
    DataWithErrors,
    MissingContent,
}

#[derive(Debug, Clone, PartialEq, Copy)]
pub enum JsonApiDataError {
    AttributeNotFound,
    IncompatibleAttributeType,
}

#[derive(Debug, Clone, PartialEq, Copy)]
pub enum RelationshipAssumptionError {
    RelationshipIsAList,
    RelationshipIsNotAList,
}

#[derive(Debug, Clone, PartialEq)]
pub enum DiffPatchError {
    IncompatibleTypes(String, String),
    DifferentAttributeKeys,
    NonExistentProperty(String),
    IncorrectPropertyValue(String),
}

#[derive(Debug, Clone, PartialEq, Copy)]
pub enum PatchType {
    Relationship,
    Attribute,
}
<|endoftext|>


<commit_before><commit_msg>Use unboxed keys<commit_after><|endoftext|>


<commit_before>// CITA
// Copyright 2016-2017 Cryptape Technologies LLC.

// 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/>.

use libc::{c_char, c_int, size_t};
use std::fmt;

const SNAPPY_OK: c_int = 0;
const SNAPPY_INVALID_INPUT: c_int = 1;
const SNAPPY_BUFFER_TOO_SMALL: c_int = 2;
#[link(name = "snappy")]
extern "C" {
    fn snappy_compress(input: *const c_char, input_len: size_t, compressed: *mut c_char, compressed_len: *mut size_t) -> c_int;

    fn snappy_max_compressed_length(source_len: size_t) -> size_t;

    fn snappy_uncompress(compressed: *const c_char, compressed_len: size_t, uncompressed: *mut c_char, uncompressed_len: *mut size_t) -> c_int;

    fn snappy_uncompressed_length(compressed: *const c_char, compressed_len: size_t, result: *mut size_t) -> c_int;

    fn snappy_validate_compressed_buffer(compressed: *const c_char, compressed_len: size_t) -> c_int;
}

/// Attempted to decompress an uncompressed buffer.
#[derive(Debug)]
pub struct InvalidInput;

impl fmt::Display for InvalidInput {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Attempted snappy decompression with invalid input")
    }
}

/// The maximum compressed length given a size.
pub fn max_compressed_len(len: usize) -> usize {
    unsafe { snappy_max_compressed_length(len as size_t) as usize }
}

/// How large the given data will be when decompressed.
pub fn decompressed_len(compressed: &[u8]) -> Result<usize, InvalidInput> {
    let mut size: size_t = 0;
    let len = compressed.len() as size_t;
    let status = unsafe { snappy_uncompressed_length(compressed.as_ptr() as *const c_char, len, &mut size) };
    if status == SNAPPY_INVALID_INPUT { Err(InvalidInput) } else { Ok(size) }
}

/// Compress a buffer using snappy.
pub fn compress(input: &[u8]) -> Vec<u8> {
    //let buf = Vec::from(input);
    info!("---compress-before size = {}--", input.len());
    let mut buf = Vec::new();
    compress_into(input, &mut buf);
    info!("---compress-after size = {}--", buf.len());
    buf

}

/// Compress a buffer using snappy, writing the result into
/// the given output buffer, growing it if necessary.
/// Otherwise, returns the length of the compressed data.
pub fn compress_into(input: &[u8], output: &mut Vec<u8>) -> usize {
    let mut len = max_compressed_len(input.len());
    if output.len() < len {
        output.resize(len, 0);
    }
    let status = unsafe { snappy_compress(input.as_ptr() as *const c_char, input.len() as size_t, output.as_mut_ptr() as *mut c_char, &mut len as &mut size_t) };
    match status {
        SNAPPY_OK => unsafe {
            output.set_len(len);
            len as usize
        },
        SNAPPY_INVALID_INPUT => panic!("snappy compression has no concept of invalid input"),
        SNAPPY_BUFFER_TOO_SMALL => {
            panic!("buffer cannot be too small, the capacity was just ensured.")
        }
        _ => panic!("snappy returned unspecified status"),
    }
}

/// Decompress a buffer using snappy. Will return an error if the buffer is not snappy-compressed.
pub fn decompress(input: &[u8]) -> Result<Vec<u8>, InvalidInput> {
    //let buf = Vec::from(input);
    //Ok(buf)
    let mut v = Vec::new();
    decompress_into(input, &mut v).map(|_| v)

}

/// Decompress a buffer using snappy, writing the result into
/// the given output buffer, growing it if necessary.
/// Will error if the input buffer is not snappy-compressed.
/// Otherwise, returns the length of the decompressed data.
pub fn decompress_into(input: &[u8], output: &mut Vec<u8>) -> Result<usize, InvalidInput> {
    let mut len = decompressed_len(input)?;
    if output.len() < len {
        output.resize(len, 0);
    }
    let status = unsafe { snappy_uncompress(input.as_ptr() as *const c_char, input.len() as size_t, output.as_mut_ptr() as *mut c_char, &mut len as &mut size_t) };

    match status {
        SNAPPY_OK => Ok(len as usize),
        SNAPPY_INVALID_INPUT => Err(InvalidInput),
        SNAPPY_BUFFER_TOO_SMALL => {
            panic!("buffer cannot be too small, size was just set to large enough.")
        }
        _ => panic!("snappy returned unspecified status"),
    }
}

/// Validate a compressed buffer. True if valid, false if not.
pub fn validate_compressed_buffer(input: &[u8]) -> bool {
    let status = unsafe { snappy_validate_compressed_buffer(input.as_ptr() as *const c_char, input.len() as size_t) };
    status == SNAPPY_OK
}

const CITA_COMPRESS_SIZE: usize = 4 * 1024;
pub fn cita_compresse(input: Vec<u8>) -> Vec<u8> {
    if input.len() > CITA_COMPRESS_SIZE { compress(&input) } else { input }
}

pub fn cita_decompress(input: Vec<u8>) -> Vec<u8> {
    if validate_compressed_buffer(&input) {
        match decompress(&input) {
            Ok(data) => data,
            Err(_) => input,
        }
    } else {
        input
    }
}

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

    #[test]
    fn valid() {
        let d = vec![0xde, 0xad, 0xd0, 0x0d];
        let cd = compress(&d);
        assert!(validate_compressed_buffer(&cd));
        let dd = decompress(&cd).unwrap();
        assert!(&d == &dd);
    }

    #[test]
    #[should_panic(expected = "InvalidInput")]
    fn invalid() {
        let d = vec![0, 0, 0, 0];
        assert!(!validate_compressed_buffer(&d));
        decompress(&d).unwrap();
    }

    #[test]
    #[should_panic(expected = "InvalidInput")]
    fn empty() {
        let d = vec![];
        assert!(!validate_compressed_buffer(&d));
        decompress(&d).unwrap();
    }

    #[test]
    fn empty_compress() {
        let d = vec![];
        let cd = compress(&d);
        assert!(validate_compressed_buffer(&cd));
        let dd = decompress(&cd).unwrap();
        assert!(&d == &dd);
    }
}
<commit_msg>optmize compress<commit_after>// CITA
// Copyright 2016-2017 Cryptape Technologies LLC.

// 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/>.

use libc::{c_char, c_int, size_t};
use std::fmt;

const SNAPPY_OK: c_int = 0;
const SNAPPY_INVALID_INPUT: c_int = 1;
const SNAPPY_BUFFER_TOO_SMALL: c_int = 2;
#[link(name = "snappy")]
extern "C" {
    fn snappy_compress(input: *const c_char, input_len: size_t, compressed: *mut c_char, compressed_len: *mut size_t) -> c_int;

    fn snappy_max_compressed_length(source_len: size_t) -> size_t;

    fn snappy_uncompress(compressed: *const c_char, compressed_len: size_t, uncompressed: *mut c_char, uncompressed_len: *mut size_t) -> c_int;

    fn snappy_uncompressed_length(compressed: *const c_char, compressed_len: size_t, result: *mut size_t) -> c_int;

    fn snappy_validate_compressed_buffer(compressed: *const c_char, compressed_len: size_t) -> c_int;
}

/// Attempted to decompress an uncompressed buffer.
#[derive(Debug)]
pub struct InvalidInput;

impl fmt::Display for InvalidInput {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Attempted snappy decompression with invalid input")
    }
}

/// The maximum compressed length given a size.
pub fn max_compressed_len(len: usize) -> usize {
    unsafe { snappy_max_compressed_length(len as size_t) as usize }
}

/// How large the given data will be when decompressed.
pub fn decompressed_len(compressed: &[u8]) -> Result<usize, InvalidInput> {
    let mut size: size_t = 0;
    let len = compressed.len() as size_t;
    let status = unsafe { snappy_uncompressed_length(compressed.as_ptr() as *const c_char, len, &mut size) };
    if status == SNAPPY_INVALID_INPUT { Err(InvalidInput) } else { Ok(size) }
}

/// Compress a buffer using snappy.
pub fn compress(input: &[u8]) -> Vec<u8> {
    //let buf = Vec::from(input);
    trace!("---compress-before size = {}--", input.len());
    let mut buf = Vec::new();
    compress_into(input, &mut buf);
    trace!("---compress-after size = {}--", buf.len());
    buf

}

/// Compress a buffer using snappy, writing the result into
/// the given output buffer, growing it if necessary.
/// Otherwise, returns the length of the compressed data.
pub fn compress_into(input: &[u8], output: &mut Vec<u8>) -> usize {
    let mut len = max_compressed_len(input.len());
    if output.len() < len {
        output.resize(len, 0);
    }
    let status = unsafe { snappy_compress(input.as_ptr() as *const c_char, input.len() as size_t, output.as_mut_ptr() as *mut c_char, &mut len as &mut size_t) };
    match status {
        SNAPPY_OK => unsafe {
            output.set_len(len);
            len as usize
        },
        SNAPPY_INVALID_INPUT => panic!("snappy compression has no concept of invalid input"),
        SNAPPY_BUFFER_TOO_SMALL => {
            panic!("buffer cannot be too small, the capacity was just ensured.")
        }
        _ => panic!("snappy returned unspecified status"),
    }
}

/// Decompress a buffer using snappy. Will return an error if the buffer is not snappy-compressed.
pub fn decompress(input: &[u8]) -> Result<Vec<u8>, InvalidInput> {
    //let buf = Vec::from(input);
    //Ok(buf)
    let mut v = Vec::new();
    decompress_into(input, &mut v).map(|_| v)

}

/// Decompress a buffer using snappy, writing the result into
/// the given output buffer, growing it if necessary.
/// Will error if the input buffer is not snappy-compressed.
/// Otherwise, returns the length of the decompressed data.
pub fn decompress_into(input: &[u8], output: &mut Vec<u8>) -> Result<usize, InvalidInput> {
    let mut len = decompressed_len(input)?;
    if output.len() < len {
        output.resize(len, 0);
    }
    let status = unsafe { snappy_uncompress(input.as_ptr() as *const c_char, input.len() as size_t, output.as_mut_ptr() as *mut c_char, &mut len as &mut size_t) };

    match status {
        SNAPPY_OK => Ok(len as usize),
        SNAPPY_INVALID_INPUT => Err(InvalidInput),
        SNAPPY_BUFFER_TOO_SMALL => {
            panic!("buffer cannot be too small, size was just set to large enough.")
        }
        _ => panic!("snappy returned unspecified status"),
    }
}

/// Validate a compressed buffer. True if valid, false if not.
pub fn validate_compressed_buffer(input: &[u8]) -> bool {
    let status = unsafe { snappy_validate_compressed_buffer(input.as_ptr() as *const c_char, input.len() as size_t) };
    status == SNAPPY_OK
}

const CITA_COMPRESS_SIZE: usize = 40 * 1024;
pub fn cita_compresse(input: Vec<u8>) -> Vec<u8> {
    if input.len() > CITA_COMPRESS_SIZE { compress(&input) } else { input }
}

pub fn cita_decompress(input: Vec<u8>) -> Vec<u8> {
    if validate_compressed_buffer(&input) {
        match decompress(&input) {
            Ok(data) => data,
            Err(_) => input,
        }
    } else {
        input
    }
}

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

    #[test]
    fn valid() {
        let d = vec![0xde, 0xad, 0xd0, 0x0d];
        let cd = compress(&d);
        assert!(validate_compressed_buffer(&cd));
        let dd = decompress(&cd).unwrap();
        assert!(&d == &dd);
    }

    #[test]
    #[should_panic(expected = "InvalidInput")]
    fn invalid() {
        let d = vec![0, 0, 0, 0];
        assert!(!validate_compressed_buffer(&d));
        decompress(&d).unwrap();
    }

    #[test]
    #[should_panic(expected = "InvalidInput")]
    fn empty() {
        let d = vec![];
        assert!(!validate_compressed_buffer(&d));
        decompress(&d).unwrap();
    }

    #[test]
    fn empty_compress() {
        let d = vec![];
        let cd = compress(&d);
        assert!(validate_compressed_buffer(&cd));
        let dd = decompress(&cd).unwrap();
        assert!(&d == &dd);
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate test;
extern crate rmp as msgpack;

use test::Bencher;

use msgpack::decode::*;

#[bench]
fn from_string_read_str(b: &mut Bencher) {
    // Lorem ipsum dolor sit amet.
    let buf = [
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73,
        0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73,
        0x69, 0x74, 0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e
    ];

    let mut out = [0u8; 32];

    b.iter(|| {
        let res = read_str(&mut &buf[..], &mut out[..]).unwrap();
        test::black_box(res);
    });
}

#[bench]
fn from_string_read_value(b: &mut Bencher) {
    // Lorem ipsum dolor sit amet.
    let buf = [
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e
    ];

    b.iter(|| {
        let res = read_value(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
}

#[bench]
fn from_string_read_value_ref(b: &mut Bencher) {
    // Lorem ipsum dolor sit amet.
    let buf = [
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e
    ];

    b.iter(|| {
        let res = read_value_ref(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
}

#[bench]
fn from_complex_read_value(b: &mut Bencher) {
    let buf = [
        0x95, // Fixed array with 5 len.
        0xc0, // Nil.
        0x2a, // 42.
        0xcb, 0x40, 0x9, 0x21, 0xca, 0xc0, 0x83, 0x12, 0x6f, // 3.1415
        // Fixed string with "Lorem ipsum dolor sit amet." content.
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e,
        0x81, // Fixed map with 1 len.
        0xa3, 0x6b, 0x65, 0x79, // Key "key".
        0xa5, 0x76, 0x61, 0x6c, 0x75, 0x65 // Value: "value".
    ];

    b.iter(|| {
        let res = read_value(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
}

#[bench]
fn from_complex_read_value_ref(b: &mut Bencher) {
    let buf = [
        0x95, // Fixed array with 5 len.
        0xc0, // Nil.
        0x2a, // 42.
        0xcb, 0x40, 0x9, 0x21, 0xca, 0xc0, 0x83, 0x12, 0x6f, // 3.1415
        // Fixed string with "Lorem ipsum dolor sit amet." content.
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e,
        0x81, // Fixed map with 1 len.
        0xa3, 0x6b, 0x65, 0x79, // Key "key".
        0xa5, 0x76, 0x61, 0x6c, 0x75, 0x65 // Value: "value".
    ];

    b.iter(|| {
        let res = read_value_ref(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
    b.bytes = buf.len() as u64;
}
}

#[bench]
fn from_complex_read_value_ref_to_owned(b: &mut Bencher) {
    let buf = [
        0x95, // Fixed array with 5 len.
        0xc0, // Nil.
        0x2a, // 42.
        0xcb, 0x40, 0x9, 0x21, 0xca, 0xc0, 0x83, 0x12, 0x6f, // 3.1415
        // Fixed string with "Lorem ipsum dolor sit amet." content.
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e,
        0x81, // Fixed map with 1 len.
        0xa3, 0x6b, 0x65, 0x79, // Key "key".
        0xa5, 0x76, 0x61, 0x6c, 0x75, 0x65 // Value: "value".
    ];

    b.iter(|| {
        let res = read_value_ref(&mut &buf[..]).unwrap().to_owned();
        test::black_box(res);
    });
}

#[bench]
fn from_i64_read_i64_loosely(b: &mut Bencher) {
    let buf = [0xd3, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];

    b.iter(|| {
        let res = read_i64_loosely(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
}

//#[bench]
//fn from_i64_read_integer(b: &mut Bencher) {
//    let buf = [0xd3, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];

//    b.iter(|| {
//        let res = read_integer(&mut &buf[..]).unwrap();
//        test::black_box(res);
//    });
//}

#[bench]
fn from_i8_read_i8(b: &mut Bencher) {
    let buf = [0xd0, 0xff];

    b.iter(|| {
        let res = read_i8(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
}

#[bench]
fn from_u8_read_u64_loosely(b: &mut Bencher) {
    let buf = [0xcc, 0xff];

    b.iter(|| {
        let res = read_u64_loosely(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
}
<commit_msg>Misc(bench): added value ref serialization bench.<commit_after>#![feature(test)]

extern crate test;
extern crate rmp as msgpack;

use test::Bencher;

use msgpack::decode::*;

#[bench]
fn from_string_read_str(b: &mut Bencher) {
    // Lorem ipsum dolor sit amet.
    let buf = [
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73,
        0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73,
        0x69, 0x74, 0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e
    ];

    let mut out = [0u8; 32];

    b.iter(|| {
        let res = read_str(&mut &buf[..], &mut out[..]).unwrap();
        test::black_box(res);
    });
}

#[bench]
fn from_string_read_value(b: &mut Bencher) {
    // Lorem ipsum dolor sit amet.
    let buf = [
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e
    ];

    b.iter(|| {
        let res = read_value(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
}

#[bench]
fn from_string_read_value_ref(b: &mut Bencher) {
    // Lorem ipsum dolor sit amet.
    let buf = [
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e
    ];

    b.iter(|| {
        let res = read_value_ref(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
}

#[bench]
fn from_complex_read_value(b: &mut Bencher) {
    let buf = [
        0x95, // Fixed array with 5 len.
        0xc0, // Nil.
        0x2a, // 42.
        0xcb, 0x40, 0x9, 0x21, 0xca, 0xc0, 0x83, 0x12, 0x6f, // 3.1415
        // Fixed string with "Lorem ipsum dolor sit amet." content.
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e,
        0x81, // Fixed map with 1 len.
        0xa3, 0x6b, 0x65, 0x79, // Key "key".
        0xa5, 0x76, 0x61, 0x6c, 0x75, 0x65 // Value: "value".
    ];

    b.iter(|| {
        let res = read_value(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
}

#[bench]
fn from_complex_read_value_ref(b: &mut Bencher) {
    let buf = [
        0x95, // Fixed array with 5 len.
        0xc0, // Nil.
        0x2a, // 42.
        0xcb, 0x40, 0x9, 0x21, 0xca, 0xc0, 0x83, 0x12, 0x6f, // 3.1415
        // Fixed string with "Lorem ipsum dolor sit amet." content.
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e,
        0x81, // Fixed map with 1 len.
        0xa3, 0x6b, 0x65, 0x79, // Key "key".
        0xa5, 0x76, 0x61, 0x6c, 0x75, 0x65 // Value: "value".
    ];

    b.iter(|| {
        let res = read_value_ref(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
    b.bytes = buf.len() as u64;
}

#[bench]
fn from_complex_write_value_ref(b: &mut Bencher) {
    use msgpack::ValueRef::*;
    use msgpack::value::Float::*;
    use msgpack::value::Integer::*;
    use msgpack::encode::value_ref::write_value_ref;

    let val = Array(vec![Nil, Integer(U64(42)), Float(F64(3.1415)),
        String("Lorem ipsum dolor sit amet."), Map(vec![(String("key"), String("value"))])]);

    let mut buf = [0u8; 64];

    b.iter(|| {
        let res = write_value_ref(&mut &mut buf[..], &val).unwrap();
        test::black_box(res);
    });
    b.bytes = 51;
}

#[bench]
fn from_complex_read_value_ref_to_owned(b: &mut Bencher) {
    let buf = [
        0x95, // Fixed array with 5 len.
        0xc0, // Nil.
        0x2a, // 42.
        0xcb, 0x40, 0x9, 0x21, 0xca, 0xc0, 0x83, 0x12, 0x6f, // 3.1415
        // Fixed string with "Lorem ipsum dolor sit amet." content.
        0xbb, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75,
        0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6d, 0x65, 0x74, 0x2e,
        0x81, // Fixed map with 1 len.
        0xa3, 0x6b, 0x65, 0x79, // Key "key".
        0xa5, 0x76, 0x61, 0x6c, 0x75, 0x65 // Value: "value".
    ];

    b.iter(|| {
        let res = read_value_ref(&mut &buf[..]).unwrap().to_owned();
        test::black_box(res);
    });
}

#[bench]
fn from_i64_read_i64_loosely(b: &mut Bencher) {
    let buf = [0xd3, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];

    b.iter(|| {
        let res = read_i64_loosely(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
}

//#[bench]
//fn from_i64_read_integer(b: &mut Bencher) {
//    let buf = [0xd3, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];

//    b.iter(|| {
//        let res = read_integer(&mut &buf[..]).unwrap();
//        test::black_box(res);
//    });
//}

#[bench]
fn from_i8_read_i8(b: &mut Bencher) {
    let buf = [0xd0, 0xff];

    b.iter(|| {
        let res = read_i8(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
}

#[bench]
fn from_u8_read_u64_loosely(b: &mut Bencher) {
    let buf = [0xcc, 0xff];

    b.iter(|| {
        let res = read_u64_loosely(&mut &buf[..]).unwrap();
        test::black_box(res);
    });
}
<|endoftext|>


<commit_before>use arm::CpuException;

use crate::{
    memory::io::{Interrupt, IoRegisters},
    scheduler::{EventTag, Scheduler},
    Gba,
};

pub fn raise(interrupt: Interrupt, ioregs: &mut IoRegisters, scheduler: &Scheduler) {
    if !ioregs.ime.enabled() || !ioregs.ie_reg.enabled(interrupt) {
        return;
    }

    if !ioregs.irq_pending.has_requests() {
        scheduler.schedule(process_irq, 0, EventTag::IRQ);
    }
    ioregs.irq_pending.request(interrupt);
}

fn process_irq(gba: &mut Gba, _late: arm::Cycles) {
    let pending = gba.mem.ioregs.irq_pending;
    gba.mem.ioregs.irq_pending.clear();

    // If IRQs are disabled by the CPU itself, we just clear the pending IRQs and get out of here.
    if gba.cpu.registers.getf_i() {
        return;
    }

    gba.mem.ioregs.if_reg.inherit(pending);
    gba.cpu.exception(CpuException::IRQ, &mut gba.mem);
}
<commit_msg>Remove unnecessary comment.<commit_after>use arm::CpuException;

use crate::{
    memory::io::{Interrupt, IoRegisters},
    scheduler::{EventTag, Scheduler},
    Gba,
};

pub fn raise(interrupt: Interrupt, ioregs: &mut IoRegisters, scheduler: &Scheduler) {
    if !ioregs.ime.enabled() || !ioregs.ie_reg.enabled(interrupt) {
        return;
    }

    if !ioregs.irq_pending.has_requests() {
        scheduler.schedule(process_irq, 0, EventTag::IRQ);
    }
    ioregs.irq_pending.request(interrupt);
}

fn process_irq(gba: &mut Gba, _late: arm::Cycles) {
    let pending = gba.mem.ioregs.irq_pending;
    gba.mem.ioregs.irq_pending.clear();

    if gba.cpu.registers.getf_i() {
        return;
    }

    gba.mem.ioregs.if_reg.inherit(pending);
    gba.cpu.exception(CpuException::IRQ, &mut gba.mem);
}
<|endoftext|>


<commit_before>// http://rosettacode.org/wiki/Gaussian_elimination
#![allow(unused_variables)]
#![allow(dead_code)]

struct Matrix<'a, T:'a> {
	m : &'a Vec<T>,
	n : usize
}

struct MatrixRowIter<'a, T:'a> {
	m : &'a Matrix<'a, T>,
	row : usize,
	col : usize
}

struct Idx(usize, usize);

impl<'a, T> Matrix<'a, T> {
	fn new (_m : &'a Vec<T>, _n : usize) -> Matrix<'a, T> {
		Matrix{m : _m, n : _n}
	}

	fn val(&self, idx : Idx) -> &T
	{
		& self.m[idx.0 + idx.1 * self.n]
	}
}

impl<'a, T> MatrixRowIter<'a, T> {
	fn new (_m : &'a Matrix<'a, T>, _col : usize) -> MatrixRowIter<'a, T> {
		MatrixRowIter{m : _m, row : 0, col : _col}
	}

}

impl<'a, T:Copy> Iterator for MatrixRowIter<'a, T> {
    type Item = T;
    fn next(&mut self) -> Option<T> {
    	if self.row >= self.m.n {
    	  return None
    	}
    	let v = *self.m.val(Idx(self.col, self.row));
    	self.row += 1;
      Some(v)
    }
}

fn main() {

	let v : Vec<f32> = vec![
		1.00, 0.00, 0.00,  0.00,  0.00, 0.00,
		1.00, 0.63, 0.39,  0.25,  0.16, 0.10,
		1.00, 1.26, 1.58,  1.98,  2.49, 3.13,
		1.00, 1.88, 3.55,  6.70, 12.62, 23.80,
		1.00, 2.51, 6.32, 15.88, 39.90, 100.28,
		1.00, 3.14, 9.87, 31.01, 97.41, 306.02];

	let mat = Matrix::new(&v, 6);
	let mat_iter = MatrixRowIter::new(&mat, 5);

	let mat_iter_print = &mat_iter;
	{
		for v in *mat_iter_print
		{
			println!("{}", v);
		}
	}

	let max = mat_iter.fold(0.0f32, |max, item| { max.max(item.abs()) } );
	println!("{}", max);
}
<commit_msg>sort completed<commit_after>// http://rosettacode.org/wiki/Gaussian_elimination
#![allow(unused_variables)]
#![allow(dead_code)]

struct Matrix<'a, T:'a> {
	m : &'a Vec<T>,
	n : usize
}

struct Idx(usize, usize);

impl<'a, T> Matrix<'a, T> {
	fn new (_m : &'a Vec<T>, _n : usize) -> Matrix<'a, T> {
		Matrix{m : _m, n : _n}
	}

	fn val(&self, idx : Idx) -> &T
	{
		& self.m[idx.0 + idx.1 * self.n]
	}

	fn get_row_slice(&self, row: usize) -> &[T]
	{
	  & self.m[row * self.n .. row * self.n + self.n ]
	}
}

struct MatrixRowIter<'a, T:'a> {
	m : &'a Matrix<'a, T>,
	row : usize,
	col : usize,
	used: &'a Vec<bool>
}

impl<'a, T> MatrixRowIter<'a, T> {
	fn new (_m : &'a Matrix<'a, T>, _used: &'a mut Vec<bool>, _col : usize) -> MatrixRowIter<'a, T> {
		MatrixRowIter{m : _m, row : 0, col : _col, used : _used }
	}

}

impl<'a, T:Copy> Iterator for MatrixRowIter<'a, T> {
    type Item = (T, usize);
    fn next(&mut self) -> Option<(T, usize)> {
    	loop {
	    	if self.row >= self.m.n {
	    	  return None
	    	}
	    	if !self.used[self.row] {
	    		break;
	    	}
    		self.row += 1;
    	}

    	let v = *self.m.val(Idx(self.col, self.row));
    	let ret = self.row;
    	self.row += 1;
      Some((v, ret))
    }
}

fn main() {

	let v : Vec<f32> = vec![
		1.00, 0.00, 0.00,  0.00,  0.00, 0.00,
		1.00, 0.63, 0.39,  0.25,  0.16, 0.10,
		1.00, 1.26, 1.58,  1.98,  2.49, 3.13,
		1.00, 1.88, 3.55,  6.70, 12.62, 230.80,
		1.00, 2.51, 6.32, 15.88, 39.90, 100.28,
		1.00, 3.14, 9.87, 31.01, 97.41, 306.02];

	let mat = Matrix::new(&v, 6);

	let mut r = Vec::new();
	let mut used: Vec<bool> = vec![false; mat.n];

	for i in 0..mat.n {

		let max;
		{
			let mat_iter = MatrixRowIter::new(&mat, &mut used, i);

			max = mat_iter
										.inspect(|&item| println!("{} {}", item.0, item.1) )
										.fold((0.0, -1),
											|max, item| if item.0.abs() > max.0 { item } else { max } )
										;
		}

		used[max.1] = true;
		println!("max {} {}", max.0, max.1);
		println!("=======");

		r.extend(mat.get_row_slice(max.1).iter());
	}

	let mat_out = Matrix::new(&r, mat.n);
	for i in 0..mat_out.n {
		for j in 0..mat_out.n {
			print!("{} ", mat_out.val(Idx(j, i)));
		}
		println!("  ");
	}

}
<|endoftext|>


<commit_before>extern crate reqwest;

#[macro_use]
mod support;

#[test]
fn test_redirect_301_and_302_and_303_changes_post_to_get() {
    let client = reqwest::Client::new().unwrap();
    let codes = [301, 302, 303];

    for code in codes.iter() {
        let redirect = server! {
            request: format!("\
                POST /{} HTTP/1.1\r\n\
                Host: $HOST\r\n\
                User-Agent: $USERAGENT\r\n\
                Accept: */*\r\n\
                Accept-Encoding: gzip\r\n\
                Content-Length: 0\r\n\
                \r\n\
                ", code),
            response: format!("\
                HTTP/1.1 {} reason\r\n\
                Server: test-redirect\r\n\
                Content-Length: 0\r\n\
                Location: /dst\r\n\
                Connection: close\r\n\
                \r\n\
                ", code),

            request: format!("\
                GET /dst HTTP/1.1\r\n\
                Host: $HOST\r\n\
                User-Agent: $USERAGENT\r\n\
                Accept: */*\r\n\
                Accept-Encoding: gzip\r\n\
                Referer: http://$HOST/{}\r\n\
                \r\n\
                ", code),
            response: b"\
                HTTP/1.1 200 OK\r\n\
                Server: test-dst\r\n\
                Content-Length: 0\r\n\
                \r\n\
                "
        };

        let url = format!("http://{}/{}", redirect.addr(), code);
        let dst = format!("http://{}/{}", redirect.addr(), "dst");
        let res = client.post(&url)
            .unwrap()
            .send()
            .unwrap();
        assert_eq!(res.url().as_str(), dst);
        assert_eq!(res.status(), reqwest::StatusCode::Ok);
        assert_eq!(res.headers().get(),
                   Some(&reqwest::header::Server::new("test-dst".to_string())));
    }
}

#[test]
fn test_redirect_307_and_308_tries_to_get_again() {
    let client = reqwest::Client::new().unwrap();
    let codes = [307, 308];
    for code in codes.iter() {
        let redirect = server! {
            request: format!("\
                GET /{} HTTP/1.1\r\n\
                Host: $HOST\r\n\
                User-Agent: $USERAGENT\r\n\
                Accept: */*\r\n\
                Accept-Encoding: gzip\r\n\
                \r\n\
                ", code),
            response: format!("\
                HTTP/1.1 {} reason\r\n\
                Server: test-redirect\r\n\
                Content-Length: 0\r\n\
                Location: /dst\r\n\
                Connection: close\r\n\
                \r\n\
                ", code),

            request: format!("\
                GET /dst HTTP/1.1\r\n\
                Host: $HOST\r\n\
                User-Agent: $USERAGENT\r\n\
                Accept: */*\r\n\
                Accept-Encoding: gzip\r\n\
                Referer: http://$HOST/{}\r\n\
                \r\n\
                ", code),
            response: b"\
                HTTP/1.1 200 OK\r\n\
                Server: test-dst\r\n\
                Content-Length: 0\r\n\
                \r\n\
                "
        };

        let url = format!("http://{}/{}", redirect.addr(), code);
        let dst = format!("http://{}/{}", redirect.addr(), "dst");
        let res = client.get(&url)
            .unwrap()
            .send()
            .unwrap();
        assert_eq!(res.url().as_str(), dst);
        assert_eq!(res.status(), reqwest::StatusCode::Ok);
        assert_eq!(res.headers().get(),
                   Some(&reqwest::header::Server::new("test-dst".to_string())));
    }
}

#[test]
fn test_redirect_307_and_308_tries_to_post_again() {
    let client = reqwest::Client::new().unwrap();
    let codes = [307, 308];
    for code in codes.iter() {
        let redirect = server! {
            request: format!("\
                POST /{} HTTP/1.1\r\n\
                Host: $HOST\r\n\
                Content-Length: 5\r\n\
                User-Agent: $USERAGENT\r\n\
                Accept: */*\r\n\
                Accept-Encoding: gzip\r\n\
                \r\n\
                Hello\
                ", code),
            response: format!("\
                HTTP/1.1 {} reason\r\n\
                Server: test-redirect\r\n\
                Content-Length: 0\r\n\
                Location: /dst\r\n\
                Connection: close\r\n\
                \r\n\
                ", code),

            request: format!("\
                POST /dst HTTP/1.1\r\n\
                Host: $HOST\r\n\
                Content-Length: 5\r\n\
                User-Agent: $USERAGENT\r\n\
                Accept: */*\r\n\
                Accept-Encoding: gzip\r\n\
                Referer: http://$HOST/{}\r\n\
                \r\n\
                Hello\
                ", code),
            response: b"\
                HTTP/1.1 200 OK\r\n\
                Server: test-dst\r\n\
                Content-Length: 0\r\n\
                \r\n\
                "
        };

        let url = format!("http://{}/{}", redirect.addr(), code);
        let dst = format!("http://{}/{}", redirect.addr(), "dst");
        let res = client.post(&url)
            .unwrap()
            .body("Hello")
            .send()
            .unwrap();
        assert_eq!(res.url().as_str(), dst);
        assert_eq!(res.status(), reqwest::StatusCode::Ok);
        assert_eq!(res.headers().get(),
                   Some(&reqwest::header::Server::new("test-dst".to_string())));
    }
}

#[test]
fn test_redirect_307_does_not_try_if_reader_cannot_reset() {
    let client = reqwest::Client::new().unwrap();
    let codes = [307, 308];
    for &code in codes.iter() {
        let redirect = server! {
            request: format!("\
                POST /{} HTTP/1.1\r\n\
                Host: $HOST\r\n\
                User-Agent: $USERAGENT\r\n\
                Accept: */*\r\n\
                Accept-Encoding: gzip\r\n\
                Transfer-Encoding: chunked\r\n\
                \r\n\
                5\r\n\
                Hello\r\n\
                0\r\n\r\n\
                ", code),
            response: format!("\
                HTTP/1.1 {} reason\r\n\
                Server: test-redirect\r\n\
                Content-Length: 0\r\n\
                Location: /dst\r\n\
                Connection: close\r\n\
                \r\n\
                ", code)
        };

        let url = format!("http://{}/{}", redirect.addr(), code);
        let res = client
            .post(&url)
            .unwrap()
            .body(reqwest::Body::new(&b"Hello"[..]))
            .send()
            .unwrap();
        assert_eq!(res.url().as_str(), url);
        assert_eq!(res.status(), reqwest::StatusCode::try_from(code).unwrap());
    }
}

#[test]
fn test_redirect_removes_sensitive_headers() {
    let end_server = server! {
        request: b"\
            GET /otherhost HTTP/1.1\r\n\
            Host: $HOST\r\n\
            User-Agent: $USERAGENT\r\n\
            Accept: */*\r\n\
            Accept-Encoding: gzip\r\n\
            \r\n\
            ",
        response: b"\
            HTTP/1.1 200 OK\r\n\
            Server: test\r\n\
            Content-Length: 0\r\n\
            \r\n\
            "
    };

    let mid_server = server! {
        request: b"\
            GET /sensitive HTTP/1.1\r\n\
            Host: $HOST\r\n\
            Cookie: foo=bar\r\n\
            User-Agent: $USERAGENT\r\n\
            Accept: */*\r\n\
            Accept-Encoding: gzip\r\n\
            \r\n\
            ",
        response: format!("\
            HTTP/1.1 302 Found\r\n\
            Server: test\r\n\
            Location: http://{}/otherhost\r\n\
            Content-Length: 0\r\n\
            \r\n\
            ", end_server.addr())
    };

    let mut cookie = reqwest::header::Cookie::new();
    cookie.set("foo", "bar");
    reqwest::Client::builder()
        .unwrap()
        .referer(false)
        .build()
        .unwrap()
        .get(&format!("http://{}/sensitive", mid_server.addr()))
        .unwrap()
        .header(cookie)
        .send()
        .unwrap();
}

#[test]
fn test_redirect_policy_can_return_errors() {
    let server = server! {
        request: b"\
            GET /loop HTTP/1.1\r\n\
            Host: $HOST\r\n\
            User-Agent: $USERAGENT\r\n\
            Accept: */*\r\n\
            Accept-Encoding: gzip\r\n\
            \r\n\
            ",
        response: b"\
            HTTP/1.1 302 Found\r\n\
            Server: test\r\n\
            Location: /loop\r\n\
            Content-Length: 0\r\n\
            \r\n\
            "
    };

    let err = reqwest::get(&format!("http://{}/loop", server.addr())).unwrap_err();
    assert!(err.is_redirect());
}

#[test]
fn test_redirect_policy_can_stop_redirects_without_an_error() {
    let server = server! {
        request: b"\
            GET /no-redirect HTTP/1.1\r\n\
            Host: $HOST\r\n\
            User-Agent: $USERAGENT\r\n\
            Accept: */*\r\n\
            Accept-Encoding: gzip\r\n\
            \r\n\
            ",
        response: b"\
            HTTP/1.1 302 Found\r\n\
            Server: test-dont\r\n\
            Location: /dont\r\n\
            Content-Length: 0\r\n\
            \r\n\
            "
    };

    let url = format!("http://{}/no-redirect", server.addr());

    let res = reqwest::Client::builder()
        .unwrap()
        .redirect(reqwest::RedirectPolicy::none())
        .build()
        .unwrap()
        .get(&url)
        .unwrap()
        .send()
        .unwrap();

    assert_eq!(res.url().as_str(), url);
    assert_eq!(res.status(), reqwest::StatusCode::Found);
    assert_eq!(res.headers().get(),
               Some(&reqwest::header::Server::new("test-dont".to_string())));
}

#[test]
fn test_referer_is_not_set_if_disabled() {
    let server = server! {
        request: b"\
            GET /no-refer HTTP/1.1\r\n\
            Host: $HOST\r\n\
            User-Agent: $USERAGENT\r\n\
            Accept: */*\r\n\
            Accept-Encoding: gzip\r\n\
            \r\n\
            ",
        response: b"\
            HTTP/1.1 302 Found\r\n\
            Server: test-no-referer\r\n\
            Content-Length: 0\r\n\
            Location: /dst\r\n\
            Connection: close\r\n\
            \r\n\
            ",

        request: b"\
            GET /dst HTTP/1.1\r\n\
            Host: $HOST\r\n\
            User-Agent: $USERAGENT\r\n\
            Accept: */*\r\n\
            Accept-Encoding: gzip\r\n\
            \r\n\
            ",
        response: b"\
            HTTP/1.1 200 OK\r\n\
            Server: test-dst\r\n\
            Content-Length: 0\r\n\
            \r\n\
            "
    };
    reqwest::Client::builder().unwrap()
        .referer(false)
        .build().unwrap()
        //client
        .get(&format!("http://{}/no-refer", server.addr()))
        .unwrap()
        .send()
        .unwrap();
}
<commit_msg>fix broken test now that hyper does not include content-length when body is empty<commit_after>extern crate reqwest;

#[macro_use]
mod support;

#[test]
fn test_redirect_301_and_302_and_303_changes_post_to_get() {
    let client = reqwest::Client::new().unwrap();
    let codes = [301, 302, 303];

    for code in codes.iter() {
        let redirect = server! {
            request: format!("\
                POST /{} HTTP/1.1\r\n\
                Host: $HOST\r\n\
                User-Agent: $USERAGENT\r\n\
                Accept: */*\r\n\
                Accept-Encoding: gzip\r\n\
                \r\n\
                ", code),
            response: format!("\
                HTTP/1.1 {} reason\r\n\
                Server: test-redirect\r\n\
                Content-Length: 0\r\n\
                Location: /dst\r\n\
                Connection: close\r\n\
                \r\n\
                ", code),

            request: format!("\
                GET /dst HTTP/1.1\r\n\
                Host: $HOST\r\n\
                User-Agent: $USERAGENT\r\n\
                Accept: */*\r\n\
                Accept-Encoding: gzip\r\n\
                Referer: http://$HOST/{}\r\n\
                \r\n\
                ", code),
            response: b"\
                HTTP/1.1 200 OK\r\n\
                Server: test-dst\r\n\
                Content-Length: 0\r\n\
                \r\n\
                "
        };

        let url = format!("http://{}/{}", redirect.addr(), code);
        let dst = format!("http://{}/{}", redirect.addr(), "dst");
        let res = client.post(&url)
            .unwrap()
            .send()
            .unwrap();
        assert_eq!(res.url().as_str(), dst);
        assert_eq!(res.status(), reqwest::StatusCode::Ok);
        assert_eq!(res.headers().get(),
                   Some(&reqwest::header::Server::new("test-dst".to_string())));
    }
}

#[test]
fn test_redirect_307_and_308_tries_to_get_again() {
    let client = reqwest::Client::new().unwrap();
    let codes = [307, 308];
    for code in codes.iter() {
        let redirect = server! {
            request: format!("\
                GET /{} HTTP/1.1\r\n\
                Host: $HOST\r\n\
                User-Agent: $USERAGENT\r\n\
                Accept: */*\r\n\
                Accept-Encoding: gzip\r\n\
                \r\n\
                ", code),
            response: format!("\
                HTTP/1.1 {} reason\r\n\
                Server: test-redirect\r\n\
                Content-Length: 0\r\n\
                Location: /dst\r\n\
                Connection: close\r\n\
                \r\n\
                ", code),

            request: format!("\
                GET /dst HTTP/1.1\r\n\
                Host: $HOST\r\n\
                User-Agent: $USERAGENT\r\n\
                Accept: */*\r\n\
                Accept-Encoding: gzip\r\n\
                Referer: http://$HOST/{}\r\n\
                \r\n\
                ", code),
            response: b"\
                HTTP/1.1 200 OK\r\n\
                Server: test-dst\r\n\
                Content-Length: 0\r\n\
                \r\n\
                "
        };

        let url = format!("http://{}/{}", redirect.addr(), code);
        let dst = format!("http://{}/{}", redirect.addr(), "dst");
        let res = client.get(&url)
            .unwrap()
            .send()
            .unwrap();
        assert_eq!(res.url().as_str(), dst);
        assert_eq!(res.status(), reqwest::StatusCode::Ok);
        assert_eq!(res.headers().get(),
                   Some(&reqwest::header::Server::new("test-dst".to_string())));
    }
}

#[test]
fn test_redirect_307_and_308_tries_to_post_again() {
    let client = reqwest::Client::new().unwrap();
    let codes = [307, 308];
    for code in codes.iter() {
        let redirect = server! {
            request: format!("\
                POST /{} HTTP/1.1\r\n\
                Host: $HOST\r\n\
                Content-Length: 5\r\n\
                User-Agent: $USERAGENT\r\n\
                Accept: */*\r\n\
                Accept-Encoding: gzip\r\n\
                \r\n\
                Hello\
                ", code),
            response: format!("\
                HTTP/1.1 {} reason\r\n\
                Server: test-redirect\r\n\
                Content-Length: 0\r\n\
                Location: /dst\r\n\
                Connection: close\r\n\
                \r\n\
                ", code),

            request: format!("\
                POST /dst HTTP/1.1\r\n\
                Host: $HOST\r\n\
                Content-Length: 5\r\n\
                User-Agent: $USERAGENT\r\n\
                Accept: */*\r\n\
                Accept-Encoding: gzip\r\n\
                Referer: http://$HOST/{}\r\n\
                \r\n\
                Hello\
                ", code),
            response: b"\
                HTTP/1.1 200 OK\r\n\
                Server: test-dst\r\n\
                Content-Length: 0\r\n\
                \r\n\
                "
        };

        let url = format!("http://{}/{}", redirect.addr(), code);
        let dst = format!("http://{}/{}", redirect.addr(), "dst");
        let res = client.post(&url)
            .unwrap()
            .body("Hello")
            .send()
            .unwrap();
        assert_eq!(res.url().as_str(), dst);
        assert_eq!(res.status(), reqwest::StatusCode::Ok);
        assert_eq!(res.headers().get(),
                   Some(&reqwest::header::Server::new("test-dst".to_string())));
    }
}

#[test]
fn test_redirect_307_does_not_try_if_reader_cannot_reset() {
    let client = reqwest::Client::new().unwrap();
    let codes = [307, 308];
    for &code in codes.iter() {
        let redirect = server! {
            request: format!("\
                POST /{} HTTP/1.1\r\n\
                Host: $HOST\r\n\
                User-Agent: $USERAGENT\r\n\
                Accept: */*\r\n\
                Accept-Encoding: gzip\r\n\
                Transfer-Encoding: chunked\r\n\
                \r\n\
                5\r\n\
                Hello\r\n\
                0\r\n\r\n\
                ", code),
            response: format!("\
                HTTP/1.1 {} reason\r\n\
                Server: test-redirect\r\n\
                Content-Length: 0\r\n\
                Location: /dst\r\n\
                Connection: close\r\n\
                \r\n\
                ", code)
        };

        let url = format!("http://{}/{}", redirect.addr(), code);
        let res = client
            .post(&url)
            .unwrap()
            .body(reqwest::Body::new(&b"Hello"[..]))
            .send()
            .unwrap();
        assert_eq!(res.url().as_str(), url);
        assert_eq!(res.status(), reqwest::StatusCode::try_from(code).unwrap());
    }
}

#[test]
fn test_redirect_removes_sensitive_headers() {
    let end_server = server! {
        request: b"\
            GET /otherhost HTTP/1.1\r\n\
            Host: $HOST\r\n\
            User-Agent: $USERAGENT\r\n\
            Accept: */*\r\n\
            Accept-Encoding: gzip\r\n\
            \r\n\
            ",
        response: b"\
            HTTP/1.1 200 OK\r\n\
            Server: test\r\n\
            Content-Length: 0\r\n\
            \r\n\
            "
    };

    let mid_server = server! {
        request: b"\
            GET /sensitive HTTP/1.1\r\n\
            Host: $HOST\r\n\
            Cookie: foo=bar\r\n\
            User-Agent: $USERAGENT\r\n\
            Accept: */*\r\n\
            Accept-Encoding: gzip\r\n\
            \r\n\
            ",
        response: format!("\
            HTTP/1.1 302 Found\r\n\
            Server: test\r\n\
            Location: http://{}/otherhost\r\n\
            Content-Length: 0\r\n\
            \r\n\
            ", end_server.addr())
    };

    let mut cookie = reqwest::header::Cookie::new();
    cookie.set("foo", "bar");
    reqwest::Client::builder()
        .unwrap()
        .referer(false)
        .build()
        .unwrap()
        .get(&format!("http://{}/sensitive", mid_server.addr()))
        .unwrap()
        .header(cookie)
        .send()
        .unwrap();
}

#[test]
fn test_redirect_policy_can_return_errors() {
    let server = server! {
        request: b"\
            GET /loop HTTP/1.1\r\n\
            Host: $HOST\r\n\
            User-Agent: $USERAGENT\r\n\
            Accept: */*\r\n\
            Accept-Encoding: gzip\r\n\
            \r\n\
            ",
        response: b"\
            HTTP/1.1 302 Found\r\n\
            Server: test\r\n\
            Location: /loop\r\n\
            Content-Length: 0\r\n\
            \r\n\
            "
    };

    let err = reqwest::get(&format!("http://{}/loop", server.addr())).unwrap_err();
    assert!(err.is_redirect());
}

#[test]
fn test_redirect_policy_can_stop_redirects_without_an_error() {
    let server = server! {
        request: b"\
            GET /no-redirect HTTP/1.1\r\n\
            Host: $HOST\r\n\
            User-Agent: $USERAGENT\r\n\
            Accept: */*\r\n\
            Accept-Encoding: gzip\r\n\
            \r\n\
            ",
        response: b"\
            HTTP/1.1 302 Found\r\n\
            Server: test-dont\r\n\
            Location: /dont\r\n\
            Content-Length: 0\r\n\
            \r\n\
            "
    };

    let url = format!("http://{}/no-redirect", server.addr());

    let res = reqwest::Client::builder()
        .unwrap()
        .redirect(reqwest::RedirectPolicy::none())
        .build()
        .unwrap()
        .get(&url)
        .unwrap()
        .send()
        .unwrap();

    assert_eq!(res.url().as_str(), url);
    assert_eq!(res.status(), reqwest::StatusCode::Found);
    assert_eq!(res.headers().get(),
               Some(&reqwest::header::Server::new("test-dont".to_string())));
}

#[test]
fn test_referer_is_not_set_if_disabled() {
    let server = server! {
        request: b"\
            GET /no-refer HTTP/1.1\r\n\
            Host: $HOST\r\n\
            User-Agent: $USERAGENT\r\n\
            Accept: */*\r\n\
            Accept-Encoding: gzip\r\n\
            \r\n\
            ",
        response: b"\
            HTTP/1.1 302 Found\r\n\
            Server: test-no-referer\r\n\
            Content-Length: 0\r\n\
            Location: /dst\r\n\
            Connection: close\r\n\
            \r\n\
            ",

        request: b"\
            GET /dst HTTP/1.1\r\n\
            Host: $HOST\r\n\
            User-Agent: $USERAGENT\r\n\
            Accept: */*\r\n\
            Accept-Encoding: gzip\r\n\
            \r\n\
            ",
        response: b"\
            HTTP/1.1 200 OK\r\n\
            Server: test-dst\r\n\
            Content-Length: 0\r\n\
            \r\n\
            "
    };
    reqwest::Client::builder().unwrap()
        .referer(false)
        .build().unwrap()
        //client
        .get(&format!("http://{}/no-refer", server.addr()))
        .unwrap()
        .send()
        .unwrap();
}
<|endoftext|>


<commit_before>extern crate onmf;
use onmf::helpers::{ToImage};
use onmf::testimage_generator;
use onmf::testimage_generator::{magnify};

extern crate nalgebra;
use self::nalgebra::{DMat};

extern crate rand;
use rand::{StdRng, SeedableRng};

fn main() {
    let mag_factor = 10;

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);

    let steps = 6;
    let per_step = 10;
    let ntimes = steps * per_step;
    let nobserved = 10 * 10;
    let nhidden = 10;
    let niterations = 100;

    let mut data = DMat::<f64>::new_zeros(ntimes, nobserved);

    // write on testimage into each row of data
    for (step, i, factor) in testimage_generator::testimages::<f64, _>(per_step, &mut rng) {
        let row = step * i;
        for (col, val) in factor.as_vec().iter().enumerate() {
            data[(row, col)] = val.clone();
        }
    }

    let nmf = onmf::OrthogonalNMF::<f64>::from_data(
        &data, nhidden, niterations);

    // read testimage out of each row of nmf.hidden
    for irow in 0..nhidden {
        let mut column = Vec::<f64>::new();
        for icol in 0..nobserved {
            column.push(nmf.hidden[(irow, icol)]);
        }
        let image = DMat::<f64>::from_col_vec(10, 10, &column[..]);
        magnify(image, mag_factor).save_to_png(&format!("orthogonal-nmf-hidden-{}.png", irow)[..]).unwrap();

    }
    // for (i, factor) in decomposed_hidden.enumerate() {
    // }
}
<commit_msg>remove dead code<commit_after>extern crate onmf;
use onmf::helpers::{ToImage};
use onmf::testimage_generator;
use onmf::testimage_generator::{magnify};

extern crate nalgebra;
use self::nalgebra::{DMat};

extern crate rand;
use rand::{StdRng, SeedableRng};

fn main() {
    let mag_factor = 10;

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);

    let steps = 6;
    let per_step = 10;
    let ntimes = steps * per_step;
    let nobserved = 10 * 10;
    let nhidden = 10;
    let niterations = 100;

    let mut data = DMat::<f64>::new_zeros(ntimes, nobserved);

    // write on testimage into each row of data
    for (step, i, factor) in testimage_generator::testimages::<f64, _>(per_step, &mut rng) {
        let row = step * i;
        for (col, val) in factor.as_vec().iter().enumerate() {
            data[(row, col)] = val.clone();
        }
    }

    let nmf = onmf::OrthogonalNMF::<f64>::from_data(
        &data, nhidden, niterations);

    // read testimage out of each row of nmf.hidden
    for irow in 0..nhidden {
        let mut column = Vec::<f64>::new();
        for icol in 0..nobserved {
            column.push(nmf.hidden[(irow, icol)]);
        }
        let image = DMat::<f64>::from_col_vec(10, 10, &column[..]);
        magnify(image, mag_factor).save_to_png(&format!("orthogonal-nmf-hidden-{}.png", irow)[..]).unwrap();

    }
}
<|endoftext|>


<commit_before>use std::io::net::ip::{SocketAddr, IpAddr};
use std::io::{TcpListener, TcpStream, Listener, Acceptor, TimedOut, IoError};
use std::io::net::tcp::{TcpAcceptor, TcpStream};
use std::collections::hashmap::HashMap;
use std::comm::{channel, Sender, Receiver};
use std::io::timer::Timer;
use std::ops::Drop;
use std::sync::{Arc, Mutex};
use std::task;
use std::clone::Clone;

use serialize::{Decodable, Encodable};
use serialize::json::{Encoder, Decoder, DecoderError};
use uuid::Uuid;

use transport::Transport;
use result::{GossipResult, io_err};
use connection::Connection;
use message::{Message, Join};
use tcp::connection::TcpConnection;
use server::Server;

pub enum ChanMessage {
    StopListening,
    NewMessage(Box<Message + Send>)
}

/// A tcp transport has two fundamental elements within: An acceptor (server)
/// and a set of connections. The only job of the acceptor is to, well,
/// accept new connections and store them.
///
/// Connections are how all the nodes will communicate. Each node within
/// the system has a connection to every other node in the cluster. That
/// means, if node A wants to communicate with server B, it'll look up
/// server's B connection and send a message through that medium.
pub struct TcpTransport {
    ip: String,
    port: u16,
    sender: Sender<ChanMessage>
}

impl TcpTransport {

    /// Createa a new local transport. The ip and port are used for the
    /// Acceptor. Thus, having a local address of "0.0.0.0" is the common
    /// practice for the tcp server to be accessible from outside the
    /// current node.
    pub fn listen(ip: &str, port: u16) -> GossipResult<TcpTransport> {

        let (sender, receiver) = channel();

        let mut transport = TcpTransport {
            ip: ip.to_string(),
            port: port,
            sender: sender
        };

        transport.handle(receiver);

        Ok(transport)
    }

    pub fn handle(&mut self, rx: Receiver<ChanMessage>) {
        let ip = self.ip.clone();
        let port = self.port.clone();

        spawn(proc() {

            let listener = TcpListener::bind(ip.as_slice(), port).unwrap();
            let mut acceptor = listener.listen().unwrap();
            let mut timer = Timer::new().unwrap();
            let mut accept = true;
            let timeout = timer.oneshot(500);

            loop {
                // FIXME: I don't like this. This seems extremely
                // hacky.
                select! {
                   val = rx.recv() => {
                       match val {
                           StopListening => {
                               break;
                           },
                           _ => {}
                       }
                   },
                   () = timeout.recv() => {}
                }

                let stream = match acceptor.accept() {
                    Ok(stream) => stream,
                    Err(err) => fail!("FOo")
                };

                spawn(proc() {

                });
            }
        });

    }
}

#[unsafe_destructor]
impl Drop for TcpTransport {
    fn drop(&mut self) {
        self.close();
    }
}

impl Transport for TcpTransport {

    /// By default, a node does **not** join a cluster automatically. Thus,
    /// one has to manually initiate the join operation.
    ///
    /// To join a cluster, one just needs to establish a connection
    /// with one that already has membership (peer node). The join operation first
    /// establishes the new connection **and** sends a "join" broadcast.
    ///
    /// The peer node is responsible for propagating the new membership details
    /// through a new broadcast.
    fn join<'a, T>(&self, ip: &str, port: u16, server: &Server<'a, T>) -> GossipResult<()> {

        // Establish a new connection with the peer node.
        let mut conn = try!(TcpConnection::connect(ip, port));
        try!(conn.send(Join::new(server)));

        Ok(())
    }

    /// Receive a message from any of the connections.
    fn receive<T: Decodable<Decoder, DecoderError>>(&self) -> GossipResult<T> {
        unimplemented!()
    }

    /// Terminate the accept, along with disconnecting all connections. However,
    /// before doing so, the node will send one last broadcast letting the
    /// cluster know it's going offline.
    fn close(&mut self) -> GossipResult<()> {
        self.sender.send(StopListening);
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::net::ip::{Ipv4Addr};
    use tcp::connection::TcpConnection;
    use connection::Connection;
    use transport::Transport;

    #[test]
    fn new_transport() {
        let addr = "127.0.0.1";
        let port = 5499;

        let mut transport = TcpTransport::listen(addr, port).unwrap();
        let mut connection = TcpConnection::connect(addr, port).unwrap();
    }
}
<commit_msg>All tests pass. Refactoring the whole TcpTransport to properly design the system<commit_after>use std::io::net::ip::{SocketAddr, IpAddr};
use std::io::{TcpListener, TcpStream, Listener, Acceptor, TimedOut, IoError};
use std::io::net::tcp::{TcpAcceptor, TcpStream};
use std::collections::hashmap::HashMap;
use std::comm::{channel, Sender, Receiver};
use std::io::timer::Timer;
use std::ops::Drop;
use std::task::TaskBuilder;
use std::clone::Clone;

use serialize::{Decodable, Encodable};
use serialize::json::{Encoder, Decoder, DecoderError};
use uuid::Uuid;

use transport::Transport;
use result::{GossipResult, io_err};
use connection::Connection;
use message::{Message, Join};
use tcp::connection::TcpConnection;
use server::Server;

/// Messages that the AcceptingManager is communicating with.
enum AcceptingMsg {
    Exit
}

/// Wrap the common idiom of accepting a string and port into a
/// single source that's easier to pass around. It also mitigates the
/// naming issue of port (u16) and port (Receiver).
#[deriving(Show, PartialEq, Clone)]
pub struct Addr {
    pub ip: String,
    pub port: u16
}

impl Addr {
    /// Create a new instance of the Addr record.
    pub fn new(ip: String, port: u16) -> Addr {
        Addr {
            ip: ip,
            port: port
        }
    }
}

/// Alias the type to be easier to use.
type AcceptingTask = Sender<AcceptingMsg>;

/// The AcceptingManager is responsible for managing incoming
/// TCP connections/streams. The manager first creates a new TcpListener
/// and TcpAcceptor in order to start listening in. All communication
/// then happens through the use of channels. A new StreamManager will
/// be created in order to handle the appropriate streams.
struct AcceptingManager {
    port: Receiver<AcceptingMsg>,
    acceptor: Option<TcpAcceptor>,
    addr: Addr
}

impl AcceptingManager {
    /// Given a Receiver (port) to read new messages from and an address
    /// create a new context. This does **not** actually create a new
    /// TcpAcceptor and doesn't bind to anything. That happens in the
    /// .start() method.
    pub fn new(port: Receiver<AcceptingMsg>, addr: Addr) -> AcceptingManager {
        AcceptingManager {
            port: port,
            acceptor: None,
            addr: addr
        }
    }

    /// Start listening on the Tcp address and start processing incoming
    /// streams. We also need to continue listening on the channel to see if
    /// we should be shutting down or not.
    ///
    /// Note: It's impossible to shutdown while the task is blocking on
    ///       acceptor.accept() and no more connections are coming through.
    ///       You'll have to physically shutdown the whole process, which is
    ///       kinda ugly, but works.
    pub fn start(&mut self) {

        let acceptor = TcpListener::bind(self.addr.ip.as_slice(), self.addr.port).listen();

        loop {
            match self.port.recv() {
                Exit => break
            }
        }
    }
}

/// Create a new AcceptingTask responsible for accepting brand new
/// tcp connections and passing them on.
///
/// We initialize a new setup channel that is used to return the correct
/// Sender, which is created inside the task.
fn create_accepting_task(addr: Addr) -> AcceptingTask {
    let (setup_chan, setup_port) = channel();
    let builder = TaskBuilder::new().named("AcceptingManager");

    builder.spawn(proc() {
        let (chan, port) = channel();
        setup_chan.send(chan);
        AcceptingManager::new(port, addr).start();
    });

    setup_port.recv()
}

/// A tcp transport has two fundamental elements within: An acceptor (server)
/// and a set of connections. The only job of the acceptor is to, well,
/// accept new connections and store them.
///
/// Connections are how all the nodes will communicate. Each node within
/// the system has a connection to every other node in the cluster. That
/// means, if node A wants to communicate with server B, it'll look up
/// server's B connection and send a message through that medium.
pub struct TcpTransport {
    addr: Addr,
    sender: AcceptingTask
}

impl TcpTransport {

    /// Createa a new local transport. The ip and port are used for the
    /// Acceptor. Thus, having a local address of "0.0.0.0" is the common
    /// practice for the tcp server to be accessible from outside the
    /// current node.
    pub fn listen(ip: &str, port: u16) -> GossipResult<TcpTransport> {

        let addr = Addr::new(ip.to_string(), port);
        let sender = create_accepting_task(addr.clone());

        let mut transport = TcpTransport {
            addr: addr,
            sender: sender
        };

        Ok(transport)
    }
}

#[unsafe_destructor]
impl Drop for TcpTransport {
    fn drop(&mut self) {
        self.close();
    }
}

impl Transport for TcpTransport {

    /// By default, a node does **not** join a cluster automatically. Thus,
    /// one has to manually initiate the join operation.
    ///
    /// To join a cluster, one just needs to establish a connection
    /// with one that already has membership (peer node). The join operation first
    /// establishes the new connection **and** sends a "join" broadcast.
    ///
    /// The peer node is responsible for propagating the new membership details
    /// through a new broadcast.
    fn join<'a, T>(&self, ip: &str, port: u16, server: &Server<'a, T>) -> GossipResult<()> {

        // Establish a new connection with the peer node.
        let mut conn = try!(TcpConnection::connect(ip, port));
        try!(conn.send(Join::new(server)));

        Ok(())
    }

    /// Receive a message from any of the connections.
    fn receive<T: Decodable<Decoder, DecoderError>>(&self) -> GossipResult<T> {
        unimplemented!()
    }

    /// Terminate the accept, along with disconnecting all connections. However,
    /// before doing so, the node will send one last broadcast letting the
    /// cluster know it's going offline.
    fn close(&mut self) -> GossipResult<()> {
        self.sender.send(Exit);
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::net::ip::{Ipv4Addr};
    use tcp::connection::TcpConnection;
    use connection::Connection;
    use transport::Transport;

    #[test]
    fn new_transport() {
        let addr = "127.0.0.1";
        let port = 5499;

        let mut transport = TcpTransport::listen(addr, port).unwrap();
        let mut connection = TcpConnection::connect(addr, port).unwrap();
    }
}
<|endoftext|>