use serde::{Deserialize, Serialize};
use crate::{GateValidationError, Obligation};
#[derive(Clone, Debug, Serialize)]
#[serde(tag = "decision", rename_all = "snake_case")]
pub enum GateDecision {
Allow {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
obligations: Vec<Obligation>,
},
Deny {
reason: String,
},
}
#[derive(Deserialize)]
#[serde(tag = "decision", rename_all = "snake_case")]
enum RawGateDecision {
Allow {
#[serde(default)]
obligations: Vec<Obligation>,
},
Deny {
reason: String,
},
}
impl TryFrom<RawGateDecision> for GateDecision {
type Error = GateValidationError;
fn try_from(raw: RawGateDecision) -> Result<Self, Self::Error> {
match raw {
RawGateDecision::Allow { obligations } => Ok(GateDecision::Allow { obligations }),
RawGateDecision::Deny { reason } => {
if reason.is_empty() {
return Err(GateValidationError::EmptyDenyReason);
}
Ok(GateDecision::Deny { reason })
}
}
}
}
impl<'de> Deserialize<'de> for GateDecision {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let raw = RawGateDecision::deserialize(deserializer)?;
GateDecision::try_from(raw).map_err(serde::de::Error::custom)
}
}
impl GateDecision {
pub fn allow() -> Self {
Self::Allow {
obligations: Vec::new(),
}
}
pub fn allow_with(obligations: Vec<Obligation>) -> Self {
Self::Allow { obligations }
}
pub fn try_deny(reason: impl Into<String>) -> Result<Self, GateValidationError> {
let reason = reason.into();
if reason.is_empty() {
return Err(GateValidationError::EmptyDenyReason);
}
Ok(Self::Deny { reason })
}
pub fn deny(reason: impl Into<String>) -> Self {
Self::try_deny(reason).expect("GateDecision::deny: reason must not be empty")
}
pub fn is_allow(&self) -> bool {
matches!(self, Self::Allow { .. })
}
}