1use super::{FromJsonError, LinkingError};
18use crate::ast;
19use crate::ast::EntityUID;
20use crate::entities::json::{
21 err::JsonDeserializationError, err::JsonDeserializationErrorContext, EntityUidJson,
22};
23use crate::parser::err::parse_errors;
24use serde::{Deserialize, Serialize};
25use smol_str::SmolStr;
26use std::collections::{BTreeMap, HashMap};
27use std::sync::Arc;
28
29#[cfg(feature = "wasm")]
30extern crate tsify;
31
32#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
34#[serde(deny_unknown_fields)]
35#[serde(tag = "op")]
36#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
37#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
38pub enum PrincipalConstraint {
39 #[serde(alias = "all")]
41 All,
42 #[serde(rename = "==")]
44 Eq(EqConstraint),
45 #[serde(rename = "in")]
47 In(PrincipalOrResourceInConstraint),
48 #[serde(rename = "is")]
50 Is(PrincipalOrResourceIsConstraint),
51}
52
53#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
55#[serde(deny_unknown_fields)]
56#[serde(tag = "op")]
57#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
58#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
59pub enum ActionConstraint {
60 #[serde(alias = "all")]
62 All,
63 #[serde(rename = "==")]
65 Eq(EqConstraint),
66 #[serde(rename = "in")]
68 In(ActionInConstraint),
69}
70
71#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
73#[serde(deny_unknown_fields)]
74#[serde(tag = "op")]
75#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
76#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
77pub enum ResourceConstraint {
78 #[serde(alias = "all")]
80 All,
81 #[serde(rename = "==")]
83 Eq(EqConstraint),
84 #[serde(rename = "in")]
86 In(PrincipalOrResourceInConstraint),
87 #[serde(rename = "is")]
88 Is(PrincipalOrResourceIsConstraint),
90}
91
92#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
94#[serde(untagged)]
95#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
96#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
97pub enum EqConstraint {
98 Entity {
100 entity: EntityUidJson,
102 },
103 Slot {
105 #[cfg_attr(feature = "wasm", tsify(type = "string"))]
107 slot: ast::SlotId,
108 },
109}
110
111#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
114#[serde(untagged)]
115#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
116#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
117pub enum PrincipalOrResourceInConstraint {
118 Entity {
120 entity: EntityUidJson,
122 },
123 Slot {
125 #[cfg_attr(feature = "wasm", tsify(type = "string"))]
127 slot: ast::SlotId,
128 },
129}
130
131#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
134#[serde(deny_unknown_fields)]
135#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
136#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
137pub struct PrincipalOrResourceIsConstraint {
138 #[cfg_attr(feature = "wasm", tsify(type = "string"))]
139 entity_type: SmolStr,
140 #[serde(skip_serializing_if = "Option::is_none")]
141 #[serde(rename = "in")]
142 in_entity: Option<PrincipalOrResourceInConstraint>,
143}
144
145#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
148#[serde(untagged)]
149#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
150#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
151pub enum ActionInConstraint {
152 Single {
154 entity: EntityUidJson,
156 },
157 Set {
159 entities: Vec<EntityUidJson>,
161 },
162}
163
164impl PrincipalConstraint {
165 pub fn link(self, vals: &HashMap<ast::SlotId, EntityUidJson>) -> Result<Self, LinkingError> {
169 match self {
170 PrincipalConstraint::All => Ok(PrincipalConstraint::All),
171 PrincipalConstraint::Eq(EqConstraint::Entity { entity }) => {
172 Ok(PrincipalConstraint::Eq(EqConstraint::Entity { entity }))
173 }
174 PrincipalConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }) => Ok(
175 PrincipalConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }),
176 ),
177 PrincipalConstraint::Eq(EqConstraint::Slot { slot }) => match vals.get(&slot) {
178 Some(val) => Ok(PrincipalConstraint::Eq(EqConstraint::Entity {
179 entity: val.clone(),
180 })),
181 None => Err(LinkingError::MissedSlot { slot }),
182 },
183 PrincipalConstraint::In(PrincipalOrResourceInConstraint::Slot { slot }) => {
184 match vals.get(&slot) {
185 Some(val) => Ok(PrincipalConstraint::In(
186 PrincipalOrResourceInConstraint::Entity {
187 entity: val.clone(),
188 },
189 )),
190 None => Err(LinkingError::MissedSlot { slot }),
191 }
192 }
193 e @ PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
194 entity_type: _,
195 in_entity: None | Some(PrincipalOrResourceInConstraint::Entity { .. }),
196 }) => Ok(e),
197 PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
198 entity_type,
199 in_entity: Some(PrincipalOrResourceInConstraint::Slot { slot }),
200 }) => Ok(PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
201 entity_type,
202 in_entity: Some(PrincipalOrResourceInConstraint::Entity {
203 entity: vals
204 .get(&slot)
205 .ok_or(LinkingError::MissedSlot { slot })?
206 .clone(),
207 }),
208 })),
209 }
210 }
211
212 pub fn sub_entity_literals(
214 self,
215 mapping: &BTreeMap<EntityUID, EntityUID>,
216 ) -> Result<Self, JsonDeserializationError> {
217 match self.clone() {
218 PrincipalConstraint::All
219 | PrincipalConstraint::Eq(EqConstraint::Slot { .. })
220 | PrincipalConstraint::In(PrincipalOrResourceInConstraint::Slot { .. })
221 | PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
222 in_entity: Some(PrincipalOrResourceInConstraint::Slot { .. }),
223 ..
224 })
225 | PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
226 entity_type: _,
227 in_entity: None,
228 }) => Ok(self),
229 PrincipalConstraint::Eq(EqConstraint::Entity { entity }) => {
230 let euid = entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?;
231 match mapping.get(&euid) {
232 Some(new_euid) => Ok(PrincipalConstraint::Eq(EqConstraint::Entity {
233 entity: new_euid.into(),
234 })),
235 None => Ok(self),
236 }
237 }
238 PrincipalConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }) => {
239 let euid = entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?;
240 match mapping.get(&euid) {
241 Some(new_euid) => Ok(PrincipalConstraint::In(
242 PrincipalOrResourceInConstraint::Entity {
243 entity: new_euid.into(),
244 },
245 )),
246 None => Ok(self),
247 }
248 }
249 PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
250 entity_type: ety,
251 in_entity: Some(PrincipalOrResourceInConstraint::Entity { entity }),
252 }) => {
253 let euid = entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?;
254 match mapping.get(&euid) {
255 Some(new_euid) => {
256 Ok(PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
257 entity_type: ety,
258 in_entity: Some(PrincipalOrResourceInConstraint::Entity {
259 entity: new_euid.into(),
260 }),
261 }))
262 }
263 None => Ok(self),
264 }
265 }
266 }
267 }
268}
269
270impl ResourceConstraint {
271 pub fn link(self, vals: &HashMap<ast::SlotId, EntityUidJson>) -> Result<Self, LinkingError> {
275 match self {
276 ResourceConstraint::All => Ok(ResourceConstraint::All),
277 ResourceConstraint::Eq(EqConstraint::Entity { entity }) => {
278 Ok(ResourceConstraint::Eq(EqConstraint::Entity { entity }))
279 }
280 ResourceConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }) => Ok(
281 ResourceConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }),
282 ),
283 ResourceConstraint::Eq(EqConstraint::Slot { slot }) => match vals.get(&slot) {
284 Some(val) => Ok(ResourceConstraint::Eq(EqConstraint::Entity {
285 entity: val.clone(),
286 })),
287 None => Err(LinkingError::MissedSlot { slot }),
288 },
289 ResourceConstraint::In(PrincipalOrResourceInConstraint::Slot { slot }) => {
290 match vals.get(&slot) {
291 Some(val) => Ok(ResourceConstraint::In(
292 PrincipalOrResourceInConstraint::Entity {
293 entity: val.clone(),
294 },
295 )),
296 None => Err(LinkingError::MissedSlot { slot }),
297 }
298 }
299 e @ ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
300 entity_type: _,
301 in_entity: None | Some(PrincipalOrResourceInConstraint::Entity { .. }),
302 }) => Ok(e),
303 ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
304 entity_type,
305 in_entity: Some(PrincipalOrResourceInConstraint::Slot { slot }),
306 }) => Ok(ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
307 entity_type,
308 in_entity: Some(PrincipalOrResourceInConstraint::Entity {
309 entity: vals
310 .get(&slot)
311 .ok_or(LinkingError::MissedSlot { slot })?
312 .clone(),
313 }),
314 })),
315 }
316 }
317
318 pub fn sub_entity_literals(
320 self,
321 mapping: &BTreeMap<EntityUID, EntityUID>,
322 ) -> Result<Self, JsonDeserializationError> {
323 match self.clone() {
324 ResourceConstraint::All
325 | ResourceConstraint::Eq(EqConstraint::Slot { .. })
326 | ResourceConstraint::In(PrincipalOrResourceInConstraint::Slot { .. })
327 | ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
328 in_entity: Some(PrincipalOrResourceInConstraint::Slot { .. }),
329 ..
330 })
331 | ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
332 entity_type: _,
333 in_entity: None,
334 }) => Ok(self),
335 ResourceConstraint::Eq(EqConstraint::Entity { entity }) => {
336 let euid = entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?;
337 match mapping.get(&euid) {
338 Some(new_euid) => Ok(ResourceConstraint::Eq(EqConstraint::Entity {
339 entity: new_euid.into(),
340 })),
341 None => Ok(self),
342 }
343 }
344 ResourceConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }) => {
345 let euid = entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?;
346 match mapping.get(&euid) {
347 Some(new_euid) => Ok(ResourceConstraint::In(
348 PrincipalOrResourceInConstraint::Entity {
349 entity: new_euid.into(),
350 },
351 )),
352 None => Ok(self),
353 }
354 }
355 ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
356 entity_type: ety,
357 in_entity: Some(PrincipalOrResourceInConstraint::Entity { entity }),
358 }) => {
359 let euid = entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?;
360 match mapping.get(&euid) {
361 Some(new_euid) => Ok(ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
362 entity_type: ety,
363 in_entity: Some(PrincipalOrResourceInConstraint::Entity {
364 entity: new_euid.into(),
365 }),
366 })),
367 None => Ok(self),
368 }
369 }
370 }
371 }
372}
373
374impl ActionConstraint {
375 pub fn link(self, _vals: &HashMap<ast::SlotId, EntityUidJson>) -> Result<Self, LinkingError> {
379 Ok(self)
381 }
382
383 pub fn sub_entity_literals(
385 self,
386 mapping: &BTreeMap<EntityUID, EntityUID>,
387 ) -> Result<Self, JsonDeserializationError> {
388 match self.clone() {
389 ActionConstraint::Eq(EqConstraint::Entity { entity }) => {
390 let euid = entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?;
391 match mapping.get(&euid) {
392 Some(new_euid) => Ok(ActionConstraint::Eq(EqConstraint::Entity {
393 entity: new_euid.into(),
394 })),
395 None => Ok(self),
396 }
397 }
398 ActionConstraint::In(ActionInConstraint::Single { entity }) => {
399 let euid = entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?;
400 match mapping.get(&euid) {
401 Some(new_euid) => Ok(ActionConstraint::In(ActionInConstraint::Single {
402 entity: new_euid.into(),
403 })),
404 None => Ok(self),
405 }
406 }
407 ActionConstraint::In(ActionInConstraint::Set { entities }) => {
408 let mut new_entities: Vec<EntityUidJson> = vec![];
409 for entity in entities {
410 let euid = entity
411 .clone()
412 .into_euid(|| JsonDeserializationErrorContext::EntityUid)?;
413 match mapping.get(&euid) {
414 Some(new_euid) => new_entities.push(new_euid.clone().into()),
415 None => new_entities.push(entity),
416 };
417 }
418 Ok(ActionConstraint::In(ActionInConstraint::Set {
419 entities: new_entities,
420 }))
421 }
422 ActionConstraint::All | ActionConstraint::Eq(EqConstraint::Slot { .. }) => Ok(self),
423 }
424 }
425}
426
427impl std::fmt::Display for PrincipalConstraint {
428 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
429 match self {
430 Self::All => write!(f, "principal"),
431 Self::Eq(ec) => {
432 write!(f, "principal ")?;
433 std::fmt::Display::fmt(ec, f)?;
434 Ok(())
435 }
436 Self::In(ic) => {
437 write!(f, "principal ")?;
438 std::fmt::Display::fmt(ic, f)?;
439 Ok(())
440 }
441 Self::Is(isc) => {
442 write!(f, "principal ")?;
443 std::fmt::Display::fmt(isc, f)?;
444 Ok(())
445 }
446 }
447 }
448}
449
450impl std::fmt::Display for ActionConstraint {
451 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
452 match self {
453 Self::All => write!(f, "action"),
454 Self::Eq(ec) => {
455 write!(f, "action ")?;
456 std::fmt::Display::fmt(ec, f)?;
457 Ok(())
458 }
459 Self::In(aic) => {
460 write!(f, "action ")?;
461 std::fmt::Display::fmt(aic, f)?;
462 Ok(())
463 }
464 }
465 }
466}
467
468impl std::fmt::Display for ResourceConstraint {
469 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
470 match self {
471 Self::All => write!(f, "resource"),
472 Self::Eq(ec) => {
473 write!(f, "resource ")?;
474 std::fmt::Display::fmt(ec, f)?;
475 Ok(())
476 }
477 Self::In(ic) => {
478 write!(f, "resource ")?;
479 std::fmt::Display::fmt(ic, f)?;
480 Ok(())
481 }
482 Self::Is(isc) => {
483 write!(f, "resource ")?;
484 std::fmt::Display::fmt(isc, f)?;
485 Ok(())
486 }
487 }
488 }
489}
490
491impl std::fmt::Display for EqConstraint {
492 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
493 match self {
494 Self::Entity { entity } => {
495 match entity
496 .clone()
497 .into_euid(|| JsonDeserializationErrorContext::EntityUid)
498 {
499 Ok(euid) => write!(f, "== {euid}"),
500 Err(e) => write!(f, "== (invalid entity uid: {e})"),
501 }
502 }
503 Self::Slot { slot } => write!(f, "== {slot}"),
504 }
505 }
506}
507
508impl std::fmt::Display for PrincipalOrResourceInConstraint {
509 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
510 match self {
511 Self::Entity { entity } => {
512 match entity
513 .clone()
514 .into_euid(|| JsonDeserializationErrorContext::EntityUid)
515 {
516 Ok(euid) => write!(f, "in {euid}"),
517 Err(e) => write!(f, "in (invalid entity uid: {e})"),
518 }
519 }
520 Self::Slot { slot } => write!(f, "in {slot}"),
521 }
522 }
523}
524
525impl std::fmt::Display for PrincipalOrResourceIsConstraint {
526 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
527 write!(f, "is {}", self.entity_type)?;
528 if let Some(in_entity) = &self.in_entity {
529 write!(f, " {}", in_entity)?;
530 }
531 Ok(())
532 }
533}
534
535impl std::fmt::Display for ActionInConstraint {
536 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
537 match self {
538 Self::Single { entity } => {
539 match entity
540 .clone()
541 .into_euid(|| JsonDeserializationErrorContext::EntityUid)
542 {
543 Ok(euid) => write!(f, "in {euid}"),
544 Err(e) => write!(f, "in (invalid entity uid: {e})"),
545 }
546 }
547 Self::Set { entities } => {
548 write!(f, "in [")?;
549 for (i, entity) in entities.iter().enumerate() {
550 match entity
551 .clone()
552 .into_euid(|| JsonDeserializationErrorContext::EntityUid)
553 {
554 Ok(euid) => write!(f, "{euid}"),
555 Err(e) => write!(f, "(invalid entity uid: {e})"),
556 }?;
557 if i < (entities.len() - 1) {
558 write!(f, ", ")?;
559 }
560 }
561 write!(f, "]")?;
562 Ok(())
563 }
564 }
565 }
566}
567
568impl From<ast::PrincipalConstraint> for PrincipalConstraint {
569 fn from(constraint: ast::PrincipalConstraint) -> PrincipalConstraint {
570 constraint.constraint.into()
571 }
572}
573
574impl TryFrom<PrincipalConstraint> for ast::PrincipalConstraint {
575 type Error = FromJsonError;
576 fn try_from(constraint: PrincipalConstraint) -> Result<ast::PrincipalConstraint, Self::Error> {
577 constraint.try_into().map(ast::PrincipalConstraint::new)
578 }
579}
580
581impl From<ast::ResourceConstraint> for ResourceConstraint {
582 fn from(constraint: ast::ResourceConstraint) -> ResourceConstraint {
583 constraint.constraint.into()
584 }
585}
586
587impl TryFrom<ResourceConstraint> for ast::ResourceConstraint {
588 type Error = FromJsonError;
589 fn try_from(constraint: ResourceConstraint) -> Result<ast::ResourceConstraint, Self::Error> {
590 constraint.try_into().map(ast::ResourceConstraint::new)
591 }
592}
593
594impl From<ast::PrincipalOrResourceConstraint> for PrincipalConstraint {
595 fn from(constraint: ast::PrincipalOrResourceConstraint) -> PrincipalConstraint {
596 match constraint {
597 ast::PrincipalOrResourceConstraint::Any => PrincipalConstraint::All,
598 ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::EUID(e)) => {
599 PrincipalConstraint::Eq(EqConstraint::Entity {
600 entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
601 })
602 }
603 ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::Slot(_)) => {
604 PrincipalConstraint::Eq(EqConstraint::Slot {
605 slot: ast::SlotId::principal(),
606 })
607 }
608 ast::PrincipalOrResourceConstraint::In(ast::EntityReference::EUID(e)) => {
609 PrincipalConstraint::In(PrincipalOrResourceInConstraint::Entity {
610 entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
611 })
612 }
613 ast::PrincipalOrResourceConstraint::In(ast::EntityReference::Slot(_)) => {
614 PrincipalConstraint::In(PrincipalOrResourceInConstraint::Slot {
615 slot: ast::SlotId::principal(),
616 })
617 }
618 ast::PrincipalOrResourceConstraint::IsIn(entity_type, euid) => {
619 PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
620 entity_type: entity_type.to_string().into(),
621 in_entity: Some(match euid {
622 ast::EntityReference::EUID(e) => PrincipalOrResourceInConstraint::Entity {
623 entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
624 },
625 ast::EntityReference::Slot(_) => PrincipalOrResourceInConstraint::Slot {
626 slot: ast::SlotId::principal(),
627 },
628 }),
629 })
630 }
631 ast::PrincipalOrResourceConstraint::Is(entity_type) => {
632 PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
633 entity_type: entity_type.to_string().into(),
634 in_entity: None,
635 })
636 }
637 }
638 }
639}
640
641impl From<ast::PrincipalOrResourceConstraint> for ResourceConstraint {
642 fn from(constraint: ast::PrincipalOrResourceConstraint) -> ResourceConstraint {
643 match constraint {
644 ast::PrincipalOrResourceConstraint::Any => ResourceConstraint::All,
645 ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::EUID(e)) => {
646 ResourceConstraint::Eq(EqConstraint::Entity {
647 entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
648 })
649 }
650 ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::Slot(_)) => {
651 ResourceConstraint::Eq(EqConstraint::Slot {
652 slot: ast::SlotId::resource(),
653 })
654 }
655 ast::PrincipalOrResourceConstraint::In(ast::EntityReference::EUID(e)) => {
656 ResourceConstraint::In(PrincipalOrResourceInConstraint::Entity {
657 entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
658 })
659 }
660 ast::PrincipalOrResourceConstraint::In(ast::EntityReference::Slot(_)) => {
661 ResourceConstraint::In(PrincipalOrResourceInConstraint::Slot {
662 slot: ast::SlotId::resource(),
663 })
664 }
665 ast::PrincipalOrResourceConstraint::IsIn(entity_type, euid) => {
666 ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
667 entity_type: entity_type.to_string().into(),
668 in_entity: Some(match euid {
669 ast::EntityReference::EUID(e) => PrincipalOrResourceInConstraint::Entity {
670 entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
671 },
672 ast::EntityReference::Slot(_) => PrincipalOrResourceInConstraint::Slot {
673 slot: ast::SlotId::resource(),
674 },
675 }),
676 })
677 }
678 ast::PrincipalOrResourceConstraint::Is(entity_type) => {
679 ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
680 entity_type: entity_type.to_string().into(),
681 in_entity: None,
682 })
683 }
684 }
685 }
686}
687
688impl TryFrom<PrincipalConstraint> for ast::PrincipalOrResourceConstraint {
689 type Error = FromJsonError;
690 fn try_from(
691 constraint: PrincipalConstraint,
692 ) -> Result<ast::PrincipalOrResourceConstraint, Self::Error> {
693 match constraint {
694 PrincipalConstraint::All => Ok(ast::PrincipalOrResourceConstraint::Any),
695 PrincipalConstraint::Eq(EqConstraint::Entity { entity }) => Ok(
696 ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::EUID(Arc::new(
697 entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
698 ))),
699 ),
700 PrincipalConstraint::Eq(EqConstraint::Slot { slot }) => {
701 if slot == ast::SlotId::principal() {
702 Ok(ast::PrincipalOrResourceConstraint::Eq(
703 ast::EntityReference::Slot(None),
704 ))
705 } else {
706 Err(Self::Error::InvalidSlotName)
707 }
708 }
709 PrincipalConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }) => Ok(
710 ast::PrincipalOrResourceConstraint::In(ast::EntityReference::EUID(Arc::new(
711 entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
712 ))),
713 ),
714 PrincipalConstraint::In(PrincipalOrResourceInConstraint::Slot { slot }) => {
715 if slot == ast::SlotId::principal() {
716 Ok(ast::PrincipalOrResourceConstraint::In(
717 ast::EntityReference::Slot(None),
718 ))
719 } else {
720 Err(Self::Error::InvalidSlotName)
721 }
722 }
723 PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
724 entity_type,
725 in_entity,
726 }) => ast::EntityType::from_normalized_str(entity_type.as_str())
727 .map_err(Self::Error::InvalidEntityType)
728 .and_then(|entity_type| {
729 Ok(match in_entity {
730 None => ast::PrincipalOrResourceConstraint::is_entity_type(Arc::new(
731 entity_type,
732 )),
733 Some(PrincipalOrResourceInConstraint::Entity { entity }) => {
734 ast::PrincipalOrResourceConstraint::is_entity_type_in(
735 Arc::new(entity_type),
736 Arc::new(
737 entity
738 .into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
739 ),
740 )
741 }
742 Some(PrincipalOrResourceInConstraint::Slot { .. }) => {
743 ast::PrincipalOrResourceConstraint::is_entity_type_in_slot(Arc::new(
744 entity_type,
745 ))
746 }
747 })
748 }),
749 }
750 }
751}
752
753impl TryFrom<ResourceConstraint> for ast::PrincipalOrResourceConstraint {
754 type Error = FromJsonError;
755 fn try_from(
756 constraint: ResourceConstraint,
757 ) -> Result<ast::PrincipalOrResourceConstraint, Self::Error> {
758 match constraint {
759 ResourceConstraint::All => Ok(ast::PrincipalOrResourceConstraint::Any),
760 ResourceConstraint::Eq(EqConstraint::Entity { entity }) => Ok(
761 ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::EUID(Arc::new(
762 entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
763 ))),
764 ),
765 ResourceConstraint::Eq(EqConstraint::Slot { slot }) => {
766 if slot == ast::SlotId::resource() {
767 Ok(ast::PrincipalOrResourceConstraint::Eq(
768 ast::EntityReference::Slot(None),
769 ))
770 } else {
771 Err(Self::Error::InvalidSlotName)
772 }
773 }
774 ResourceConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }) => Ok(
775 ast::PrincipalOrResourceConstraint::In(ast::EntityReference::EUID(Arc::new(
776 entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
777 ))),
778 ),
779 ResourceConstraint::In(PrincipalOrResourceInConstraint::Slot { slot }) => {
780 if slot == ast::SlotId::resource() {
781 Ok(ast::PrincipalOrResourceConstraint::In(
782 ast::EntityReference::Slot(None),
783 ))
784 } else {
785 Err(Self::Error::InvalidSlotName)
786 }
787 }
788 ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
789 entity_type,
790 in_entity,
791 }) => ast::EntityType::from_normalized_str(entity_type.as_str())
792 .map_err(Self::Error::InvalidEntityType)
793 .and_then(|entity_type| {
794 Ok(match in_entity {
795 None => ast::PrincipalOrResourceConstraint::is_entity_type(Arc::new(
796 entity_type,
797 )),
798 Some(PrincipalOrResourceInConstraint::Entity { entity }) => {
799 ast::PrincipalOrResourceConstraint::is_entity_type_in(
800 Arc::new(entity_type),
801 Arc::new(
802 entity
803 .into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
804 ),
805 )
806 }
807 Some(PrincipalOrResourceInConstraint::Slot { .. }) => {
808 ast::PrincipalOrResourceConstraint::is_entity_type_in_slot(Arc::new(
809 entity_type,
810 ))
811 }
812 })
813 }),
814 }
815 }
816}
817
818impl From<ast::ActionConstraint> for ActionConstraint {
819 fn from(constraint: ast::ActionConstraint) -> ActionConstraint {
820 match constraint {
821 ast::ActionConstraint::Any => ActionConstraint::All,
822 ast::ActionConstraint::Eq(e) => ActionConstraint::Eq(EqConstraint::Entity {
823 entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
824 }),
825 ast::ActionConstraint::In(es) => match &es[..] {
826 [e] => ActionConstraint::In(ActionInConstraint::Single {
827 entity: EntityUidJson::ImplicitEntityEscape((&**e).into()),
828 }),
829 es => ActionConstraint::In(ActionInConstraint::Set {
830 entities: es
831 .iter()
832 .map(|e| EntityUidJson::ImplicitEntityEscape((&**e).into()))
833 .collect(),
834 }),
835 },
836 }
837 }
838}
839
840impl TryFrom<ActionConstraint> for ast::ActionConstraint {
841 type Error = FromJsonError;
842 fn try_from(constraint: ActionConstraint) -> Result<ast::ActionConstraint, Self::Error> {
843 let ast_action_constraint = match constraint {
844 ActionConstraint::All => Ok(ast::ActionConstraint::Any),
845 ActionConstraint::Eq(EqConstraint::Entity { entity }) => Ok(ast::ActionConstraint::Eq(
846 Arc::new(entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?),
847 )),
848 ActionConstraint::Eq(EqConstraint::Slot { .. }) => Err(Self::Error::ActionSlot),
849 ActionConstraint::In(ActionInConstraint::Single { entity }) => {
850 Ok(ast::ActionConstraint::In(vec![Arc::new(
851 entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
852 )]))
853 }
854 ActionConstraint::In(ActionInConstraint::Set { entities }) => {
855 Ok(ast::ActionConstraint::In(
856 entities
857 .into_iter()
858 .map(|e| {
859 e.into_euid(|| JsonDeserializationErrorContext::EntityUid)
860 .map(Arc::new)
861 })
862 .collect::<Result<Vec<_>, _>>()?,
863 ))
864 }
865 }?;
866
867 ast_action_constraint
868 .contains_only_action_types()
869 .map_err(|non_action_euids| {
870 parse_errors::InvalidActionType {
871 euids: non_action_euids,
872 }
873 .into()
874 })
875 }
876}