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