versa 1.9.0-rc2

Versa types and utilities for developing Versa client applications in Rust
Documentation
use serde::{Deserialize, Serialize};
use std::fmt;

#[cfg(feature = "diesel")]
use std::io::Write;

#[cfg(feature = "diesel")]
use diesel::deserialize::{self, FromSql, FromSqlRow};
#[cfg(feature = "diesel")]
use diesel::prelude::*;
#[cfg(feature = "diesel")]
use diesel::serialize::{self, IsNull, Output, ToSql};
#[cfg(feature = "diesel")]
use diesel::{expression::AsExpression, sql_types::Text};

#[cfg(feature = "diesel")]
use diesel::mysql::{Mysql, MysqlValue};

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(
  feature = "diesel",
  derive(diesel::expression::AsExpression, diesel::deserialize::FromSqlRow)
)]
#[cfg_attr(feature = "diesel", diesel(sql_type = Text))]
pub enum MisuseCode {
  /// Decrypting the received receipt JSON failed
  ProtocolDecryptionFailed,
  /// Decryption succeeded, but the payload was not valid JSON
  ProtocolDeserializationFailed,
  /// Schema validation of the receipt failed, according to its provided schema version
  SchemaValidationFailed,
  /// The schema version provided is invalid, or does not exist
  SchemaVersionInvalid,
  /// Schema validation failed because the schema version was valid but not recognized; which may indicate an out-of-date implementation
  SchemaVersionUnknown,
  /// Semantic validation returned one or more violations
  SemanticValidationFailed,
}

impl fmt::Display for MisuseCode {
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    let job = match self {
      MisuseCode::ProtocolDecryptionFailed => "protocol_decryption_failed",
      MisuseCode::ProtocolDeserializationFailed => "protocol_deserialization_failed",
      MisuseCode::SchemaValidationFailed => "schema_validation_failed",
      MisuseCode::SchemaVersionInvalid => "schema_version_invalid",
      MisuseCode::SchemaVersionUnknown => "schema_version_unknown",
      MisuseCode::SemanticValidationFailed => "semantic_validation_failed",
    };
    write!(f, "{}", job)
  }
}

#[cfg(feature = "diesel")]
impl ToSql<Text, Mysql> for MisuseCode {
  fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
    out.write_all(&*self.to_string().as_bytes())?;
    Ok(IsNull::No)
  }
}

#[cfg(feature = "diesel")]
impl FromSql<Text, Mysql> for MisuseCode {
  fn from_sql(bytes: MysqlValue<'_>) -> deserialize::Result<Self> {
    match bytes.as_bytes() {
      b"protocol_decryption_failed" => Ok(MisuseCode::ProtocolDecryptionFailed),
      b"protocol_deserialization_failed" => Ok(MisuseCode::ProtocolDeserializationFailed),
      b"schema_version_invalid" => Ok(MisuseCode::SchemaVersionInvalid),
      b"schema_validation_failed" => Ok(MisuseCode::SchemaValidationFailed),
      b"schema_version_unknown" => Ok(MisuseCode::SchemaVersionUnknown),
      b"semantic_validation_failed" => Ok(MisuseCode::SemanticValidationFailed),
      _ => Err("Unrecognized misuse_code enum variant".into()),
    }
  }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct ReportMisuseRequest {
  pub receipt_id: String,
  pub misuse: Vec<Misuse>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Misuse {
  pub code: MisuseCode,
  pub rule: Option<String>,
  pub description: Option<String>,
}

impl Misuse {
  pub fn from(code: MisuseCode) -> Self {
    Misuse {
      code,
      rule: None,
      description: None,
    }
  }
  pub fn with_rule(self, rule: String) -> Self {
    Misuse {
      rule: Some(rule),
      ..self
    }
  }
  pub fn with_description(self, description: String) -> Self {
    Misuse {
      description: Some(description),
      ..self
    }
  }
}