<commit_before>use chrono::Utc;
use serde::ser::Serialize;
use serde_json::map::Map;
use serde_json::{from_value, to_value, Value};

use crypto::Algorithm;
use errors::{new_error, ErrorKind, Result};

/// Contains the various validations that are applied after decoding a token.
///
/// All time validation happen on UTC timestamps.
///
/// ```rust
/// use jsonwebtoken::Validation;
///
/// // Default value
/// let validation = Validation::default();
///
/// // Changing one parameter
/// let mut validation = Validation {leeway: 60, ..Default::default()};
///
/// // Setting audience
/// let mut validation = Validation::default();
/// validation.set_audience(&"Me"); // string
/// validation.set_audience(&["Me", "You"]); // array of strings
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct Validation {
    /// Add some leeway (in seconds) to the `exp`, `iat` and `nbf` validation to
    /// account for clock skew.
    ///
    /// Defaults to `0`.
    pub leeway: i64,
    /// Whether to validate the `exp` field.
    ///
    /// It will return an error if the time in the `exp` field is past.
    ///
    /// Defaults to `true`.
    pub validate_exp: bool,
    /// Whether to validate the `iat` field.
    ///
    /// It will return an error if the time in the `iat` field is in the future.
    ///
    /// Defaults to `true`.
    pub validate_iat: bool,
    /// Whether to validate the `nbf` field.
    ///
    /// It will return an error if the current timestamp is before the time in the `nbf` field.
    ///
    /// Defaults to `true`.
    pub validate_nbf: bool,
    /// If it contains a value, the validation will check that the `aud` field is the same as the
    /// one provided and will error otherwise.
    /// Since `aud` can be either a String or a Vec<String> in the JWT spec, you will need to use
    /// the [set_audience](struct.Validation.html#method.set_audience) method to set it.
    ///
    /// Defaults to `None`.
    pub aud: Option<Value>,
    /// If it contains a value, the validation will check that the `iss` field is the same as the
    /// one provided and will error otherwise.
    ///
    /// Defaults to `None`.
    pub iss: Option<String>,
    /// If it contains a value, the validation will check that the `sub` field is the same as the
    /// one provided and will error otherwise.
    ///
    /// Defaults to `None`.
    pub sub: Option<String>,
    /// If it contains a value, the validation will check that the `alg` of the header is contained
    /// in the ones provided and will error otherwise.
    ///
    /// Defaults to `vec![Algorithm::HS256]`.
    pub algorithms: Vec<Algorithm>,
}

impl Validation {
    /// Create a default validation setup allowing the given alg
    pub fn new(alg: Algorithm) -> Validation {
        let mut validation = Validation::default();
        validation.algorithms = vec![alg];
        validation
    }

    /// Since `aud` can be either a String or an array of String in the JWT spec, this method will take
    /// care of serializing the value.
    pub fn set_audience<T: Serialize>(&mut self, audience: &T) {
        self.aud = Some(to_value(audience).unwrap());
    }
}

impl Default for Validation {
    fn default() -> Validation {
        Validation {
            leeway: 0,

            validate_exp: true,
            validate_iat: false,
            validate_nbf: false,

            iss: None,
            sub: None,
            aud: None,

            algorithms: vec![Algorithm::HS256],
        }
    }
}

