1use super::{EstToAstError, InstantiationError};
18use crate::ast;
19use crate::entities::{EntityUidJSON, JsonDeserializationErrorContext};
20use serde::{Deserialize, Serialize};
21use std::collections::HashMap;
22use std::sync::Arc;
23
24#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
26#[serde(deny_unknown_fields)]
27#[serde(tag = "op")]
28pub enum PrincipalConstraint {
29 All,
31 #[serde(rename = "==")]
33 Eq(EqConstraint),
34 #[serde(rename = "in")]
36 In(PrincipalOrResourceInConstraint),
37}
38
39#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
41#[serde(deny_unknown_fields)]
42#[serde(tag = "op")]
43pub enum ActionConstraint {
44 All,
46 #[serde(rename = "==")]
48 Eq(EqConstraint),
49 #[serde(rename = "in")]
51 In(ActionInConstraint),
52}
53
54#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
56#[serde(deny_unknown_fields)]
57#[serde(tag = "op")]
58pub enum ResourceConstraint {
59 All,
61 #[serde(rename = "==")]
63 Eq(EqConstraint),
64 #[serde(rename = "in")]
66 In(PrincipalOrResourceInConstraint),
67}
68
69#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
71#[serde(untagged)]
72pub enum EqConstraint {
73 Entity {
75 entity: EntityUidJSON,
77 },
78 Slot {
80 slot: ast::SlotId,
82 },
83}
84
85#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
88#[serde(untagged)]
89pub enum PrincipalOrResourceInConstraint {
90 Entity {
92 entity: EntityUidJSON,
94 },
95 Slot {
97 slot: ast::SlotId,
99 },
100}
101
102#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
105#[serde(untagged)]
106pub enum ActionInConstraint {
107 Single {
109 entity: EntityUidJSON,
111 },
112 Set {
114 entities: Vec<EntityUidJSON>,
116 },
117}
118
119impl PrincipalConstraint {
120 pub fn instantiate(
124 self,
125 vals: &HashMap<ast::SlotId, EntityUidJSON>,
126 ) -> Result<Self, InstantiationError> {
127 match self {
128 PrincipalConstraint::All => Ok(PrincipalConstraint::All),
129 PrincipalConstraint::Eq(EqConstraint::Entity { entity }) => {
130 Ok(PrincipalConstraint::Eq(EqConstraint::Entity { entity }))
131 }
132 PrincipalConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }) => Ok(
133 PrincipalConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }),
134 ),
135 PrincipalConstraint::Eq(EqConstraint::Slot { slot }) => match vals.get(&slot) {
136 Some(val) => Ok(PrincipalConstraint::Eq(EqConstraint::Entity {
137 entity: val.clone(),
138 })),
139 None => Err(InstantiationError::MissedSlot { slot }),
140 },
141 PrincipalConstraint::In(PrincipalOrResourceInConstraint::Slot { slot }) => {
142 match vals.get(&slot) {
143 Some(val) => Ok(PrincipalConstraint::In(
144 PrincipalOrResourceInConstraint::Entity {
145 entity: val.clone(),
146 },
147 )),
148 None => Err(InstantiationError::MissedSlot { slot }),
149 }
150 }
151 }
152 }
153}
154
155impl ResourceConstraint {
156 pub fn instantiate(
160 self,
161 vals: &HashMap<ast::SlotId, EntityUidJSON>,
162 ) -> Result<Self, InstantiationError> {
163 match self {
164 ResourceConstraint::All => Ok(ResourceConstraint::All),
165 ResourceConstraint::Eq(EqConstraint::Entity { entity }) => {
166 Ok(ResourceConstraint::Eq(EqConstraint::Entity { entity }))
167 }
168 ResourceConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }) => Ok(
169 ResourceConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }),
170 ),
171 ResourceConstraint::Eq(EqConstraint::Slot { slot }) => match vals.get(&slot) {
172 Some(val) => Ok(ResourceConstraint::Eq(EqConstraint::Entity {
173 entity: val.clone(),
174 })),
175 None => Err(InstantiationError::MissedSlot { slot }),
176 },
177 ResourceConstraint::In(PrincipalOrResourceInConstraint::Slot { slot }) => {
178 match vals.get(&slot) {
179 Some(val) => Ok(ResourceConstraint::In(
180 PrincipalOrResourceInConstraint::Entity {
181 entity: val.clone(),
182 },
183 )),
184 None => Err(InstantiationError::MissedSlot { slot }),
185 }
186 }
187 }
188 }
189}
190
191impl ActionConstraint {
192 pub fn instantiate(
196 self,
197 _vals: &HashMap<ast::SlotId, EntityUidJSON>,
198 ) -> Result<Self, InstantiationError> {
199 Ok(self)
201 }
202}
203
204impl From<ast::PrincipalConstraint> for PrincipalConstraint {
205 fn from(constraint: ast::PrincipalConstraint) -> PrincipalConstraint {
206 constraint.constraint.into()
207 }
208}
209
210impl TryFrom<PrincipalConstraint> for ast::PrincipalConstraint {
211 type Error = EstToAstError;
212 fn try_from(
213 constraint: PrincipalConstraint,
214 ) -> Result<ast::PrincipalConstraint, EstToAstError> {
215 constraint.try_into().map(ast::PrincipalConstraint::new)
216 }
217}
218
219impl From<ast::ResourceConstraint> for ResourceConstraint {
220 fn from(constraint: ast::ResourceConstraint) -> ResourceConstraint {
221 constraint.constraint.into()
222 }
223}
224
225impl TryFrom<ResourceConstraint> for ast::ResourceConstraint {
226 type Error = EstToAstError;
227 fn try_from(constraint: ResourceConstraint) -> Result<ast::ResourceConstraint, EstToAstError> {
228 constraint.try_into().map(ast::ResourceConstraint::new)
229 }
230}
231
232impl From<ast::PrincipalOrResourceConstraint> for PrincipalConstraint {
233 fn from(constraint: ast::PrincipalOrResourceConstraint) -> PrincipalConstraint {
234 match constraint {
235 ast::PrincipalOrResourceConstraint::Any => PrincipalConstraint::All,
236 ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::EUID(e)) => {
237 PrincipalConstraint::Eq(EqConstraint::Entity {
238 entity: EntityUidJSON::ImplicitEntityEscape((&*e).into()),
239 })
240 }
241 ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::Slot) => {
242 PrincipalConstraint::Eq(EqConstraint::Slot {
243 slot: ast::SlotId::principal(),
244 })
245 }
246 ast::PrincipalOrResourceConstraint::In(ast::EntityReference::EUID(e)) => {
247 PrincipalConstraint::In(PrincipalOrResourceInConstraint::Entity {
248 entity: EntityUidJSON::ImplicitEntityEscape((&*e).into()),
249 })
250 }
251 ast::PrincipalOrResourceConstraint::In(ast::EntityReference::Slot) => {
252 PrincipalConstraint::In(PrincipalOrResourceInConstraint::Slot {
253 slot: ast::SlotId::principal(),
254 })
255 }
256 }
257 }
258}
259
260impl From<ast::PrincipalOrResourceConstraint> for ResourceConstraint {
261 fn from(constraint: ast::PrincipalOrResourceConstraint) -> ResourceConstraint {
262 match constraint {
263 ast::PrincipalOrResourceConstraint::Any => ResourceConstraint::All,
264 ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::EUID(e)) => {
265 ResourceConstraint::Eq(EqConstraint::Entity {
266 entity: EntityUidJSON::ImplicitEntityEscape((&*e).into()),
267 })
268 }
269 ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::Slot) => {
270 ResourceConstraint::Eq(EqConstraint::Slot {
271 slot: ast::SlotId::resource(),
272 })
273 }
274 ast::PrincipalOrResourceConstraint::In(ast::EntityReference::EUID(e)) => {
275 ResourceConstraint::In(PrincipalOrResourceInConstraint::Entity {
276 entity: EntityUidJSON::ImplicitEntityEscape((&*e).into()),
277 })
278 }
279 ast::PrincipalOrResourceConstraint::In(ast::EntityReference::Slot) => {
280 ResourceConstraint::In(PrincipalOrResourceInConstraint::Slot {
281 slot: ast::SlotId::resource(),
282 })
283 }
284 }
285 }
286}
287
288impl TryFrom<PrincipalConstraint> for ast::PrincipalOrResourceConstraint {
289 type Error = EstToAstError;
290 fn try_from(
291 constraint: PrincipalConstraint,
292 ) -> Result<ast::PrincipalOrResourceConstraint, EstToAstError> {
293 match constraint {
294 PrincipalConstraint::All => Ok(ast::PrincipalOrResourceConstraint::Any),
295 PrincipalConstraint::Eq(EqConstraint::Entity { entity }) => Ok(
296 ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::EUID(Arc::new(
297 entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
298 ))),
299 ),
300 PrincipalConstraint::Eq(EqConstraint::Slot { slot }) => {
301 if slot == ast::SlotId::principal() {
302 Ok(ast::PrincipalOrResourceConstraint::Eq(
303 ast::EntityReference::Slot,
304 ))
305 } else {
306 Err(EstToAstError::InvalidSlotName)
307 }
308 }
309 PrincipalConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }) => Ok(
310 ast::PrincipalOrResourceConstraint::In(ast::EntityReference::EUID(Arc::new(
311 entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
312 ))),
313 ),
314 PrincipalConstraint::In(PrincipalOrResourceInConstraint::Slot { slot }) => {
315 if slot == ast::SlotId::principal() {
316 Ok(ast::PrincipalOrResourceConstraint::In(
317 ast::EntityReference::Slot,
318 ))
319 } else {
320 Err(EstToAstError::InvalidSlotName)
321 }
322 }
323 }
324 }
325}
326
327impl TryFrom<ResourceConstraint> for ast::PrincipalOrResourceConstraint {
328 type Error = EstToAstError;
329 fn try_from(
330 constraint: ResourceConstraint,
331 ) -> Result<ast::PrincipalOrResourceConstraint, EstToAstError> {
332 match constraint {
333 ResourceConstraint::All => Ok(ast::PrincipalOrResourceConstraint::Any),
334 ResourceConstraint::Eq(EqConstraint::Entity { entity }) => Ok(
335 ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::EUID(Arc::new(
336 entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
337 ))),
338 ),
339 ResourceConstraint::Eq(EqConstraint::Slot { slot }) => {
340 if slot == ast::SlotId::resource() {
341 Ok(ast::PrincipalOrResourceConstraint::Eq(
342 ast::EntityReference::Slot,
343 ))
344 } else {
345 Err(EstToAstError::InvalidSlotName)
346 }
347 }
348 ResourceConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }) => Ok(
349 ast::PrincipalOrResourceConstraint::In(ast::EntityReference::EUID(Arc::new(
350 entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
351 ))),
352 ),
353 ResourceConstraint::In(PrincipalOrResourceInConstraint::Slot { slot }) => {
354 if slot == ast::SlotId::resource() {
355 Ok(ast::PrincipalOrResourceConstraint::In(
356 ast::EntityReference::Slot,
357 ))
358 } else {
359 Err(EstToAstError::InvalidSlotName)
360 }
361 }
362 }
363 }
364}
365
366impl From<ast::ActionConstraint> for ActionConstraint {
367 fn from(constraint: ast::ActionConstraint) -> ActionConstraint {
368 match constraint {
369 ast::ActionConstraint::Any => ActionConstraint::All,
370 ast::ActionConstraint::Eq(e) => ActionConstraint::Eq(EqConstraint::Entity {
371 entity: EntityUidJSON::ImplicitEntityEscape((&*e).into()),
372 }),
373 ast::ActionConstraint::In(es) => match &es[..] {
374 [e] => ActionConstraint::In(ActionInConstraint::Single {
375 entity: EntityUidJSON::ImplicitEntityEscape((&**e).into()),
376 }),
377 es => ActionConstraint::In(ActionInConstraint::Set {
378 entities: es
379 .iter()
380 .map(|e| EntityUidJSON::ImplicitEntityEscape((&**e).into()))
381 .collect(),
382 }),
383 },
384 }
385 }
386}
387
388impl TryFrom<ActionConstraint> for ast::ActionConstraint {
389 type Error = EstToAstError;
390 fn try_from(constraint: ActionConstraint) -> Result<ast::ActionConstraint, EstToAstError> {
391 match constraint {
392 ActionConstraint::All => Ok(ast::ActionConstraint::Any),
393 ActionConstraint::Eq(EqConstraint::Entity { entity }) => Ok(ast::ActionConstraint::Eq(
394 Arc::new(entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?),
395 )),
396 ActionConstraint::Eq(EqConstraint::Slot { .. }) => Err(EstToAstError::ActionSlot),
397 ActionConstraint::In(ActionInConstraint::Single { entity }) => {
398 Ok(ast::ActionConstraint::In(vec![Arc::new(
399 entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
400 )]))
401 }
402 ActionConstraint::In(ActionInConstraint::Set { entities }) => {
403 Ok(ast::ActionConstraint::In(
404 entities
405 .into_iter()
406 .map(|e| {
407 e.into_euid(|| JsonDeserializationErrorContext::EntityUid)
408 .map(Arc::new)
409 })
410 .collect::<Result<Vec<_>, _>>()?,
411 ))
412 }
413 }
414 }
415}