1use serde::{Deserialize, Serialize};
2
3use crate::{GateValidationError, Obligation};
4
5#[derive(Clone, Debug, Serialize)]
10#[serde(tag = "decision", rename_all = "snake_case")]
11pub enum GateDecision {
12 Allow {
13 #[serde(default, skip_serializing_if = "Vec::is_empty")]
14 obligations: Vec<Obligation>,
15 },
16 Deny {
17 reason: String,
18 },
19}
20
21#[derive(Deserialize)]
23#[serde(tag = "decision", rename_all = "snake_case")]
24enum RawGateDecision {
25 Allow {
26 #[serde(default)]
27 obligations: Vec<Obligation>,
28 },
29 Deny {
30 reason: String,
31 },
32}
33
34impl TryFrom<RawGateDecision> for GateDecision {
35 type Error = GateValidationError;
36
37 fn try_from(raw: RawGateDecision) -> Result<Self, Self::Error> {
38 match raw {
39 RawGateDecision::Allow { obligations } => Ok(GateDecision::Allow { obligations }),
40 RawGateDecision::Deny { reason } => {
41 if reason.is_empty() {
42 return Err(GateValidationError::EmptyDenyReason);
43 }
44 Ok(GateDecision::Deny { reason })
45 }
46 }
47 }
48}
49
50impl<'de> Deserialize<'de> for GateDecision {
51 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
52 where
53 D: serde::Deserializer<'de>,
54 {
55 let raw = RawGateDecision::deserialize(deserializer)?;
56 GateDecision::try_from(raw).map_err(serde::de::Error::custom)
57 }
58}
59
60impl GateDecision {
61 pub fn allow() -> Self {
63 Self::Allow {
64 obligations: Vec::new(),
65 }
66 }
67
68 pub fn allow_with(obligations: Vec<Obligation>) -> Self {
70 Self::Allow { obligations }
71 }
72
73 pub fn try_deny(reason: impl Into<String>) -> Result<Self, GateValidationError> {
75 let reason = reason.into();
76 if reason.is_empty() {
77 return Err(GateValidationError::EmptyDenyReason);
78 }
79 Ok(Self::Deny { reason })
80 }
81
82 pub fn deny(reason: impl Into<String>) -> Self {
84 Self::try_deny(reason).expect("GateDecision::deny: reason must not be empty")
85 }
86
87 pub fn is_allow(&self) -> bool {
89 matches!(self, Self::Allow { .. })
90 }
91}