pub fn validate(claims: &Map<String, Value>, options: &Validation) -> Result<()> {
    let now = Utc::now().timestamp();

    if options.validate_iat {
        if let Some(iat) = claims.get("iat") {
            if from_value::<i64>(iat.clone())? > now + options.leeway {
                return Err(new_error(ErrorKind::InvalidIssuedAt));
            }
        } else {
            return Err(new_error(ErrorKind::InvalidIssuedAt));
        }
    }

    if options.validate_exp {
        if let Some(exp) = claims.get("exp") {
            if from_value::<i64>(exp.clone())? < now - options.leeway {
                return Err(new_error(ErrorKind::ExpiredSignature));
            }
        } else {
            return Err(new_error(ErrorKind::ExpiredSignature));
        }
    }

    if options.validate_nbf {
        if let Some(nbf) = claims.get("nbf") {
            if from_value::<i64>(nbf.clone())? > now + options.leeway {
                return Err(new_error(ErrorKind::ImmatureSignature));
            }
        } else {
            return Err(new_error(ErrorKind::ImmatureSignature));
        }
    }

    if let Some(ref correct_iss) = options.iss {
        if let Some(iss) = claims.get("iss") {
            if from_value::<String>(iss.clone())? != *correct_iss {
                return Err(new_error(ErrorKind::InvalidIssuer));
            }
        } else {
            return Err(new_error(ErrorKind::InvalidIssuer));
        }
    }

    if let Some(ref correct_sub) = options.sub {
        if let Some(sub) = claims.get("sub") {
            if from_value::<String>(sub.clone())? != *correct_sub {
                return Err(new_error(ErrorKind::InvalidSubject));
            }
        } else {
            return Err(new_error(ErrorKind::InvalidSubject));
        }
    }

    if let Some(ref correct_aud) = options.aud {
        if let Some(aud) = claims.get("aud") {
            if aud != correct_aud {
                return Err(new_error(ErrorKind::InvalidAudience));
            }
        } else {
            return Err(new_error(ErrorKind::InvalidAudience));
        }
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use chrono::Utc;
    use serde_json::map::Map;
    use serde_json::to_value;

    use super::{validate, Validation};

    use errors::ErrorKind;

    #[test]
    fn iat_in_past_ok() {
        let mut claims = Map::new();
        claims.insert("iat".to_string(), to_value(Utc::now().timestamp() - 10000).unwrap());
        let validation =
            Validation { validate_exp: false, validate_iat: true, ..Validation::default() };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn iat_in_future_fails() {
        let mut claims = Map::new();
        claims.insert("iat".to_string(), to_value(Utc::now().timestamp() + 100000).unwrap());
        let validation =
            Validation { validate_exp: false, validate_iat: true, ..Validation::default() };
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidIssuedAt => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn iat_in_future_but_in_leeway_ok() {
        let mut claims = Map::new();
        claims.insert("iat".to_string(), to_value(Utc::now().timestamp() + 50).unwrap());
        let validation = Validation {
            leeway: 1000 * 60,
            validate_iat: true,
            validate_exp: false,
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn exp_in_future_ok() {
        let mut claims = Map::new();
        claims.insert("exp".to_string(), to_value(Utc::now().timestamp() + 10000).unwrap());
        let res = validate(&claims, &Validation::default());
        assert!(res.is_ok());
    }

    #[test]
    fn exp_in_past_fails() {
        let mut claims = Map::new();
        claims.insert("exp".to_string(), to_value(Utc::now().timestamp() - 100000).unwrap());
        let res = validate(&claims, &Validation::default());
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::ExpiredSignature => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn exp_in_past_but_in_leeway_ok() {
        let mut claims = Map::new();
        claims.insert("exp".to_string(), to_value(Utc::now().timestamp() - 500).unwrap());
        let validation = Validation { leeway: 1000 * 60, ..Default::default() };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    // https://github.com/Keats/jsonwebtoken/issues/51
    #[test]
    fn validation_called_even_if_field_is_empty() {
        let claims = Map::new();
        let res = validate(&claims, &Validation::default());
        assert!(res.is_err());
        match res.unwrap_err().kind() {
            &ErrorKind::ExpiredSignature => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn nbf_in_past_ok() {
        let mut claims = Map::new();
        claims.insert("nbf".to_string(), to_value(Utc::now().timestamp() - 10000).unwrap());
        let validation =
            Validation { validate_exp: false, validate_nbf: true, ..Validation::default() };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn nbf_in_future_fails() {
        let mut claims = Map::new();
        claims.insert("nbf".to_string(), to_value(Utc::now().timestamp() + 100000).unwrap());
        let validation =
            Validation { validate_exp: false, validate_nbf: true, ..Validation::default() };
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::ImmatureSignature => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn nbf_in_future_but_in_leeway_ok() {
        let mut claims = Map::new();
        claims.insert("nbf".to_string(), to_value(Utc::now().timestamp() + 500).unwrap());
        let validation = Validation {
            leeway: 1000 * 60,
            validate_nbf: true,
            validate_exp: false,
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn iss_ok() {
        let mut claims = Map::new();
        claims.insert("iss".to_string(), to_value("Keats").unwrap());
        let validation = Validation {
            validate_exp: false,
            iss: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn iss_not_matching_fails() {
        let mut claims = Map::new();
        claims.insert("iss".to_string(), to_value("Hacked").unwrap());
        let validation = Validation {
            validate_exp: false,
            iss: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidIssuer => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn iss_missing_fails() {
        let claims = Map::new();
        let validation = Validation {
            validate_exp: false,
            iss: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidIssuer => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn sub_ok() {
        let mut claims = Map::new();
        claims.insert("sub".to_string(), to_value("Keats").unwrap());
        let validation = Validation {
            validate_exp: false,
            sub: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn sub_not_matching_fails() {
        let mut claims = Map::new();
        claims.insert("sub".to_string(), to_value("Hacked").unwrap());
        let validation = Validation {
            validate_exp: false,
            sub: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidSubject => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn sub_missing_fails() {
        let claims = Map::new();
        let validation = Validation {
            validate_exp: false,
            sub: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidSubject => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn aud_string_ok() {
        let mut claims = Map::new();
        claims.insert("aud".to_string(), to_value("Everyone").unwrap());
        let mut validation = Validation { validate_exp: false, ..Validation::default() };
        validation.set_audience(&"Everyone");
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn aud_array_of_string_ok() {
        let mut claims = Map::new();
        claims.insert("aud".to_string(), to_value(["UserA", "UserB"]).unwrap());
        let mut validation = Validation { validate_exp: false, ..Validation::default() };
        validation.set_audience(&["UserA", "UserB"]);
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn aud_type_mismatch_fails() {
        let mut claims = Map::new();
        claims.insert("aud".to_string(), to_value("Everyone").unwrap());
        let mut validation = Validation { validate_exp: false, ..Validation::default() };
        validation.set_audience(&["UserA", "UserB"]);
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidAudience => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn aud_correct_type_not_matching_fails() {
        let mut claims = Map::new();
        claims.insert("aud".to_string(), to_value("Everyone").unwrap());
        let mut validation = Validation { validate_exp: false, ..Validation::default() };
        validation.set_audience(&"None");
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidAudience => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn aud_missing_fails() {
        let claims = Map::new();
        let mut validation = Validation { validate_exp: false, ..Validation::default() };
        validation.set_audience(&"None");
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidAudience => (),
            _ => assert!(false),
        };
    }
}
<commit_msg>Fix documentation of default values in validation<commit_after>use chrono::Utc;
use serde::ser::Serialize;
use serde_json::map::Map;
use serde_json::{from_value, to_value, Value};

use crypto::Algorithm;
use errors::{new_error, ErrorKind, Result};

/// Contains the various validations that are applied after decoding a token.
///
/// All time validation happen on UTC timestamps.
///
/// ```rust
/// use jsonwebtoken::Validation;
///
/// // Default value
/// let validation = Validation::default();
///
/// // Changing one parameter
/// let mut validation = Validation {leeway: 60, ..Default::default()};
///
/// // Setting audience
/// let mut validation = Validation::default();
/// validation.set_audience(&"Me"); // string
/// validation.set_audience(&["Me", "You"]); // array of strings
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct Validation {
    /// Add some leeway (in seconds) to the `exp`, `iat` and `nbf` validation to
    /// account for clock skew.
    ///
    /// Defaults to `0`.
    pub leeway: i64,
    /// Whether to validate the `exp` field.
    ///
    /// It will return an error if the time in the `exp` field is past.
    ///
    /// Defaults to `true`.
    pub validate_exp: bool,
    /// Whether to validate the `iat` field.
    ///
    /// It will return an error if the time in the `iat` field is in the future.
    ///
    /// Defaults to `false`.
    pub validate_iat: bool,
    /// Whether to validate the `nbf` field.
    ///
    /// It will return an error if the current timestamp is before the time in the `nbf` field.
    ///
    /// Defaults to `false`.
    pub validate_nbf: bool,
    /// If it contains a value, the validation will check that the `aud` field is the same as the
    /// one provided and will error otherwise.
    /// Since `aud` can be either a String or a Vec<String> in the JWT spec, you will need to use
    /// the [set_audience](struct.Validation.html#method.set_audience) method to set it.
    ///
    /// Defaults to `None`.
    pub aud: Option<Value>,
    /// If it contains a value, the validation will check that the `iss` field is the same as the
    /// one provided and will error otherwise.
    ///
    /// Defaults to `None`.
    pub iss: Option<String>,
    /// If it contains a value, the validation will check that the `sub` field is the same as the
    /// one provided and will error otherwise.
    ///
    /// Defaults to `None`.
    pub sub: Option<String>,
    /// If it contains a value, the validation will check that the `alg` of the header is contained
    /// in the ones provided and will error otherwise.
    ///
    /// Defaults to `vec![Algorithm::HS256]`.
    pub algorithms: Vec<Algorithm>,
}

impl Validation {
    /// Create a default validation setup allowing the given alg
    pub fn new(alg: Algorithm) -> Validation {
        let mut validation = Validation::default();
        validation.algorithms = vec![alg];
        validation
    }

    /// Since `aud` can be either a String or an array of String in the JWT spec, this method will take
    /// care of serializing the value.
    pub fn set_audience<T: Serialize>(&mut self, audience: &T) {
        self.aud = Some(to_value(audience).unwrap());
    }
}

impl Default for Validation {
    fn default() -> Validation {
        Validation {
            leeway: 0,

            validate_exp: true,
            validate_iat: false,
            validate_nbf: false,

            iss: None,
            sub: None,
            aud: None,

            algorithms: vec![Algorithm::HS256],
        }
    }
}

pub fn validate(claims: &Map<String, Value>, options: &Validation) -> Result<()> {
    let now = Utc::now().timestamp();

    if options.validate_iat {
        if let Some(iat) = claims.get("iat") {
            if from_value::<i64>(iat.clone())? > now + options.leeway {
                return Err(new_error(ErrorKind::InvalidIssuedAt));
            }
        } else {
            return Err(new_error(ErrorKind::InvalidIssuedAt));
        }
    }

    if options.validate_exp {
        if let Some(exp) = claims.get("exp") {
            if from_value::<i64>(exp.clone())? < now - options.leeway {
                return Err(new_error(ErrorKind::ExpiredSignature));
            }
        } else {
            return Err(new_error(ErrorKind::ExpiredSignature));
        }
    }

    if options.validate_nbf {
        if let Some(nbf) = claims.get("nbf") {
            if from_value::<i64>(nbf.clone())? > now + options.leeway {
                return Err(new_error(ErrorKind::ImmatureSignature));
            }
        } else {
            return Err(new_error(ErrorKind::ImmatureSignature));
        }
    }

    if let Some(ref correct_iss) = options.iss {
        if let Some(iss) = claims.get("iss") {
            if from_value::<String>(iss.clone())? != *correct_iss {
                return Err(new_error(ErrorKind::InvalidIssuer));
            }
        } else {
            return Err(new_error(ErrorKind::InvalidIssuer));
        }
    }

    if let Some(ref correct_sub) = options.sub {
        if let Some(sub) = claims.get("sub") {
            if from_value::<String>(sub.clone())? != *correct_sub {
                return Err(new_error(ErrorKind::InvalidSubject));
            }
        } else {
            return Err(new_error(ErrorKind::InvalidSubject));
        }
    }

    if let Some(ref correct_aud) = options.aud {
        if let Some(aud) = claims.get("aud") {
            if aud != correct_aud {
                return Err(new_error(ErrorKind::InvalidAudience));
            }
        } else {
            return Err(new_error(ErrorKind::InvalidAudience));
        }
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use chrono::Utc;
    use serde_json::map::Map;
    use serde_json::to_value;

    use super::{validate, Validation};

    use errors::ErrorKind;

    #[test]
    fn iat_in_past_ok() {
        let mut claims = Map::new();
        claims.insert("iat".to_string(), to_value(Utc::now().timestamp() - 10000).unwrap());
        let validation =
            Validation { validate_exp: false, validate_iat: true, ..Validation::default() };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn iat_in_future_fails() {
        let mut claims = Map::new();
        claims.insert("iat".to_string(), to_value(Utc::now().timestamp() + 100000).unwrap());
        let validation =
            Validation { validate_exp: false, validate_iat: true, ..Validation::default() };
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidIssuedAt => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn iat_in_future_but_in_leeway_ok() {
        let mut claims = Map::new();
        claims.insert("iat".to_string(), to_value(Utc::now().timestamp() + 50).unwrap());
        let validation = Validation {
            leeway: 1000 * 60,
            validate_iat: true,
            validate_exp: false,
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn exp_in_future_ok() {
        let mut claims = Map::new();
        claims.insert("exp".to_string(), to_value(Utc::now().timestamp() + 10000).unwrap());
        let res = validate(&claims, &Validation::default());
        assert!(res.is_ok());
    }

    #[test]
    fn exp_in_past_fails() {
        let mut claims = Map::new();
        claims.insert("exp".to_string(), to_value(Utc::now().timestamp() - 100000).unwrap());
        let res = validate(&claims, &Validation::default());
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::ExpiredSignature => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn exp_in_past_but_in_leeway_ok() {
        let mut claims = Map::new();
        claims.insert("exp".to_string(), to_value(Utc::now().timestamp() - 500).unwrap());
        let validation = Validation { leeway: 1000 * 60, ..Default::default() };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    // https://github.com/Keats/jsonwebtoken/issues/51
    #[test]
    fn validation_called_even_if_field_is_empty() {
        let claims = Map::new();
        let res = validate(&claims, &Validation::default());
        assert!(res.is_err());
        match res.unwrap_err().kind() {
            &ErrorKind::ExpiredSignature => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn nbf_in_past_ok() {
        let mut claims = Map::new();
        claims.insert("nbf".to_string(), to_value(Utc::now().timestamp() - 10000).unwrap());
        let validation =
            Validation { validate_exp: false, validate_nbf: true, ..Validation::default() };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn nbf_in_future_fails() {
        let mut claims = Map::new();
        claims.insert("nbf".to_string(), to_value(Utc::now().timestamp() + 100000).unwrap());
        let validation =
            Validation { validate_exp: false, validate_nbf: true, ..Validation::default() };
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::ImmatureSignature => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn nbf_in_future_but_in_leeway_ok() {
        let mut claims = Map::new();
        claims.insert("nbf".to_string(), to_value(Utc::now().timestamp() + 500).unwrap());
        let validation = Validation {
            leeway: 1000 * 60,
            validate_nbf: true,
            validate_exp: false,
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn iss_ok() {
        let mut claims = Map::new();
        claims.insert("iss".to_string(), to_value("Keats").unwrap());
        let validation = Validation {
            validate_exp: false,
            iss: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn iss_not_matching_fails() {
        let mut claims = Map::new();
        claims.insert("iss".to_string(), to_value("Hacked").unwrap());
        let validation = Validation {
            validate_exp: false,
            iss: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidIssuer => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn iss_missing_fails() {
        let claims = Map::new();
        let validation = Validation {
            validate_exp: false,
            iss: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidIssuer => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn sub_ok() {
        let mut claims = Map::new();
        claims.insert("sub".to_string(), to_value("Keats").unwrap());
        let validation = Validation {
            validate_exp: false,
            sub: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn sub_not_matching_fails() {
        let mut claims = Map::new();
        claims.insert("sub".to_string(), to_value("Hacked").unwrap());
        let validation = Validation {
            validate_exp: false,
            sub: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidSubject => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn sub_missing_fails() {
        let claims = Map::new();
        let validation = Validation {
            validate_exp: false,
            sub: Some("Keats".to_string()),
            ..Default::default()
        };
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidSubject => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn aud_string_ok() {
        let mut claims = Map::new();
        claims.insert("aud".to_string(), to_value("Everyone").unwrap());
        let mut validation = Validation { validate_exp: false, ..Validation::default() };
        validation.set_audience(&"Everyone");
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn aud_array_of_string_ok() {
        let mut claims = Map::new();
        claims.insert("aud".to_string(), to_value(["UserA", "UserB"]).unwrap());
        let mut validation = Validation { validate_exp: false, ..Validation::default() };
        validation.set_audience(&["UserA", "UserB"]);
        let res = validate(&claims, &validation);
        assert!(res.is_ok());
    }

    #[test]
    fn aud_type_mismatch_fails() {
        let mut claims = Map::new();
        claims.insert("aud".to_string(), to_value("Everyone").unwrap());
        let mut validation = Validation { validate_exp: false, ..Validation::default() };
        validation.set_audience(&["UserA", "UserB"]);
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidAudience => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn aud_correct_type_not_matching_fails() {
        let mut claims = Map::new();
        claims.insert("aud".to_string(), to_value("Everyone").unwrap());
        let mut validation = Validation { validate_exp: false, ..Validation::default() };
        validation.set_audience(&"None");
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidAudience => (),
            _ => assert!(false),
        };
    }

    #[test]
    fn aud_missing_fails() {
        let claims = Map::new();
        let mut validation = Validation { validate_exp: false, ..Validation::default() };
        validation.set_audience(&"None");
        let res = validate(&claims, &validation);
        assert!(res.is_err());

        match res.unwrap_err().kind() {
            &ErrorKind::InvalidAudience => (),
            _ => assert!(false),
        };
    }
}
<|endoftext|>


<commit_before>use super::{Numeric, Columnar, Tabular};

use std::ops::{Add, Sub, Mul, Div, Rem};
use std::ops;
use std::convert;
use std::mem::transmute;

#[cfg(features = "parallel")]
use super::parallel::*;

#[cfg(features = "rand")]
use rand::Rand;

#[cfg(test)] mod test;
#[cfg(test)] mod bench;

#[macro_use] mod macros;

pub trait Vector<N>: Sized
where N: Numeric {

    #[cfg(features = "unstable")]
    fn is_perpendicular_to<M>(self, v_prime: Self) -> bool
    where Self: Mul<Self, Output=M>
        , M: PartialEq {
        (self * v_prime) == M::zero()
    }
}

/// A 5D vector of any numeric type.
///
/// This is the non-SIMD version.
#[cfg(not(simd))]
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Debug, Default)]
#[repr(C)]
pub struct Vector5<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              , pub z: N
              , pub w: N
              , pub a: N
              }

#[cfg(features = "rand")]
impl_rand! { Vector5, x, y, z, w, a }

/// A 4D vector of any numeric type.
///
/// This is the non-SIMD version.
#[cfg(not(simd))]
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Debug, Default)]
#[repr(C)]
pub struct Vector4<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              , pub z: N
              , pub w: N
              }

#[cfg(features = "rand")]
impl_rand! { Vector4, x, y, z, w }

/// A 3D vector of any numeric type.
///
/// This is the non-SIMD version.
#[cfg(not(simd))]
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Debug, Default)]
#[repr(C)]
pub struct Vector3<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              , pub z: N
              }

#[cfg(features = "rand")]
impl_rand! { Vector3, x, y, z }
impl_ops! { Vector3, x, y, z }

impl<N> Mul<N> for Vector3<N>
where N: Numeric + Mul<Output = N>
    , N: Copy {

    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector3 { x: self.x * rhs
                , y: self.y * rhs
                , z: self.z * rhs
                }
    }

}

impl<N> Mul<Vector3<N>> for Vector3<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy {

    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) +
        (self.y * rhs.y) +
        (self.z * rhs.z)
    }
}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector3<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N> {

    type Output = Self;
    fn mul(self, rhs: N) -> Output {
        self.simdalize() * N::splat(rhs)
    }
}

/// A 2D vector of any numeric type.
///
/// This is the non-SIMD version.
#[cfg(not(simd))]
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Debug, Default)]
#[repr(C)]
pub struct Vector2<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              }

#[cfg(features = "rand")]
impl_rand! { Vector2, x, y }
impl_ops! { Vector2, x, y }

// impl_v2_ops! { Add, add, +
//                Sub, sub, -
//                Div, div, /
//                Rem, rem, %
//              }

impl<N> Mul<N> for Vector2<N>
where N: Numeric + Mul<Output = N>
    , N: Copy {

    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector2 { x: self.x * rhs
                , y: self.y * rhs
                }
    }
}

impl<N> Mul<Vector2<N>> for Vector2<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy {

    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) + (self.y * rhs.y)
    }

}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector2<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N> {

    type Output = Self;
    fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
}

pub struct VectorN<'a, N: Numeric + 'a>(&'a [N]);

impl_converts! { Vector2, 2
               , Vector3, 3
               , Vector4, 4
               , Vector5, 5
               }

impl_index! { Vector2
            , Vector3
            , Vector4
            , Vector5
            }
<commit_msg>[vector] Vectors up to size 5 now get ops for free New macros make life much easier<commit_after>use super::{Numeric, Columnar, Tabular};

use std::ops::{Add, Sub, Mul, Div, Rem};
use std::ops;
use std::convert;
use std::mem::transmute;

#[cfg(features = "parallel")]
use super::parallel::*;

#[cfg(features = "rand")]
use rand::Rand;

#[cfg(test)] mod test;
#[cfg(test)] mod bench;

#[macro_use] mod macros;

pub trait Vector<N>: Sized
where N: Numeric {

    #[cfg(features = "unstable")]
    fn is_perpendicular_to<M>(self, v_prime: Self) -> bool
    where Self: Mul<Self, Output=M>
        , M: PartialEq {
        (self * v_prime) == M::zero()
    }
}

/// A 5D vector of any numeric type.
///
/// This is the non-SIMD version.
#[cfg(not(simd))]
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Debug, Default)]
#[repr(C)]
pub struct Vector5<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              , pub z: N
              , pub w: N
              , pub a: N
              }

#[cfg(features = "rand")]
impl_rand! { Vector5, x, y, z, w, a }
impl_ops! { Vector5, x, y, z, w, a }

/// A 4D vector of any numeric type.
///
/// This is the non-SIMD version.
#[cfg(not(simd))]
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Debug, Default)]
#[repr(C)]
pub struct Vector4<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              , pub z: N
              , pub w: N
              }

#[cfg(features = "rand")]
impl_rand! { Vector4, x, y, z, w }
impl_ops! { Vector4, x, y, z, w }

/// A 3D vector of any numeric type.
///
/// This is the non-SIMD version.
#[cfg(not(simd))]
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Debug, Default)]
#[repr(C)]
pub struct Vector3<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              , pub z: N
              }

#[cfg(features = "rand")]
impl_rand! { Vector3, x, y, z }
impl_ops! { Vector3, x, y, z }

impl<N> Mul<N> for Vector3<N>
where N: Numeric + Mul<Output = N>
    , N: Copy {

    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector3 { x: self.x * rhs
                , y: self.y * rhs
                , z: self.z * rhs
                }
    }

}

impl<N> Mul<Vector3<N>> for Vector3<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy {

    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) +
        (self.y * rhs.y) +
        (self.z * rhs.z)
    }
}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector3<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N> {

    type Output = Self;
    fn mul(self, rhs: N) -> Output {
        self.simdalize() * N::splat(rhs)
    }
}

/// A 2D vector of any numeric type.
///
/// This is the non-SIMD version.
#[cfg(not(simd))]
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Debug, Default)]
#[repr(C)]
pub struct Vector2<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              }

#[cfg(features = "rand")]
impl_rand! { Vector2, x, y }
impl_ops! { Vector2, x, y }

// impl_v2_ops! { Add, add, +
//                Sub, sub, -
//                Div, div, /
//                Rem, rem, %
//              }

impl<N> Mul<N> for Vector2<N>
where N: Numeric + Mul<Output = N>
    , N: Copy {

    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector2 { x: self.x * rhs
                , y: self.y * rhs
                }
    }
}

impl<N> Mul<Vector2<N>> for Vector2<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy {

    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) + (self.y * rhs.y)
    }

}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector2<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N> {

    type Output = Self;
    fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
}

pub struct VectorN<'a, N: Numeric + 'a>(&'a [N]);

impl_converts! { Vector2, 2
               , Vector3, 3
               , Vector4, 4
               , Vector5, 5
               }

impl_index! { Vector2
            , Vector3
            , Vector4
            , Vector5
            }
<|endoftext|>


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

use toml::Value;

use libimagrt::runtime::Runtime;
use libimagrt::edit::{Edit, EditResult};
use libimagstore::storeid::IntoStoreId;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::StoreIdIterator;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagentrytag::tag::{Tag, TagSlice};
use libimagentrytag::tagable::Tagable;
use libimagentrytag::result::Result as TagResult;

use module_path::ModuleEntryPath;
use result::Result;
use error::NoteError as NE;
use error::NoteErrorKind as NEK;

#[derive(Debug)]
pub struct Note<'a> {
    entry: FileLockEntry<'a>,
}

impl<'a> Note<'a> {

    pub fn new(store: &Store, name: String, text: String) -> Result<Note> {
        use std::ops::DerefMut;

        debug!("Creating new Note: '{}'", name);
        let fle = {
            let lockentry = store.create(ModuleEntryPath::new(name.clone()).into_storeid());
            if lockentry.is_err() {
                return Err(NE::new(NEK::StoreWriteError, Some(Box::new(lockentry.unwrap_err()))));
            }
            let mut lockentry = lockentry.unwrap();

            {
                let mut entry  = lockentry.deref_mut();

                {
                    let mut header = entry.get_header_mut();
                    let setres = header.set("note", Value::Table(BTreeMap::new()));
                    if setres.is_err() {
                        let kind = NEK::StoreWriteError;
                        return Err(NE::new(kind, Some(Box::new(setres.unwrap_err()))));
                    }

                    let setres = header.set("note.name", Value::String(name));
                    if setres.is_err() {
                        let kind = NEK::StoreWriteError;
                        return Err(NE::new(kind, Some(Box::new(setres.unwrap_err()))));
                    }
                }

                *entry.get_content_mut() = text;
            }

            lockentry
        };

        Ok(Note { entry: fle })
    }

    pub fn set_name(&mut self, n: String) -> Result<()> {
        let mut header = self.entry.get_header_mut();
        header.set("note.name", Value::String(n))
            .map_err(|e| NE::new(NEK::StoreWriteError, Some(Box::new(e))))
            .map(|_| ())
    }

    pub fn get_name(&self) -> Result<String> {
        let header = self.entry.get_header();
        match header.read("note.name") {
            Ok(Some(Value::String(s))) => Ok(String::from(s)),
            Ok(_)                => {
                let e = NE::new(NEK::HeaderTypeError, None);
                Err(NE::new(NEK::StoreReadError, Some(Box::new(e))))
            },
            Err(e) => Err(NE::new(NEK::StoreReadError, Some(Box::new(e))))
        }
    }

    pub fn set_text(&mut self, n: String) {
        *self.entry.get_content_mut() = n
    }

    pub fn get_text(&self) -> &String {
        self.entry.get_content()
    }

    pub fn delete(store: &Store, name: String) -> Result<()> {
        store.delete(ModuleEntryPath::new(name).into_storeid())
            .map_err(|e| NE::new(NEK::StoreWriteError, Some(Box::new(e))))
    }

    pub fn retrieve(store: &Store, name: String) -> Result<Note> {
        store.retrieve(ModuleEntryPath::new(name).into_storeid())
            .map_err(|e| NE::new(NEK::StoreWriteError, Some(Box::new(e))))
            .map(|entry| Note { entry: entry })
    }

    pub fn all_notes(store: &Store) -> Result<NoteIterator> {
        store.retrieve_for_module("notes")
            .map(|iter| NoteIterator::new(store, iter))
            .map_err(|e| NE::new(NEK::StoreReadError, Some(Box::new(e))))
    }

}

impl<'a> Edit for Note<'a> {

    fn edit_content(&mut self, rt: &Runtime) -> EditResult<()> {
        self.entry.edit_content(rt)
    }

}

impl<'a> Tagable for Note<'a> {

    fn get_tags(&self) -> TagResult<Vec<Tag>> {
        self.entry.get_tags()
    }

    fn set_tags(&mut self, ts: &[Tag]) -> TagResult<()> {
        self.entry.set_tags(ts)
    }

    fn add_tag(&mut self, t: Tag) -> TagResult<()> {
        self.entry.add_tag(t)
    }

    fn remove_tag(&mut self, t: Tag) -> TagResult<()> {
        self.entry.remove_tag(t)
    }

    fn has_tag(&self, t: TagSlice) -> TagResult<bool> {
        self.entry.has_tag(t)
    }

    fn has_tags(&self, ts: &[Tag]) -> TagResult<bool> {
        self.entry.has_tags(ts)
    }

}

trait FromStoreId {
    fn from_storeid(&Store, StoreId) -> Result<Note>;
}

impl<'a> FromStoreId for Note<'a> {

    fn from_storeid(store: &Store, id: StoreId) -> Result<Note> {
        debug!("Loading note from storeid: '{:?}'", id);
        match store.retrieve(id) {
            Err(e)    => Err(NE::new(NEK::StoreReadError, Some(Box::new(e)))),
            Ok(entry) => Ok(Note { entry: entry }),
        }
    }

}

impl<'a> Deref for Note<'a> {

    type Target = FileLockEntry<'a>;

    fn deref(&self) -> &FileLockEntry<'a> {
        &self.entry
    }

}

#[derive(Debug)]
pub struct NoteIterator<'a> {
    store: &'a Store,
    iditer: StoreIdIterator,
}

impl<'a> NoteIterator<'a> {

    pub fn new(store: &'a Store, iditer: StoreIdIterator) -> NoteIterator<'a> {
        NoteIterator {
            store: store,
            iditer: iditer,
        }
    }

}

impl<'a> Iterator for NoteIterator<'a> {
    type Item = Result<Note<'a>>;

    fn next(&mut self) -> Option<Result<Note<'a>>> {
        self.iditer
            .next()
            .map(|id| Note::from_storeid(self.store, id))
    }

}

<commit_msg>Add Note::get()<commit_after>use std::collections::BTreeMap;
use std::ops::Deref;

use toml::Value;

use libimagrt::runtime::Runtime;
use libimagrt::edit::{Edit, EditResult};
use libimagstore::storeid::IntoStoreId;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::StoreIdIterator;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagentrytag::tag::{Tag, TagSlice};
use libimagentrytag::tagable::Tagable;
use libimagentrytag::result::Result as TagResult;

use module_path::ModuleEntryPath;
use result::Result;
use error::NoteError as NE;
use error::NoteErrorKind as NEK;

#[derive(Debug)]
pub struct Note<'a> {
    entry: FileLockEntry<'a>,
}

impl<'a> Note<'a> {

    pub fn new(store: &Store, name: String, text: String) -> Result<Note> {
        use std::ops::DerefMut;

        debug!("Creating new Note: '{}'", name);
        let fle = {
            let lockentry = store.create(ModuleEntryPath::new(name.clone()).into_storeid());
            if lockentry.is_err() {
                return Err(NE::new(NEK::StoreWriteError, Some(Box::new(lockentry.unwrap_err()))));
            }
            let mut lockentry = lockentry.unwrap();

            {
                let mut entry  = lockentry.deref_mut();

                {
                    let mut header = entry.get_header_mut();
                    let setres = header.set("note", Value::Table(BTreeMap::new()));
                    if setres.is_err() {
                        let kind = NEK::StoreWriteError;
                        return Err(NE::new(kind, Some(Box::new(setres.unwrap_err()))));
                    }

                    let setres = header.set("note.name", Value::String(name));
                    if setres.is_err() {
                        let kind = NEK::StoreWriteError;
                        return Err(NE::new(kind, Some(Box::new(setres.unwrap_err()))));
                    }
                }

                *entry.get_content_mut() = text;
            }

            lockentry
        };

        Ok(Note { entry: fle })
    }

    pub fn set_name(&mut self, n: String) -> Result<()> {
        let mut header = self.entry.get_header_mut();
        header.set("note.name", Value::String(n))
            .map_err(|e| NE::new(NEK::StoreWriteError, Some(Box::new(e))))
            .map(|_| ())
    }

    pub fn get_name(&self) -> Result<String> {
        let header = self.entry.get_header();
        match header.read("note.name") {
            Ok(Some(Value::String(s))) => Ok(String::from(s)),
            Ok(_)                => {
                let e = NE::new(NEK::HeaderTypeError, None);
                Err(NE::new(NEK::StoreReadError, Some(Box::new(e))))
            },
            Err(e) => Err(NE::new(NEK::StoreReadError, Some(Box::new(e))))
        }
    }

    pub fn set_text(&mut self, n: String) {
        *self.entry.get_content_mut() = n
    }

    pub fn get_text(&self) -> &String {
        self.entry.get_content()
    }

    pub fn delete(store: &Store, name: String) -> Result<()> {
        store.delete(ModuleEntryPath::new(name).into_storeid())
            .map_err(|e| NE::new(NEK::StoreWriteError, Some(Box::new(e))))
    }

    pub fn retrieve(store: &Store, name: String) -> Result<Note> {
        store.retrieve(ModuleEntryPath::new(name).into_storeid())
            .map_err(|e| NE::new(NEK::StoreWriteError, Some(Box::new(e))))
            .map(|entry| Note { entry: entry })
    }

    pub fn get(store: &Store, name: String) -> Result<Option<Note>> {
        use libimagerror::into::IntoError;

        match store.get(ModuleEntryPath::new(name).into_storeid()) {
            Ok(Some(entry)) => Ok(Some(Note { entry: entry })),
            Ok(None) => Ok(None),
            Err(e) => Err(NEK::StoreWriteError.into_error_with_cause(Box::new(e))),
        }
    }

    pub fn all_notes(store: &Store) -> Result<NoteIterator> {
        store.retrieve_for_module("notes")
            .map(|iter| NoteIterator::new(store, iter))
            .map_err(|e| NE::new(NEK::StoreReadError, Some(Box::new(e))))
    }

}

impl<'a> Edit for Note<'a> {

    fn edit_content(&mut self, rt: &Runtime) -> EditResult<()> {
        self.entry.edit_content(rt)
    }

}

impl<'a> Tagable for Note<'a> {

    fn get_tags(&self) -> TagResult<Vec<Tag>> {
        self.entry.get_tags()
    }

    fn set_tags(&mut self, ts: &[Tag]) -> TagResult<()> {
        self.entry.set_tags(ts)
    }

    fn add_tag(&mut self, t: Tag) -> TagResult<()> {
        self.entry.add_tag(t)
    }

    fn remove_tag(&mut self, t: Tag) -> TagResult<()> {
        self.entry.remove_tag(t)
    }

    fn has_tag(&self, t: TagSlice) -> TagResult<bool> {
        self.entry.has_tag(t)
    }

    fn has_tags(&self, ts: &[Tag]) -> TagResult<bool> {
        self.entry.has_tags(ts)
    }

}

trait FromStoreId {
    fn from_storeid(&Store, StoreId) -> Result<Note>;
}

impl<'a> FromStoreId for Note<'a> {

    fn from_storeid(store: &Store, id: StoreId) -> Result<Note> {
        debug!("Loading note from storeid: '{:?}'", id);
        match store.retrieve(id) {
            Err(e)    => Err(NE::new(NEK::StoreReadError, Some(Box::new(e)))),
            Ok(entry) => Ok(Note { entry: entry }),
        }
    }

}

impl<'a> Deref for Note<'a> {

    type Target = FileLockEntry<'a>;

    fn deref(&self) -> &FileLockEntry<'a> {
        &self.entry
    }

}

#[derive(Debug)]
pub struct NoteIterator<'a> {
    store: &'a Store,
    iditer: StoreIdIterator,
}

impl<'a> NoteIterator<'a> {

    pub fn new(store: &'a Store, iditer: StoreIdIterator) -> NoteIterator<'a> {
        NoteIterator {
            store: store,
            iditer: iditer,
        }
    }

}

impl<'a> Iterator for NoteIterator<'a> {
    type Item = Result<Note<'a>>;

    fn next(&mut self) -> Option<Result<Note<'a>>> {
        self.iditer
            .next()
            .map(|id| Note::from_storeid(self.store, id))
    }

}

<|endoftext|>


<commit_before>use storeid::StoreId;
use store::FileLockEntry;

use self::error::HookError;

pub type HookResult = Result<(), HookError>;

pub trait Hook {
    fn description(&self) -> &str;
    fn dependencies(&self) -> Vec<Box<Hook>>;
}

pub trait StoreIdHook : Hook {
    fn execute(&self, &StoreId) -> HookResult;
}

pub trait FileLockHook : Hook {
    fn execute(&self, &StoreId, &FileLockEntry) -> HookResult;
}

pub mod read {
    use super::FileLockHook;
    use super::StoreIdHook;

    pub trait PreReadHook : StoreIdHook {
    }

    pub trait PostReadHook : FileLockHook {
    }

}

pub mod create {
    use super::FileLockHook;
    use super::StoreIdHook;

    pub trait PreCreateHook : StoreIdHook {
    }

    pub trait PostCreateHook : FileLockHook {
    }

}

pub mod retrieve {
    use super::FileLockHook;
    use super::StoreIdHook;

    pub trait PreRetrieveHook : StoreIdHook {
    }

    pub trait PostRetrieveHook : FileLockHook {
    }
}

pub mod delete {
    use super::StoreIdHook;

    pub trait PreDeleteHook : StoreIdHook {
    }

    pub trait PostDeleteHook : StoreIdHook {
    }
}

pub mod error {
    use std::error::Error;
    use std::fmt::Error as FmtError;
    use std::clone::Clone;
    use std::fmt::{Display, Formatter};

    /**
     * Kind of error
     */
    #[derive(Clone, Copy, Debug, PartialEq)]
    pub enum HookErrorKind {
        // ...
    }

    fn hook_error_type_as_str(e: &HookErrorKind) -> &'static str {
        match e {
            _ => "",
        }
    }

    impl Display for HookErrorKind {

        fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
            try!(write!(fmt, "{}", hook_error_type_as_str(self)));
            Ok(())
        }

    }

    /**
     * Error type
     */
    #[derive(Debug)]
    pub struct HookError {
        err_type: HookErrorKind,
        cause: Option<Box<Error>>,
    }

    impl HookError {

        /**
         * Build a new HookError from an HookErrorKind, optionally with cause
         */
        pub fn new(errtype: HookErrorKind, cause: Option<Box<Error>>)
            -> HookError
            {
                HookError {
                    err_type: errtype,
                    cause: cause,
                }
            }

        /**
         * Get the error type of this HookError
         */
        pub fn err_type(&self) -> HookErrorKind {
            self.err_type.clone()
        }

    }

    impl Display for HookError {

        fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
            try!(write!(fmt, "[{}]", hook_error_type_as_str(&self.err_type.clone())));
            Ok(())
        }

    }

    impl Error for HookError {

        fn description(&self) -> &str {
            hook_error_type_as_str(&self.err_type.clone())
        }

        fn cause(&self) -> Option<&Error> {
            self.cause.as_ref().map(|e| &**e)
        }

    }

}

<commit_msg>Hook: Add traits which must be implemented for Hook<commit_after>use storeid::StoreId;
use store::FileLockEntry;

use self::error::HookError;

pub type HookResult = Result<(), HookError>;

pub trait Hook : Eq + PartialEq + Debug + Display {
    fn dependencies(&self) -> Vec<Box<Hook>>;
}

pub trait StoreIdHook : Hook {
    fn execute(&self, &StoreId) -> HookResult;
}

pub trait FileLockHook : Hook {
    fn execute(&self, &StoreId, &FileLockEntry) -> HookResult;
}

pub mod read {
    use super::FileLockHook;
    use super::StoreIdHook;

    pub trait PreReadHook : StoreIdHook {
    }

    pub trait PostReadHook : FileLockHook {
    }

}

pub mod create {
    use super::FileLockHook;
    use super::StoreIdHook;

    pub trait PreCreateHook : StoreIdHook {
    }

    pub trait PostCreateHook : FileLockHook {
    }

}

pub mod retrieve {
    use super::FileLockHook;
    use super::StoreIdHook;

    pub trait PreRetrieveHook : StoreIdHook {
    }

    pub trait PostRetrieveHook : FileLockHook {
    }
}

pub mod delete {
    use super::StoreIdHook;

    pub trait PreDeleteHook : StoreIdHook {
    }

    pub trait PostDeleteHook : StoreIdHook {
    }
}

pub mod error {
    use std::error::Error;
    use std::fmt::Error as FmtError;
    use std::clone::Clone;
    use std::fmt::{Display, Formatter};

    /**
     * Kind of error
     */
    #[derive(Clone, Copy, Debug, PartialEq)]
    pub enum HookErrorKind {
        // ...
    }

    fn hook_error_type_as_str(e: &HookErrorKind) -> &'static str {
        match e {
            _ => "",
        }
    }

    impl Display for HookErrorKind {

        fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
            try!(write!(fmt, "{}", hook_error_type_as_str(self)));
            Ok(())
        }

    }

    /**
     * Error type
     */
    #[derive(Debug)]
    pub struct HookError {
        err_type: HookErrorKind,
        cause: Option<Box<Error>>,
    }

    impl HookError {

        /**
         * Build a new HookError from an HookErrorKind, optionally with cause
         */
        pub fn new(errtype: HookErrorKind, cause: Option<Box<Error>>)
            -> HookError
            {
                HookError {
                    err_type: errtype,
                    cause: cause,
                }
            }

        /**
         * Get the error type of this HookError
         */
        pub fn err_type(&self) -> HookErrorKind {
            self.err_type.clone()
        }

    }

    impl Display for HookError {

        fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
            try!(write!(fmt, "[{}]", hook_error_type_as_str(&self.err_type.clone())));
            Ok(())
        }

    }

    impl Error for HookError {

        fn description(&self) -> &str {
            hook_error_type_as_str(&self.err_type.clone())
        }

        fn cause(&self) -> Option<&Error> {
            self.cause.as_ref().map(|e| &**e)
        }

    }

}

<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::rc::Rc;

use syntex_syntax::ast::{self, Attribute};
use syntex_syntax::ext::base::{
    self,
    Determinacy,
    MultiDecorator,
    MultiModifier,
    SyntaxExtension,
};
use syntex_syntax::ext::expand::Expansion;
use syntex_syntax::ext::hygiene::Mark;
use syntex_syntax::parse::token::intern;
use syntex_syntax::parse::ParseSess;
use syntex_syntax::ptr::P;

pub struct Resolver<'a> {
    session: &'a ParseSess,
    extensions: HashMap<ast::Name, Rc<SyntaxExtension>>,
}

impl<'a> Resolver<'a> {
    pub fn new(session: &'a ParseSess) -> Self {
        Resolver {
            session: session,
            extensions: HashMap::new(),
        }
    }
}

impl<'a> base::Resolver for Resolver<'a> {
    fn next_node_id(&mut self) -> ast::NodeId {
        ast::DUMMY_NODE_ID
    }
    fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() }
    fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item> { item }

    fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {}
    fn add_macro(&mut self, _scope: Mark, def: ast::MacroDef, _export: bool) {
        self.session.span_diagnostic.span_bug(
            def.span,
            "add_macro is not supported yet");
    }
    fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
        self.extensions.insert(ident.name, ext);
    }
    fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec<Mark>) {}

    fn find_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute> {
        for i in 0..attrs.len() {
            let name = intern(&attrs[i].name());

            if let Some(ext) = self.extensions.get(&name) {
                match **ext {
                    MultiModifier(..) | MultiDecorator(..) => return Some(attrs.remove(i)),
                    _ => {}
                }
            }
        }
        None
    }
    fn find_extension(&mut self, _scope: Mark, name: ast::Name) -> Option<Rc<SyntaxExtension>> {
        self.extensions.get(&name).map(|ext| ext.clone())
    }
    fn find_mac(&mut self, scope: Mark, mac: &ast::Mac) -> Option<Rc<SyntaxExtension>> {
        let path = &mac.node.path;
        if path.segments.len() > 1 || path.global ||
           !path.segments[0].parameters.is_empty() {
            // NOTE: Pass macros with module separators through to the generated source.
            self.session.span_diagnostic.span_err(path.span,
                                                  "expected macro name without module separators");
            return None;
        }
        let name = path.segments[0].identifier.name;
        self.find_extension(scope, name)
    }
    fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
                     -> Result<Rc<SyntaxExtension>, Determinacy> {
        if path.segments.len() > 1 || path.global ||
            !path.segments[0].parameters.is_empty() {
            // NOTE: Pass macros with module separators through to the generated source.
            self.session.span_diagnostic.span_err(path.span,
                                                    "expected macro name without module separators");
            return Err(Determinacy::Undetermined);
        }
        let name = path.segments[0].identifier.name;
        let span = path.span;

        self.find_extension(scope, name).ok_or_else(|| {
            if force {
                let mut err =
                    self.session.span_diagnostic.struct_span_err(span, &format!("macro undefined: '{}!'", name));
                err.emit();
                Determinacy::Determined
            } else {
                Determinacy::Undetermined
            }
        })
    }
}
<commit_msg>Resolve conflict<commit_after>use std::collections::HashMap;
use std::rc::Rc;

use syntex_syntax::ast::{self, Attribute};
use syntex_syntax::ext::base::{
    self,
    Determinacy,
    MultiDecorator,
    MultiModifier,
    SyntaxExtension,
};
use syntex_syntax::ext::expand::Expansion;
use syntex_syntax::ext::hygiene::Mark;
use syntex_syntax::parse::token::intern;
use syntex_syntax::parse::ParseSess;
use syntex_syntax::ptr::P;

pub struct Resolver<'a> {
    session: &'a ParseSess,
    extensions: HashMap<ast::Name, Rc<SyntaxExtension>>,
}

impl<'a> Resolver<'a> {
    pub fn new(session: &'a ParseSess) -> Self {
        Resolver {
            session: session,
            extensions: HashMap::new(),
        }
    }
}

impl<'a> base::Resolver for Resolver<'a> {
    fn next_node_id(&mut self) -> ast::NodeId {
        ast::DUMMY_NODE_ID
    }
    fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() }
    fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item> { item }

    fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {}
    fn add_macro(&mut self, _scope: Mark, def: ast::MacroDef, _export: bool) {
        self.session.span_diagnostic.span_bug(
            def.span,
            "add_macro is not supported yet");
    }
    fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
        self.extensions.insert(ident.name, ext);
    }
    fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec<Mark>) {}

    fn resolve_imports(&mut self) {}
    fn find_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute> {
        for i in 0..attrs.len() {
            let name = intern(&attrs[i].name());

            if let Some(ext) = self.extensions.get(&name) {
                match **ext {
                    MultiModifier(..) | MultiDecorator(..) => return Some(attrs.remove(i)),
                    _ => {}
                }
            }
        }
        None
    }
    fn find_extension(&mut self, _scope: Mark, name: ast::Name) -> Option<Rc<SyntaxExtension>> {
        self.extensions.get(&name).map(|ext| ext.clone())
    }
    fn find_mac(&mut self, scope: Mark, mac: &ast::Mac) -> Option<Rc<SyntaxExtension>> {
        let path = &mac.node.path;
        if path.segments.len() > 1 || path.global ||
           !path.segments[0].parameters.is_empty() {
            // NOTE: Pass macros with module separators through to the generated source.
            self.session.span_diagnostic.span_err(path.span,
                                                  "expected macro name without module separators");
            return None;
        }
        let name = path.segments[0].identifier.name;
        self.find_extension(scope, name)
    }
    fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
                     -> Result<Rc<SyntaxExtension>, Determinacy> {
        if path.segments.len() > 1 || path.global ||
            !path.segments[0].parameters.is_empty() {
            // NOTE: Pass macros with module separators through to the generated source.
            self.session.span_diagnostic.span_err(path.span,
                                                    "expected macro name without module separators");
            return Err(Determinacy::Undetermined);
        }
        let name = path.segments[0].identifier.name;
        let span = path.span;

        self.find_extension(scope, name).ok_or_else(|| {
            if force {
                let mut err =
                    self.session.span_diagnostic.struct_span_err(span, &format!("macro undefined: '{}!'", name));
                err.emit();
                Determinacy::Determined
            } else {
                Determinacy::Undetermined
            }
        })
    }
}
<|endoftext|>


