1use super::{FromJsonError, LinkingError};
18use crate::ast;
19use crate::entities::json::{err::JsonDeserializationErrorContext, EntityUidJson};
20use crate::parser::err::parse_errors;
21use serde::{Deserialize, Serialize};
22use smol_str::SmolStr;
23use std::collections::HashMap;
24use std::sync::Arc;
25
26#[cfg(feature = "wasm")]
27extern crate tsify;
28
29#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
31#[serde(deny_unknown_fields)]
32#[serde(tag = "op")]
33#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
34#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
35pub enum PrincipalConstraint {
36 #[serde(alias = "all")]
38 All,
39 #[serde(rename = "==")]
41 Eq(EqConstraint),
42 #[serde(rename = "in")]
44 In(PrincipalOrResourceInConstraint),
45 #[serde(rename = "is")]
47 Is(PrincipalOrResourceIsConstraint),
48}
49
50#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
52#[serde(deny_unknown_fields)]
53#[serde(tag = "op")]
54#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
55#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
56pub enum ActionConstraint {
57 #[serde(alias = "all")]
59 All,
60 #[serde(rename = "==")]
62 Eq(EqConstraint),
63 #[serde(rename = "in")]
65 In(ActionInConstraint),
66}
67
68#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
70#[serde(deny_unknown_fields)]
71#[serde(tag = "op")]
72#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
73#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
74pub enum ResourceConstraint {
75 #[serde(alias = "all")]
77 All,
78 #[serde(rename = "==")]
80 Eq(EqConstraint),
81 #[serde(rename = "in")]
83 In(PrincipalOrResourceInConstraint),
84 #[serde(rename = "is")]
85 Is(PrincipalOrResourceIsConstraint),
87}
88
89#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
91#[serde(untagged)]
92#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
93#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
94pub enum EqConstraint {
95 Entity {
97 entity: EntityUidJson,
99 },
100 Slot {
102 #[cfg_attr(feature = "wasm", tsify(type = "string"))]
104 slot: ast::SlotId,
105 },
106}
107
108#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
111#[serde(untagged)]
112#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
113#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
114pub enum PrincipalOrResourceInConstraint {
115 Entity {
117 entity: EntityUidJson,
119 },
120 Slot {
122 #[cfg_attr(feature = "wasm", tsify(type = "string"))]
124 slot: ast::SlotId,
125 },
126}
127
128#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
131#[serde(deny_unknown_fields)]
132#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
133#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
134pub struct PrincipalOrResourceIsConstraint {
135 #[cfg_attr(feature = "wasm", tsify(type = "string"))]
136 entity_type: SmolStr,
137 #[serde(skip_serializing_if = "Option::is_none")]
138 #[serde(rename = "in")]
139 in_entity: Option<PrincipalOrResourceInConstraint>,
140}
141
142#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
145#[serde(untagged)]
146#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
147#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
148pub enum ActionInConstraint {
149 Single {
151 entity: EntityUidJson,
153 },
154 Set {
156 entities: Vec<EntityUidJson>,
158 },
159}
160
161impl PrincipalConstraint {
162 pub fn link(self, vals: &HashMap<ast::SlotId, EntityUidJson>) -> Result<Self, LinkingError> {
166 match self {
167 PrincipalConstraint::All => Ok(PrincipalConstraint::All),
168 PrincipalConstraint::Eq(EqConstraint::Entity { entity }) => {
169 Ok(PrincipalConstraint::Eq(EqConstraint::Entity { entity }))
170 }
171 PrincipalConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }) => Ok(
172 PrincipalConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }),
173 ),
174 PrincipalConstraint::Eq(EqConstraint::Slot { slot }) => match vals.get(&slot) {
175 Some(val) => Ok(PrincipalConstraint::Eq(EqConstraint::Entity {
176 entity: val.clone(),
177 })),
178 None => Err(LinkingError::MissedSlot { slot }),
179 },
180 PrincipalConstraint::In(PrincipalOrResourceInConstraint::Slot { slot }) => {
181 match vals.get(&slot) {
182 Some(val) => Ok(PrincipalConstraint::In(
183 PrincipalOrResourceInConstraint::Entity {
184 entity: val.clone(),
185 },
186 )),
187 None => Err(LinkingError::MissedSlot { slot }),
188 }
189 }
190 e @ PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
191 entity_type: _,
192 in_entity: None | Some(PrincipalOrResourceInConstraint::Entity { .. }),
193 }) => Ok(e),
194 PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
195 entity_type,
196 in_entity: Some(PrincipalOrResourceInConstraint::Slot { slot }),
197 }) => Ok(PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
198 entity_type,
199 in_entity: Some(PrincipalOrResourceInConstraint::Entity {
200 entity: vals
201 .get(&slot)
202 .ok_or(LinkingError::MissedSlot { slot })?
203 .clone(),
204 }),
205 })),
206 }
207 }
208}
209
210impl ResourceConstraint {
211 pub fn link(self, vals: &HashMap<ast::SlotId, EntityUidJson>) -> Result<Self, LinkingError> {
215 match self {
216 ResourceConstraint::All => Ok(ResourceConstraint::All),
217 ResourceConstraint::Eq(EqConstraint::Entity { entity }) => {
218 Ok(ResourceConstraint::Eq(EqConstraint::Entity { entity }))
219 }
220 ResourceConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }) => Ok(
221 ResourceConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }),
222 ),
223 ResourceConstraint::Eq(EqConstraint::Slot { slot }) => match vals.get(&slot) {
224 Some(val) => Ok(ResourceConstraint::Eq(EqConstraint::Entity {
225 entity: val.clone(),
226 })),
227 None => Err(LinkingError::MissedSlot { slot }),
228 },
229 ResourceConstraint::In(PrincipalOrResourceInConstraint::Slot { slot }) => {
230 match vals.get(&slot) {
231 Some(val) => Ok(ResourceConstraint::In(
232 PrincipalOrResourceInConstraint::Entity {
233 entity: val.clone(),
234 },
235 )),
236 None => Err(LinkingError::MissedSlot { slot }),
237 }
238 }
239 e @ ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
240 entity_type: _,
241 in_entity: None | Some(PrincipalOrResourceInConstraint::Entity { .. }),
242 }) => Ok(e),
243 ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
244 entity_type,
245 in_entity: Some(PrincipalOrResourceInConstraint::Slot { slot }),
246 }) => Ok(ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
247 entity_type,
248 in_entity: Some(PrincipalOrResourceInConstraint::Entity {
249 entity: vals
250 .get(&slot)
251 .ok_or(LinkingError::MissedSlot { slot })?
252 .clone(),
253 }),
254 })),
255 }
256 }
257}
258
259impl ActionConstraint {
260 pub fn link(self, _vals: &HashMap<ast::SlotId, EntityUidJson>) -> Result<Self, LinkingError> {
264 Ok(self)
266 }
267}
268
269impl std::fmt::Display for PrincipalConstraint {
270 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
271 match self {
272 Self::All => write!(f, "principal"),
273 Self::Eq(ec) => {
274 write!(f, "principal ")?;
275 std::fmt::Display::fmt(ec, f)?;
276 Ok(())
277 }
278 Self::In(ic) => {
279 write!(f, "principal ")?;
280 std::fmt::Display::fmt(ic, f)?;
281 Ok(())
282 }
283 Self::Is(isc) => {
284 write!(f, "principal ")?;
285 std::fmt::Display::fmt(isc, f)?;
286 Ok(())
287 }
288 }
289 }
290}
291
292impl std::fmt::Display for ActionConstraint {
293 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
294 match self {
295 Self::All => write!(f, "action"),
296 Self::Eq(ec) => {
297 write!(f, "action ")?;
298 std::fmt::Display::fmt(ec, f)?;
299 Ok(())
300 }
301 Self::In(aic) => {
302 write!(f, "action ")?;
303 std::fmt::Display::fmt(aic, f)?;
304 Ok(())
305 }
306 }
307 }
308}
309
310impl std::fmt::Display for ResourceConstraint {
311 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
312 match self {
313 Self::All => write!(f, "resource"),
314 Self::Eq(ec) => {
315 write!(f, "resource ")?;
316 std::fmt::Display::fmt(ec, f)?;
317 Ok(())
318 }
319 Self::In(ic) => {
320 write!(f, "resource ")?;
321 std::fmt::Display::fmt(ic, f)?;
322 Ok(())
323 }
324 Self::Is(isc) => {
325 write!(f, "resource ")?;
326 std::fmt::Display::fmt(isc, f)?;
327 Ok(())
328 }
329 }
330 }
331}
332
333impl std::fmt::Display for EqConstraint {
334 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
335 match self {
336 Self::Entity { entity } => {
337 match entity
338 .clone()
339 .into_euid(|| JsonDeserializationErrorContext::EntityUid)
340 {
341 Ok(euid) => write!(f, "== {euid}"),
342 Err(e) => write!(f, "== (invalid entity uid: {e})"),
343 }
344 }
345 Self::Slot { slot } => write!(f, "== {slot}"),
346 }
347 }
348}
349
350impl std::fmt::Display for PrincipalOrResourceInConstraint {
351 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
352 match self {
353 Self::Entity { entity } => {
354 match entity
355 .clone()
356 .into_euid(|| JsonDeserializationErrorContext::EntityUid)
357 {
358 Ok(euid) => write!(f, "in {euid}"),
359 Err(e) => write!(f, "in (invalid entity uid: {e})"),
360 }
361 }
362 Self::Slot { slot } => write!(f, "in {slot}"),
363 }
364 }
365}
366
367impl std::fmt::Display for PrincipalOrResourceIsConstraint {
368 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
369 write!(f, "is {}", self.entity_type)?;
370 if let Some(in_entity) = &self.in_entity {
371 write!(f, " {}", in_entity)?;
372 }
373 Ok(())
374 }
375}
376
377impl std::fmt::Display for ActionInConstraint {
378 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
379 match self {
380 Self::Single { entity } => {
381 match entity
382 .clone()
383 .into_euid(|| JsonDeserializationErrorContext::EntityUid)
384 {
385 Ok(euid) => write!(f, "in {euid}"),
386 Err(e) => write!(f, "in (invalid entity uid: {e})"),
387 }
388 }
389 Self::Set { entities } => {
390 write!(f, "in [")?;
391 for (i, entity) in entities.iter().enumerate() {
392 match entity
393 .clone()
394 .into_euid(|| JsonDeserializationErrorContext::EntityUid)
395 {
396 Ok(euid) => write!(f, "{euid}"),
397 Err(e) => write!(f, "(invalid entity uid: {e})"),
398 }?;
399 if i < (entities.len() - 1) {
400 write!(f, ", ")?;
401 }
402 }
403 write!(f, "]")?;
404 Ok(())
405 }
406 }
407 }
408}
409
410impl From<ast::PrincipalConstraint> for PrincipalConstraint {
411 fn from(constraint: ast::PrincipalConstraint) -> PrincipalConstraint {
412 constraint.constraint.into()
413 }
414}
415
416impl TryFrom<PrincipalConstraint> for ast::PrincipalConstraint {
417 type Error = FromJsonError;
418 fn try_from(constraint: PrincipalConstraint) -> Result<ast::PrincipalConstraint, Self::Error> {
419 constraint.try_into().map(ast::PrincipalConstraint::new)
420 }
421}
422
423impl From<ast::ResourceConstraint> for ResourceConstraint {
424 fn from(constraint: ast::ResourceConstraint) -> ResourceConstraint {
425 constraint.constraint.into()
426 }
427}
428
429impl TryFrom<ResourceConstraint> for ast::ResourceConstraint {
430 type Error = FromJsonError;
431 fn try_from(constraint: ResourceConstraint) -> Result<ast::ResourceConstraint, Self::Error> {
432 constraint.try_into().map(ast::ResourceConstraint::new)
433 }
434}
435
436impl From<ast::PrincipalOrResourceConstraint> for PrincipalConstraint {
437 fn from(constraint: ast::PrincipalOrResourceConstraint) -> PrincipalConstraint {
438 match constraint {
439 ast::PrincipalOrResourceConstraint::Any => PrincipalConstraint::All,
440 ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::EUID(e)) => {
441 PrincipalConstraint::Eq(EqConstraint::Entity {
442 entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
443 })
444 }
445 ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::Slot) => {
446 PrincipalConstraint::Eq(EqConstraint::Slot {
447 slot: ast::SlotId::principal(),
448 })
449 }
450 ast::PrincipalOrResourceConstraint::In(ast::EntityReference::EUID(e)) => {
451 PrincipalConstraint::In(PrincipalOrResourceInConstraint::Entity {
452 entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
453 })
454 }
455 ast::PrincipalOrResourceConstraint::In(ast::EntityReference::Slot) => {
456 PrincipalConstraint::In(PrincipalOrResourceInConstraint::Slot {
457 slot: ast::SlotId::principal(),
458 })
459 }
460 ast::PrincipalOrResourceConstraint::IsIn(entity_type, euid) => {
461 PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
462 entity_type: entity_type.to_string().into(),
463 in_entity: Some(match euid {
464 ast::EntityReference::EUID(e) => PrincipalOrResourceInConstraint::Entity {
465 entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
466 },
467 ast::EntityReference::Slot => PrincipalOrResourceInConstraint::Slot {
468 slot: ast::SlotId::principal(),
469 },
470 }),
471 })
472 }
473 ast::PrincipalOrResourceConstraint::Is(entity_type) => {
474 PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
475 entity_type: entity_type.to_string().into(),
476 in_entity: None,
477 })
478 }
479 }
480 }
481}
482
483impl From<ast::PrincipalOrResourceConstraint> for ResourceConstraint {
484 fn from(constraint: ast::PrincipalOrResourceConstraint) -> ResourceConstraint {
485 match constraint {
486 ast::PrincipalOrResourceConstraint::Any => ResourceConstraint::All,
487 ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::EUID(e)) => {
488 ResourceConstraint::Eq(EqConstraint::Entity {
489 entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
490 })
491 }
492 ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::Slot) => {
493 ResourceConstraint::Eq(EqConstraint::Slot {
494 slot: ast::SlotId::resource(),
495 })
496 }
497 ast::PrincipalOrResourceConstraint::In(ast::EntityReference::EUID(e)) => {
498 ResourceConstraint::In(PrincipalOrResourceInConstraint::Entity {
499 entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
500 })
501 }
502 ast::PrincipalOrResourceConstraint::In(ast::EntityReference::Slot) => {
503 ResourceConstraint::In(PrincipalOrResourceInConstraint::Slot {
504 slot: ast::SlotId::resource(),
505 })
506 }
507 ast::PrincipalOrResourceConstraint::IsIn(entity_type, euid) => {
508 ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
509 entity_type: entity_type.to_string().into(),
510 in_entity: Some(match euid {
511 ast::EntityReference::EUID(e) => PrincipalOrResourceInConstraint::Entity {
512 entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
513 },
514 ast::EntityReference::Slot => PrincipalOrResourceInConstraint::Slot {
515 slot: ast::SlotId::resource(),
516 },
517 }),
518 })
519 }
520 ast::PrincipalOrResourceConstraint::Is(entity_type) => {
521 ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
522 entity_type: entity_type.to_string().into(),
523 in_entity: None,
524 })
525 }
526 }
527 }
528}
529
530impl TryFrom<PrincipalConstraint> for ast::PrincipalOrResourceConstraint {
531 type Error = FromJsonError;
532 fn try_from(
533 constraint: PrincipalConstraint,
534 ) -> Result<ast::PrincipalOrResourceConstraint, Self::Error> {
535 match constraint {
536 PrincipalConstraint::All => Ok(ast::PrincipalOrResourceConstraint::Any),
537 PrincipalConstraint::Eq(EqConstraint::Entity { entity }) => Ok(
538 ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::EUID(Arc::new(
539 entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
540 ))),
541 ),
542 PrincipalConstraint::Eq(EqConstraint::Slot { slot }) => {
543 if slot == ast::SlotId::principal() {
544 Ok(ast::PrincipalOrResourceConstraint::Eq(
545 ast::EntityReference::Slot,
546 ))
547 } else {
548 Err(Self::Error::InvalidSlotName)
549 }
550 }
551 PrincipalConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }) => Ok(
552 ast::PrincipalOrResourceConstraint::In(ast::EntityReference::EUID(Arc::new(
553 entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
554 ))),
555 ),
556 PrincipalConstraint::In(PrincipalOrResourceInConstraint::Slot { slot }) => {
557 if slot == ast::SlotId::principal() {
558 Ok(ast::PrincipalOrResourceConstraint::In(
559 ast::EntityReference::Slot,
560 ))
561 } else {
562 Err(Self::Error::InvalidSlotName)
563 }
564 }
565 PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
566 entity_type,
567 in_entity,
568 }) => ast::EntityType::from_normalized_str(entity_type.as_str())
569 .map_err(Self::Error::InvalidEntityType)
570 .and_then(|entity_type| {
571 Ok(match in_entity {
572 None => ast::PrincipalOrResourceConstraint::is_entity_type(Arc::new(
573 entity_type,
574 )),
575 Some(PrincipalOrResourceInConstraint::Entity { entity }) => {
576 ast::PrincipalOrResourceConstraint::is_entity_type_in(
577 Arc::new(entity_type),
578 Arc::new(
579 entity
580 .into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
581 ),
582 )
583 }
584 Some(PrincipalOrResourceInConstraint::Slot { .. }) => {
585 ast::PrincipalOrResourceConstraint::is_entity_type_in_slot(Arc::new(
586 entity_type,
587 ))
588 }
589 })
590 }),
591 }
592 }
593}
594
595impl TryFrom<ResourceConstraint> for ast::PrincipalOrResourceConstraint {
596 type Error = FromJsonError;
597 fn try_from(
598 constraint: ResourceConstraint,
599 ) -> Result<ast::PrincipalOrResourceConstraint, Self::Error> {
600 match constraint {
601 ResourceConstraint::All => Ok(ast::PrincipalOrResourceConstraint::Any),
602 ResourceConstraint::Eq(EqConstraint::Entity { entity }) => Ok(
603 ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::EUID(Arc::new(
604 entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
605 ))),
606 ),
607 ResourceConstraint::Eq(EqConstraint::Slot { slot }) => {
608 if slot == ast::SlotId::resource() {
609 Ok(ast::PrincipalOrResourceConstraint::Eq(
610 ast::EntityReference::Slot,
611 ))
612 } else {
613 Err(Self::Error::InvalidSlotName)
614 }
615 }
616 ResourceConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }) => Ok(
617 ast::PrincipalOrResourceConstraint::In(ast::EntityReference::EUID(Arc::new(
618 entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
619 ))),
620 ),
621 ResourceConstraint::In(PrincipalOrResourceInConstraint::Slot { slot }) => {
622 if slot == ast::SlotId::resource() {
623 Ok(ast::PrincipalOrResourceConstraint::In(
624 ast::EntityReference::Slot,
625 ))
626 } else {
627 Err(Self::Error::InvalidSlotName)
628 }
629 }
630 ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
631 entity_type,
632 in_entity,
633 }) => ast::EntityType::from_normalized_str(entity_type.as_str())
634 .map_err(Self::Error::InvalidEntityType)
635 .and_then(|entity_type| {
636 Ok(match in_entity {
637 None => ast::PrincipalOrResourceConstraint::is_entity_type(Arc::new(
638 entity_type,
639 )),
640 Some(PrincipalOrResourceInConstraint::Entity { entity }) => {
641 ast::PrincipalOrResourceConstraint::is_entity_type_in(
642 Arc::new(entity_type),
643 Arc::new(
644 entity
645 .into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
646 ),
647 )
648 }
649 Some(PrincipalOrResourceInConstraint::Slot { .. }) => {
650 ast::PrincipalOrResourceConstraint::is_entity_type_in_slot(Arc::new(
651 entity_type,
652 ))
653 }
654 })
655 }),
656 }
657 }
658}
659
660impl From<ast::ActionConstraint> for ActionConstraint {
661 fn from(constraint: ast::ActionConstraint) -> ActionConstraint {
662 match constraint {
663 ast::ActionConstraint::Any => ActionConstraint::All,
664 ast::ActionConstraint::Eq(e) => ActionConstraint::Eq(EqConstraint::Entity {
665 entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
666 }),
667 ast::ActionConstraint::In(es) => match &es[..] {
668 [e] => ActionConstraint::In(ActionInConstraint::Single {
669 entity: EntityUidJson::ImplicitEntityEscape((&**e).into()),
670 }),
671 es => ActionConstraint::In(ActionInConstraint::Set {
672 entities: es
673 .iter()
674 .map(|e| EntityUidJson::ImplicitEntityEscape((&**e).into()))
675 .collect(),
676 }),
677 },
678 }
679 }
680}
681
682impl TryFrom<ActionConstraint> for ast::ActionConstraint {
683 type Error = FromJsonError;
684 fn try_from(constraint: ActionConstraint) -> Result<ast::ActionConstraint, Self::Error> {
685 let ast_action_constraint = match constraint {
686 ActionConstraint::All => Ok(ast::ActionConstraint::Any),
687 ActionConstraint::Eq(EqConstraint::Entity { entity }) => Ok(ast::ActionConstraint::Eq(
688 Arc::new(entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?),
689 )),
690 ActionConstraint::Eq(EqConstraint::Slot { .. }) => Err(Self::Error::ActionSlot),
691 ActionConstraint::In(ActionInConstraint::Single { entity }) => {
692 Ok(ast::ActionConstraint::In(vec![Arc::new(
693 entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
694 )]))
695 }
696 ActionConstraint::In(ActionInConstraint::Set { entities }) => {
697 Ok(ast::ActionConstraint::In(
698 entities
699 .into_iter()
700 .map(|e| {
701 e.into_euid(|| JsonDeserializationErrorContext::EntityUid)
702 .map(Arc::new)
703 })
704 .collect::<Result<Vec<_>, _>>()?,
705 ))
706 }
707 }?;
708
709 ast_action_constraint
710 .contains_only_action_types()
711 .map_err(|non_action_euids| {
712 parse_errors::InvalidActionType {
713 euids: non_action_euids,
714 }
715 .into()
716 })
717 }
718}