1use crate::{
2 ClauseLabel, Condition, DenyShape, GatekeepResult, ObligationId, ObligationSpec, Policy,
3 ReasonCode,
4};
5
6#[must_use]
8pub const fn permit<O>(outcome: O) -> Policy<O> {
9 Policy::Permit(outcome)
10}
11
12#[must_use]
14pub const fn deny<O>() -> Policy<O> {
15 Policy::Deny
16}
17
18#[must_use]
24pub fn deny_when<O: crate::Lattice>(
25 condition: Condition,
26 reason: impl IntoReasonCode,
27) -> Policy<O> {
28 grant(O::top(), crate::condition::not(condition)).reason(reason)
29}
30
31#[must_use]
33pub const fn grant<O>(outcome: O, condition: Condition) -> Policy<O> {
34 Policy::Grant {
35 outcome,
36 condition,
37 label: None,
38 deny_shape: DenyShape::Forbidden,
39 obligations: Vec::new(),
40 reason: None,
41 }
42}
43
44#[must_use]
50pub const fn grant_clause<O>(outcome: O, condition: Condition) -> GrantPolicy<O> {
51 GrantPolicy {
52 outcome,
53 condition,
54 label: None,
55 deny_shape: DenyShape::Forbidden,
56 obligations: Vec::new(),
57 reason: None,
58 }
59}
60
61#[derive(Clone, Debug, PartialEq, Eq)]
63pub struct GrantPolicy<O> {
64 outcome: O,
65 condition: Condition,
66 label: Option<ClauseLabel>,
67 deny_shape: DenyShape,
68 obligations: Vec<ObligationId>,
69 reason: Option<ReasonCode>,
70}
71
72impl<O> GrantPolicy<O> {
73 #[must_use]
75 pub fn into_policy(self) -> Policy<O> {
76 Policy::Grant {
77 outcome: self.outcome,
78 condition: self.condition,
79 label: self.label,
80 deny_shape: self.deny_shape,
81 obligations: self.obligations,
82 reason: self.reason,
83 }
84 }
85
86 #[must_use]
88 pub fn labeled(mut self, label: impl IntoLabel) -> Self {
89 self.label = Some(label.into_label());
90 self
91 }
92
93 pub fn try_labeled(self, label: impl Into<String>) -> GatekeepResult<Self> {
100 Ok(self.labeled(ClauseLabel::new(label)?))
101 }
102
103 #[must_use]
105 pub const fn hidden(mut self) -> Self {
106 self.deny_shape = DenyShape::Hidden;
107 self
108 }
109
110 #[must_use]
112 pub fn reason(mut self, reason: impl IntoReasonCode) -> Self {
113 self.reason = Some(reason.into_reason_code());
114 self
115 }
116
117 pub fn try_reason(self, reason: impl Into<String>) -> GatekeepResult<Self> {
124 Ok(self.reason(ReasonCode::new(reason)?))
125 }
126
127 #[must_use]
129 pub fn with_obligation<S: ObligationSpec>(mut self) -> Self {
130 self.obligations
131 .push(ObligationId::from_trusted(S::ID.as_str()));
132 self
133 }
134}
135
136impl<O> From<GrantPolicy<O>> for Policy<O> {
137 fn from(grant: GrantPolicy<O>) -> Self {
138 grant.into_policy()
139 }
140}
141
142#[must_use]
144pub fn all<O>(policies: impl IntoIterator<Item = Policy<O>>) -> Policy<O> {
145 let policies = policies.into_iter().collect::<Vec<_>>();
146 if policies.is_empty() {
147 Policy::Deny
148 } else {
149 Policy::All(policies)
150 }
151}
152
153#[must_use]
155pub fn any<O>(policies: impl IntoIterator<Item = Policy<O>>) -> Policy<O> {
156 let policies = policies.into_iter().collect::<Vec<_>>();
157 if policies.is_empty() {
158 Policy::Deny
159 } else {
160 Policy::Any(policies)
161 }
162}
163
164#[must_use]
166pub fn or_else<O>(primary: Policy<O>, fallback: Policy<O>) -> Policy<O> {
167 Policy::OrElse {
168 primary: Box::new(primary),
169 fallback: Box::new(fallback),
170 }
171}
172
173impl<O> Policy<O> {
174 #[must_use]
176 pub fn labeled(mut self, label: impl IntoLabel) -> Self {
177 if let Self::Grant {
178 label: grant_label, ..
179 } = &mut self
180 {
181 *grant_label = Some(label.into_label());
182 }
183 self
184 }
185
186 pub fn try_labeled(self, label: impl Into<String>) -> GatekeepResult<Self> {
193 Ok(self.labeled(ClauseLabel::new(label)?))
194 }
195
196 #[must_use]
198 pub const fn hidden(mut self) -> Self {
199 if let Self::Grant { deny_shape, .. } = &mut self {
200 *deny_shape = crate::DenyShape::Hidden;
201 }
202 self
203 }
204
205 #[must_use]
207 pub fn reason(mut self, reason: impl IntoReasonCode) -> Self {
208 if let Self::Grant {
209 reason: grant_reason,
210 ..
211 } = &mut self
212 {
213 *grant_reason = Some(reason.into_reason_code());
214 }
215 self
216 }
217
218 pub fn try_reason(self, reason: impl Into<String>) -> GatekeepResult<Self> {
225 Ok(self.reason(ReasonCode::new(reason)?))
226 }
227
228 #[must_use]
230 pub fn with_obligation<S: ObligationSpec>(mut self) -> Self {
231 if let Self::Grant { obligations, .. } = &mut self {
232 obligations.push(crate::ObligationId::from_trusted(S::ID.as_str()));
233 }
234 self
235 }
236}
237
238pub trait IntoLabel {
240 fn into_label(self) -> ClauseLabel;
242}
243
244impl IntoLabel for ClauseLabel {
245 fn into_label(self) -> ClauseLabel {
246 self
247 }
248}
249
250pub trait IntoReasonCode {
252 fn into_reason_code(self) -> ReasonCode;
254}
255
256impl IntoReasonCode for ReasonCode {
257 fn into_reason_code(self) -> ReasonCode {
258 self
259 }
260}