<commit_before><commit_msg>Support closure in change_return_type_to_result assist<commit_after><|endoftext|>


<commit_before>use crate::error;
use scroll::{Pread, Pwrite, SizeWith};

#[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)]
pub struct DataDirectory {
    pub virtual_address: u32,
    pub size: u32,
}

pub const SIZEOF_DATA_DIRECTORY: usize = 8;
const NUM_DATA_DIRECTORIES: usize = 16;

impl DataDirectory {
    pub fn parse(bytes: &[u8], offset: &mut usize) -> error::Result<Self> {
        let dd = bytes.gread_with(offset, scroll::LE)?;
        Ok(dd)
    }
}

#[derive(Debug, PartialEq, Copy, Clone, Default)]
pub struct DataDirectories {
    pub data_directories: [Option<DataDirectory>; NUM_DATA_DIRECTORIES],
}

impl DataDirectories {
    pub fn parse(bytes: &[u8], count: usize, offset: &mut usize) -> error::Result<Self> {
        let mut data_directories = [None; NUM_DATA_DIRECTORIES];
        if count > NUM_DATA_DIRECTORIES {
            return Err(error::Error::Malformed(format!(
                "data directory count ({}) is greater than maximum number of data directories ({})",
                count, NUM_DATA_DIRECTORIES
            )));
        }
        for dir in data_directories.iter_mut().take(count) {
            let dd = DataDirectory::parse(bytes, offset)?;
            let dd = if dd.virtual_address == 0 && dd.size == 0 {
                None
            } else {
                Some(dd)
            };
            *dir = dd;
        }
        Ok(DataDirectories { data_directories })
    }
    pub fn get_export_table(&self) -> &Option<DataDirectory> {
        let idx = 0;
        unsafe { self.data_directories.get_unchecked(idx) }
    }
    pub fn get_import_table(&self) -> &Option<DataDirectory> {
        let idx = 1;
        unsafe { self.data_directories.get_unchecked(idx) }
    }
    pub fn get_resource_table(&self) -> &Option<DataDirectory> {
        let idx = 2;
        unsafe { self.data_directories.get_unchecked(idx) }
    }
    pub fn get_exception_table(&self) -> &Option<DataDirectory> {
        let idx = 3;
        unsafe { self.data_directories.get_unchecked(idx) }
    }
    pub fn get_certificate_table(&self) -> &Option<DataDirectory> {
        let idx = 4;
        unsafe { self.data_directories.get_unchecked(idx) }
    }
    pub fn get_base_relocation_table(&self) -> &Option<DataDirectory> {
        let idx = 5;
        unsafe { self.data_directories.get_unchecked(idx) }
    }
    pub fn get_debug_table(&self) -> &Option<DataDirectory> {
        let idx = 6;
        unsafe { self.data_directories.get_unchecked(idx) }
    }
    pub fn get_architecture(&self) -> &Option<DataDirectory> {
        let idx = 7;
        unsafe { self.data_directories.get_unchecked(idx) }
    }
    pub fn get_global_ptr(&self) -> &Option<DataDirectory> {
        let idx = 8;
        unsafe { self.data_directories.get_unchecked(idx) }
    }
    pub fn get_tls_table(&self) -> &Option<DataDirectory> {
        let idx = 9;
        unsafe { self.data_directories.get_unchecked(idx) }
    }
    pub fn get_load_config_table(&self) -> &Option<DataDirectory> {
        let idx = 10;
        unsafe { self.data_directories.get_unchecked(idx) }
    }
    pub fn get_bound_import_table(&self) -> &Option<DataDirectory> {
        let idx = 11;
        unsafe { self.data_directories.get_unchecked(idx) }
    }
    pub fn get_import_address_table(&self) -> &Option<DataDirectory> {
        let idx = 12;
        unsafe { self.data_directories.get_unchecked(idx) }
    }
    pub fn get_delay_import_descriptor(&self) -> &Option<DataDirectory> {
        let idx = 13;
        unsafe { self.data_directories.get_unchecked(idx) }
    }
    pub fn get_clr_runtime_header(&self) -> &Option<DataDirectory> {
        let idx = 14;
        unsafe { self.data_directories.get_unchecked(idx) }
    }
}
<commit_msg>pe.data_directories: replace unsafe get_unchecked calls with direct indexing<commit_after>use crate::error;
use scroll::{Pread, Pwrite, SizeWith};

#[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)]
pub struct DataDirectory {
    pub virtual_address: u32,
    pub size: u32,
}

pub const SIZEOF_DATA_DIRECTORY: usize = 8;
const NUM_DATA_DIRECTORIES: usize = 16;

impl DataDirectory {
    pub fn parse(bytes: &[u8], offset: &mut usize) -> error::Result<Self> {
        let dd = bytes.gread_with(offset, scroll::LE)?;
        Ok(dd)
    }
}

#[derive(Debug, PartialEq, Copy, Clone, Default)]
pub struct DataDirectories {
    pub data_directories: [Option<DataDirectory>; NUM_DATA_DIRECTORIES],
}

impl DataDirectories {
    pub fn parse(bytes: &[u8], count: usize, offset: &mut usize) -> error::Result<Self> {
        let mut data_directories = [None; NUM_DATA_DIRECTORIES];
        if count > NUM_DATA_DIRECTORIES {
            return Err(error::Error::Malformed(format!(
                "data directory count ({}) is greater than maximum number of data directories ({})",
                count, NUM_DATA_DIRECTORIES
            )));
        }
        for dir in data_directories.iter_mut().take(count) {
            let dd = DataDirectory::parse(bytes, offset)?;
            let dd = if dd.virtual_address == 0 && dd.size == 0 {
                None
            } else {
                Some(dd)
            };
            *dir = dd;
        }
        Ok(DataDirectories { data_directories })
    }
    pub fn get_export_table(&self) -> &Option<DataDirectory> {
        let idx = 0;
        &self.data_directories[idx]
    }
    pub fn get_import_table(&self) -> &Option<DataDirectory> {
        let idx = 1;
        &self.data_directories[idx]
    }
    pub fn get_resource_table(&self) -> &Option<DataDirectory> {
        let idx = 2;
        &self.data_directories[idx]
    }
    pub fn get_exception_table(&self) -> &Option<DataDirectory> {
        let idx = 3;
        &self.data_directories[idx]
    }
    pub fn get_certificate_table(&self) -> &Option<DataDirectory> {
        let idx = 4;
        &self.data_directories[idx]
    }
    pub fn get_base_relocation_table(&self) -> &Option<DataDirectory> {
        let idx = 5;
        &self.data_directories[idx]
    }
    pub fn get_debug_table(&self) -> &Option<DataDirectory> {
        let idx = 6;
        &self.data_directories[idx]
    }
    pub fn get_architecture(&self) -> &Option<DataDirectory> {
        let idx = 7;
        &self.data_directories[idx]
    }
    pub fn get_global_ptr(&self) -> &Option<DataDirectory> {
        let idx = 8;
        &self.data_directories[idx]
    }
    pub fn get_tls_table(&self) -> &Option<DataDirectory> {
        let idx = 9;
        &self.data_directories[idx]
    }
    pub fn get_load_config_table(&self) -> &Option<DataDirectory> {
        let idx = 10;
        &self.data_directories[idx]
    }
    pub fn get_bound_import_table(&self) -> &Option<DataDirectory> {
        let idx = 11;
        &self.data_directories[idx]
    }
    pub fn get_import_address_table(&self) -> &Option<DataDirectory> {
        let idx = 12;
        &self.data_directories[idx]
    }
    pub fn get_delay_import_descriptor(&self) -> &Option<DataDirectory> {
        let idx = 13;
        &self.data_directories[idx]
    }
    pub fn get_clr_runtime_header(&self) -> &Option<DataDirectory> {
        let idx = 14;
        &self.data_directories[idx]
    }
}
<|endoftext|>


<commit_before>use crate::schema::*;
use diesel::*;

#[test]
fn insert_from_table() {
    use crate::schema::posts::dsl::*;
    let conn = connection_with_sean_and_tess_in_users_table();
    insert_into(posts)
        .values(users::table)
        .into_columns((user_id, title, body))
        .execute(&conn)
        .unwrap();

    let data = posts.select((user_id, title, body)).load(&conn);
    let expected = vec![
        (1, String::from("Sean"), None::<String>),
        (2, String::from("Tess"), None),
    ];
    assert_eq!(Ok(expected), data);
}

#[test]
fn insert_from_table_reference() {
    use crate::schema::posts::dsl::*;
    let conn = connection_with_sean_and_tess_in_users_table();
    insert_into(posts)
        .values(&users::table)
        .into_columns((user_id, title, body))
        .execute(&conn)
        .unwrap();

    let data = posts.select((user_id, title, body)).load(&conn);
    let expected = vec![
        (1, String::from("Sean"), None::<String>),
        (2, String::from("Tess"), None),
    ];
    assert_eq!(Ok(expected), data);
}

#[test]
fn insert_from_select() {
    use crate::schema::posts::dsl::*;
    use crate::schema::users::dsl::{id, name, users};

    let conn = connection_with_sean_and_tess_in_users_table();
    users
        .select((id, name.concat(" says hi")))
        .insert_into(posts)
        .into_columns((user_id, title))
        .execute(&conn)
        .unwrap();

    let data = posts.select(title).load::<String>(&conn).unwrap();
    let expected = vec!["Sean says hi", "Tess says hi"];
    assert_eq!(expected, data);
}

#[test]
fn insert_from_select_reference() {
    use crate::schema::posts::dsl::*;
    use crate::schema::users::dsl::{id, name, users};

    let conn = connection_with_sean_and_tess_in_users_table();
    let select = users.select((id, name.concat(" says hi")));
    insert_into(posts)
        .values(&select)
        .into_columns((user_id, title))
        .execute(&conn)
        .unwrap();

    let data = posts.select(title).load::<String>(&conn).unwrap();
    let expected = vec!["Sean says hi", "Tess says hi"];
    assert_eq!(expected, data);
}

#[test]
fn insert_from_boxed() {
    use crate::schema::posts::dsl::*;
    use crate::schema::users::dsl::{id, name, users};

    let conn = connection_with_sean_and_tess_in_users_table();
    users
        .select((id, name.concat(" says hi")))
        .into_boxed()
        .insert_into(posts)
        .into_columns((user_id, title))
        .execute(&conn)
        .unwrap();

    let data = posts.select(title).load::<String>(&conn).unwrap();
    let expected = vec!["Sean says hi", "Tess says hi"];
    assert_eq!(expected, data);
}

#[test]
fn insert_from_boxed_reference() {
    use crate::schema::posts::dsl::*;
    use crate::schema::users::dsl::{id, name, users};

    let conn = connection_with_sean_and_tess_in_users_table();
    let select = users.select((id, name.concat(" says hi"))).into_boxed();
    insert_into(posts)
        .values(&select)
        .into_columns((user_id, title))
        .execute(&conn)
        .unwrap();

    let data = posts.select(title).load::<String>(&conn).unwrap();
    let expected = vec!["Sean says hi", "Tess says hi"];
    assert_eq!(expected, data);
}

#[test]
#[cfg(feature = "sqlite")]
fn insert_or_ignore_with_select() {
    use crate::schema::posts::dsl::*;
    use crate::schema::users::dsl::{id, name, users};

    let conn = connection_with_sean_and_tess_in_users_table();
    sql_query("CREATE UNIQUE INDEX foo ON posts (user_id)")
        .execute(&conn)
        .unwrap();

    insert_or_ignore_into(posts)
        .values(users.select((id, name.concat(" says hi"))))
        .into_columns((user_id, title))
        .execute(&conn)
        .unwrap();
    insert_or_ignore_into(posts)
        .values(users.select((id, name.concat(" says bye"))))
        .into_columns((user_id, title))
        .execute(&conn)
        .unwrap();

    let data = posts.select(title).load::<String>(&conn).unwrap();
    let expected = vec!["Sean says hi", "Tess says hi"];
    assert_eq!(expected, data);
}

#[test]
#[cfg(feature = "sqlite")]
fn insert_or_replace_with_select() {
    use crate::schema::posts::dsl::*;
    use crate::schema::users::dsl::{id, name, users};

    let conn = connection_with_sean_and_tess_in_users_table();
    sql_query("CREATE UNIQUE INDEX foo ON posts (user_id)")
        .execute(&conn)
        .unwrap();

    replace_into(posts)
        .values(users.select((id, name.concat(" says hi"))))
        .into_columns((user_id, title))
        .execute(&conn)
        .unwrap();
    replace_into(posts)
        .values(users.select((id, name.concat(" says bye"))))
        .into_columns((user_id, title))
        .execute(&conn)
        .unwrap();

    let data = posts.select(title).load::<String>(&conn).unwrap();
    let expected = vec!["Sean says bye", "Tess says bye"];
    assert_eq!(expected, data);
}

#[test]
#[cfg(feature = "mysql")]
// We can't share the test with SQLite because it modifies
// schema, but we can at least make sure the query is *syntactically* valid.
fn insert_or_ignore_with_select() {
    use crate::schema::posts::dsl::*;
    use crate::schema::users::dsl::{id, name, users};

    let conn = connection_with_sean_and_tess_in_users_table();

    insert_or_ignore_into(posts)
        .values(users.select((id, name.concat(" says hi"))))
        .into_columns((user_id, title))
        .execute(&conn)
        .unwrap();

    let data = posts.select(title).load::<String>(&conn).unwrap();
    let expected = vec!["Sean says hi", "Tess says hi"];
    assert_eq!(expected, data);
}

#[test]
#[cfg(feature = "mysql")]
// We can't share the test with SQLite because it modifies
// schema, but we can at least make sure the query is *syntactically* valid.
fn insert_or_replace_with_select() {
    use crate::schema::posts::dsl::*;
    use crate::schema::users::dsl::{id, name, users};

    let conn = connection_with_sean_and_tess_in_users_table();

    replace_into(posts)
        .values(users.select((id, name.concat(" says hi"))))
        .into_columns((user_id, title))
        .execute(&conn)
        .unwrap();

    let data = posts.select(title).load::<String>(&conn).unwrap();
    let expected = vec!["Sean says hi", "Tess says hi"];
    assert_eq!(expected, data);
}

#[test]
#[cfg(feature = "postgres")]
fn on_conflict_do_nothing_with_select() {
    use crate::schema::posts::dsl::*;
    use crate::schema::users::dsl::{id, name, users};

    let conn = connection_with_sean_and_tess_in_users_table();
    sql_query("CREATE UNIQUE INDEX ON posts (title)")
        .execute(&conn)
        .unwrap();
    let query = users
        .select((id, name.concat(" says hi")))
        .insert_into(posts)
        .into_columns((user_id, title))
        .on_conflict_do_nothing();

    let inserted_rows = query.execute(&conn).unwrap();
    assert_eq!(2, inserted_rows);
    let inserted_rows = query.execute(&conn).unwrap();
    assert_eq!(0, inserted_rows);

    let data = posts.select(title).load::<String>(&conn).unwrap();
    let expected = vec!["Sean says hi", "Tess says hi"];
    assert_eq!(expected, data);
}

#[test]
#[cfg(feature = "postgres")]
fn on_conflict_do_update_with_select() {
    use crate::schema::posts::dsl::*;
    use crate::schema::users::dsl::{id, name, users};

    let conn = connection_with_sean_and_tess_in_users_table();
    sql_query("CREATE UNIQUE INDEX ON posts (title)")
        .execute(&conn)
        .unwrap();
    let query = users
        .select((id, name.concat(" says hi")))
        .insert_into(posts)
        .into_columns((user_id, title))
        .on_conflict(title)
        .do_update()
        .set(body.eq("updated"));

    query.execute(&conn).unwrap();

    insert_into(users)
        .values(name.eq("Ruby"))
        .execute(&conn)
        .unwrap();

    query.execute(&conn).unwrap();

    let data = posts.select((title, body)).load(&conn).unwrap();
    let expected = vec![
        (String::from("Sean says hi"), Some(String::from("updated"))),
        (String::from("Tess says hi"), Some(String::from("updated"))),
        (String::from("Ruby says hi"), None),
    ];
    assert_eq!(expected, data);
}
<commit_msg>Add sqlite fail case test<commit_after>use crate::schema::*;
use diesel::*;

#[test]
fn insert_from_table() {
    use crate::schema::posts::dsl::*;
    let conn = connection_with_sean_and_tess_in_users_table();
    insert_into(posts)
        .values(users::table)
        .into_columns((user_id, title, body))
        .execute(&conn)
        .unwrap();

    let data = posts.select((user_id, title, body)).load(&conn);
    let expected = vec![
        (1, String::from("Sean"), None::<String>),
        (2, String::from("Tess"), None),
    ];
    assert_eq!(Ok(expected), data);
}

#[test]
fn insert_from_table_reference() {
    use crate::schema::posts::dsl::*;
    let conn = connection_with_sean_and_tess_in_users_table();
    insert_into(posts)
        .values(&users::table)
        .into_columns((user_id, title, body))
        .execute(&conn)
        .unwrap();

    let data = posts.select((user_id, title, body)).load(&conn);
    let expected = vec![
        (1, String::from("Sean"), None::<String>),
        (2, String::from("Tess"), None),
    ];
    assert_eq!(Ok(expected), data);
}

#[test]
fn insert_from_select() {
    use crate::schema::posts::dsl::*;
    use crate::schema::users::dsl::{id, name, users};

    let conn = connection_with_sean_and_tess_in_users_table();
    users
        .select((id, name.concat(" says hi")))
        .insert_into(posts)
        .into_columns((user_id, title))
        .execute(&conn)
        .unwrap();

    let data = posts.select(title).load::<String>(&conn).unwrap();
    let expected = vec!["Sean says hi", "Tess says hi"];
    assert_eq!(expected, data);
}

#[test]
fn insert_from_select_reference() {
    use crate::schema::posts::dsl::*;
    use crate::schema::users::dsl::{id, name, users};

    let conn = connection_with_sean_and_tess_in_users_table();
    let select = users.select((id, name.concat(" says hi")));
    insert_into(posts)
        .values(&select)
        .into_columns((user_id, title))
        .execute(&conn)
        .unwrap();

    let data = posts.select(title).load::<String>(&conn).unwrap();
    let expected = vec!["Sean says hi", "Tess says hi"];
    assert_eq!(expected, data);
}

#[test]
fn insert_from_boxed() {
    use crate::schema::posts::dsl::*;
    use crate::schema::users::dsl::{id, name, users};

    let conn = connection_with_sean_and_tess_in_users_table();
    users
        .select((id, name.concat(" says hi")))
        .into_boxed()
        .insert_into(posts)
        .into_columns((user_id, title))
        .execute(&conn)
        .unwrap();

    let data = posts.select(title).load::<String>(&conn).unwrap();
    let expected = vec!["Sean says hi", "Tess says hi"];
    assert_eq!(expected, data);
}

#[test]
fn insert_from_boxed_reference() {
    use crate::schema::posts::dsl::*;
    use crate::schema::users::dsl::{id, name, users};

    let conn = connection_with_sean_and_tess_in_users_table();
    let select = users.select((id, name.concat(" says hi"))).into_boxed();
    insert_into(posts)
        .values(&select)
        .into_columns((user_id, title))
        .execute(&conn)
        .unwrap();

    let data = posts.select(title).load::<String>(&conn).unwrap();
    let expected = vec!["Sean says hi", "Tess says hi"];
    assert_eq!(expected, data);
}

#[test]
#[cfg(feature = "sqlite")]
fn insert_or_ignore_with_select() {
    use crate::schema::posts::dsl::*;
    use crate::schema::users::dsl::{id, name, users};

    let conn = connection_with_sean_and_tess_in_users_table();
    sql_query("CREATE UNIQUE INDEX foo ON posts (user_id)")
        .execute(&conn)
        .unwrap();

    insert_or_ignore_into(posts)
        .values(users.select((id, name.concat(" says hi"))))
        .into_columns((user_id, title))
        .execute(&conn)
        .unwrap();
    insert_or_ignore_into(posts)
        .values(users.select((id, name.concat(" says bye"))))
        .into_columns((user_id, title))
        .execute(&conn)
        .unwrap();

    let data = posts.select(title).load::<String>(&conn).unwrap();
    let expected = vec!["Sean says hi", "Tess says hi"];
    assert_eq!(expected, data);
}

#[test]
#[cfg(feature = "sqlite")]
fn insert_or_replace_with_select() {
    use crate::schema::posts::dsl::*;
    use crate::schema::users::dsl::{id, name, users};

    let conn = connection_with_sean_and_tess_in_users_table();
    sql_query("CREATE UNIQUE INDEX foo ON posts (user_id)")
        .execute(&conn)
        .unwrap();

    replace_into(posts)
        .values(users.select((id, name.concat(" says hi"))))
        .into_columns((user_id, title))
        .execute(&conn)
        .unwrap();
    replace_into(posts)
        .values(users.select((id, name.concat(" says bye"))))
        .into_columns((user_id, title))
        .execute(&conn)
        .unwrap();

    let data = posts.select(title).load::<String>(&conn).unwrap();
    let expected = vec!["Sean says bye", "Tess says bye"];
    assert_eq!(expected, data);
}

#[test]
#[cfg(feature = "mysql")]
// We can't share the test with SQLite because it modifies
// schema, but we can at least make sure the query is *syntactically* valid.
fn insert_or_ignore_with_select() {
    use crate::schema::posts::dsl::*;
    use crate::schema::users::dsl::{id, name, users};

    let conn = connection_with_sean_and_tess_in_users_table();

    insert_or_ignore_into(posts)
        .values(users.select((id, name.concat(" says hi"))))
        .into_columns((user_id, title))
        .execute(&conn)
        .unwrap();

    let data = posts.select(title).load::<String>(&conn).unwrap();
    let expected = vec!["Sean says hi", "Tess says hi"];
    assert_eq!(expected, data);
}

#[test]
#[cfg(feature = "mysql")]
// We can't share the test with SQLite because it modifies
// schema, but we can at least make sure the query is *syntactically* valid.
fn insert_or_replace_with_select() {
    use crate::schema::posts::dsl::*;
    use crate::schema::users::dsl::{id, name, users};

    let conn = connection_with_sean_and_tess_in_users_table();

    replace_into(posts)
        .values(users.select((id, name.concat(" says hi"))))
        .into_columns((user_id, title))
        .execute(&conn)
        .unwrap();

    let data = posts.select(title).load::<String>(&conn).unwrap();
    let expected = vec!["Sean says hi", "Tess says hi"];
    assert_eq!(expected, data);
}

#[test]
#[cfg(feature = "postgres")]
fn on_conflict_do_nothing_with_select() {
    use crate::schema::posts::dsl::*;
    use crate::schema::users::dsl::{id, name, users};

    let conn = connection_with_sean_and_tess_in_users_table();

    sql_query("CREATE UNIQUE INDEX ON posts (title)")
        .execute(&conn)
        .unwrap();
    let query = users
        .select((id, name.concat(" says hi")))
        .insert_into(posts)
        .into_columns((user_id, title))
        .on_conflict_do_nothing();

    let inserted_rows = query.execute(&conn).unwrap();
    assert_eq!(2, inserted_rows);
    let inserted_rows = query.execute(&conn).unwrap();
    assert_eq!(0, inserted_rows);

    let data = posts.select(title).load::<String>(&conn).unwrap();
    let expected = vec!["Sean says hi", "Tess says hi"];
    assert_eq!(expected, data);
}

// FIXME: sqlite needs 'WHERE clause' if we use 'ON CONFLICT clause' with 'InsertFromSelect'.
#[test]
#[should_panic]
#[cfg(feature = "sqlite")]
fn on_conflict_do_nothing_with_select_for_sqlite() {
    use schema::posts::dsl::*;
    use schema::users::dsl::{id, name, users};

    let conn = connection_with_sean_and_tess_in_users_table();

    sql_query("CREATE UNIQUE INDEX index_on_title  ON posts (title)")
        .execute(&conn)
        .unwrap();
    let query = users
        .select((id, name.concat(" says hi")))
        .insert_into(posts)
        .into_columns((user_id, title))
        .on_conflict_do_nothing();

    let inserted_rows = query.execute(&conn).unwrap();
    assert_eq!(2, inserted_rows);
    let inserted_rows = query.execute(&conn).unwrap();
    assert_eq!(0, inserted_rows);

    let data = posts.select(title).load::<String>(&conn).unwrap();
    let expected = vec!["Sean says hi", "Tess says hi"];
    assert_eq!(expected, data);
}

#[test]
#[cfg(feature = "postgres")]
fn on_conflict_do_update_with_select() {
    use crate::schema::posts::dsl::*;
    use crate::schema::users::dsl::{id, name, users};

    let conn = connection_with_sean_and_tess_in_users_table();

    #[cfg(feature = "postgres")]
    sql_query("CREATE UNIQUE INDEX ON posts (title)")
        .execute(&conn)
        .unwrap();
    let query = users
        .select((id, name.concat(" says hi")))
        .insert_into(posts)
        .into_columns((user_id, title))
        .on_conflict(title)
        .do_update()
        .set(body.eq("updated"));

    query.execute(&conn).unwrap();

    insert_into(users)
        .values(name.eq("Ruby"))
        .execute(&conn)
        .unwrap();

    query.execute(&conn).unwrap();

    let data = posts.select((title, body)).load(&conn).unwrap();
    let expected = vec![
        (String::from("Sean says hi"), Some(String::from("updated"))),
        (String::from("Tess says hi"), Some(String::from("updated"))),
        (String::from("Ruby says hi"), None),
    ];
    assert_eq!(expected, data);
}

// FIXME: sqlite needs 'WHERE clause' if we use 'ON CONFLICT clause' with 'InsertFromSelect'.
#[test]
#[should_panic]
#[cfg(feature = "sqlite")]
fn on_conflict_do_update_with_select_for_sqlite() {
    use schema::posts::dsl::*;
    use schema::users::dsl::{id, name, users};

    let conn = connection_with_sean_and_tess_in_users_table();

    sql_query("CREATE UNIQUE INDEX index_on_title  ON posts (title)")
        .execute(&conn)
        .unwrap();
    let query = users
        .select((id, name.concat(" says hi")))
        .insert_into(posts)
        .into_columns((user_id, title))
        .on_conflict(title)
        .do_update()
        .set(body.eq("updated"));

    query.execute(&conn).unwrap();

    insert_into(users)
        .values(name.eq("Ruby"))
        .execute(&conn)
        .unwrap();

    query.execute(&conn).unwrap();

    let data = posts.select((title, body)).load(&conn).unwrap();
    let expected = vec![
        (String::from("Sean says hi"), Some(String::from("updated"))),
        (String::from("Tess says hi"), Some(String::from("updated"))),
        (String::from("Ruby says hi"), None),
    ];
    assert_eq!(expected, data);
}
<|endoftext|>