use super::{FromJsonError, LinkingError};
use crate::ast;
use crate::ast::EntityUID;
use crate::entities::json::{
err::JsonDeserializationError, err::JsonDeserializationErrorContext, EntityUidJson,
};
use crate::parser::err::parse_errors;
use serde::{Deserialize, Serialize};
use smol_str::SmolStr;
use std::collections::{BTreeMap, HashMap};
use std::sync::Arc;
#[cfg(feature = "wasm")]
extern crate tsify;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
#[serde(tag = "op")]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
pub enum PrincipalConstraint {
#[serde(alias = "all")]
All,
#[serde(rename = "==")]
Eq(EqConstraint),
#[serde(rename = "in")]
In(PrincipalOrResourceInConstraint),
#[serde(rename = "is")]
Is(PrincipalOrResourceIsConstraint),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
#[serde(tag = "op")]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
pub enum ActionConstraint {
#[serde(alias = "all")]
All,
#[serde(rename = "==")]
Eq(EqConstraint),
#[serde(rename = "in")]
In(ActionInConstraint),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
#[serde(tag = "op")]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
pub enum ResourceConstraint {
#[serde(alias = "all")]
All,
#[serde(rename = "==")]
Eq(EqConstraint),
#[serde(rename = "in")]
In(PrincipalOrResourceInConstraint),
#[serde(rename = "is")]
Is(PrincipalOrResourceIsConstraint),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
pub enum EqConstraint {
Entity {
entity: EntityUidJson,
},
Slot {
#[cfg_attr(feature = "wasm", tsify(type = "string"))]
slot: ast::SlotId,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
pub enum PrincipalOrResourceInConstraint {
Entity {
entity: EntityUidJson,
},
Slot {
#[cfg_attr(feature = "wasm", tsify(type = "string"))]
slot: ast::SlotId,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
pub struct PrincipalOrResourceIsConstraint {
#[cfg_attr(feature = "wasm", tsify(type = "string"))]
entity_type: SmolStr,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "in")]
in_entity: Option<PrincipalOrResourceInConstraint>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
pub enum ActionInConstraint {
Single {
entity: EntityUidJson,
},
Set {
entities: Vec<EntityUidJson>,
},
}
impl PrincipalConstraint {
pub fn link(self, vals: &HashMap<ast::SlotId, EntityUidJson>) -> Result<Self, LinkingError> {
match self {
PrincipalConstraint::All => Ok(PrincipalConstraint::All),
PrincipalConstraint::Eq(EqConstraint::Entity { entity }) => {
Ok(PrincipalConstraint::Eq(EqConstraint::Entity { entity }))
}
PrincipalConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }) => Ok(
PrincipalConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }),
),
PrincipalConstraint::Eq(EqConstraint::Slot { slot }) => match vals.get(&slot) {
Some(val) => Ok(PrincipalConstraint::Eq(EqConstraint::Entity {
entity: val.clone(),
})),
None => Err(LinkingError::MissedSlot { slot }),
},
PrincipalConstraint::In(PrincipalOrResourceInConstraint::Slot { slot }) => {
match vals.get(&slot) {
Some(val) => Ok(PrincipalConstraint::In(
PrincipalOrResourceInConstraint::Entity {
entity: val.clone(),
},
)),
None => Err(LinkingError::MissedSlot { slot }),
}
}
e @ PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
entity_type: _,
in_entity: None | Some(PrincipalOrResourceInConstraint::Entity { .. }),
}) => Ok(e),
PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
entity_type,
in_entity: Some(PrincipalOrResourceInConstraint::Slot { slot }),
}) => Ok(PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
entity_type,
in_entity: Some(PrincipalOrResourceInConstraint::Entity {
entity: vals
.get(&slot)
.ok_or(LinkingError::MissedSlot { slot })?
.clone(),
}),
})),
}
}
pub fn sub_entity_literals(
self,
mapping: &BTreeMap<EntityUID, EntityUID>,
) -> Result<Self, JsonDeserializationError> {
match self.clone() {
PrincipalConstraint::All
| PrincipalConstraint::Eq(EqConstraint::Slot { .. })
| PrincipalConstraint::In(PrincipalOrResourceInConstraint::Slot { .. })
| PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
in_entity: Some(PrincipalOrResourceInConstraint::Slot { .. }),
..
})
| PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
entity_type: _,
in_entity: None,
}) => Ok(self.clone()),
PrincipalConstraint::Eq(EqConstraint::Entity { entity }) => {
let euid = entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?;
match mapping.get(&euid) {
Some(new_euid) => Ok(PrincipalConstraint::Eq(EqConstraint::Entity {
entity: new_euid.into(),
})),
None => Ok(self.clone()),
}
}
PrincipalConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }) => {
let euid = entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?;
match mapping.get(&euid) {
Some(new_euid) => Ok(PrincipalConstraint::In(
PrincipalOrResourceInConstraint::Entity {
entity: new_euid.into(),
},
)),
None => Ok(self.clone()),
}
}
PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
entity_type: ety,
in_entity: Some(PrincipalOrResourceInConstraint::Entity { entity }),
}) => {
let euid = entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?;
match mapping.get(&euid) {
Some(new_euid) => {
Ok(PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
entity_type: ety,
in_entity: Some(PrincipalOrResourceInConstraint::Entity {
entity: new_euid.into(),
}),
}))
}
None => Ok(self.clone()),
}
}
}
}
}
impl ResourceConstraint {
pub fn link(self, vals: &HashMap<ast::SlotId, EntityUidJson>) -> Result<Self, LinkingError> {
match self {
ResourceConstraint::All => Ok(ResourceConstraint::All),
ResourceConstraint::Eq(EqConstraint::Entity { entity }) => {
Ok(ResourceConstraint::Eq(EqConstraint::Entity { entity }))
}
ResourceConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }) => Ok(
ResourceConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }),
),
ResourceConstraint::Eq(EqConstraint::Slot { slot }) => match vals.get(&slot) {
Some(val) => Ok(ResourceConstraint::Eq(EqConstraint::Entity {
entity: val.clone(),
})),
None => Err(LinkingError::MissedSlot { slot }),
},
ResourceConstraint::In(PrincipalOrResourceInConstraint::Slot { slot }) => {
match vals.get(&slot) {
Some(val) => Ok(ResourceConstraint::In(
PrincipalOrResourceInConstraint::Entity {
entity: val.clone(),
},
)),
None => Err(LinkingError::MissedSlot { slot }),
}
}
e @ ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
entity_type: _,
in_entity: None | Some(PrincipalOrResourceInConstraint::Entity { .. }),
}) => Ok(e),
ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
entity_type,
in_entity: Some(PrincipalOrResourceInConstraint::Slot { slot }),
}) => Ok(ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
entity_type,
in_entity: Some(PrincipalOrResourceInConstraint::Entity {
entity: vals
.get(&slot)
.ok_or(LinkingError::MissedSlot { slot })?
.clone(),
}),
})),
}
}
pub fn sub_entity_literals(
self,
mapping: &BTreeMap<EntityUID, EntityUID>,
) -> Result<Self, JsonDeserializationError> {
match self.clone() {
ResourceConstraint::All
| ResourceConstraint::Eq(EqConstraint::Slot { .. })
| ResourceConstraint::In(PrincipalOrResourceInConstraint::Slot { .. })
| ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
in_entity: Some(PrincipalOrResourceInConstraint::Slot { .. }),
..
})
| ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
entity_type: _,
in_entity: None,
}) => Ok(self.clone()),
ResourceConstraint::Eq(EqConstraint::Entity { entity }) => {
let euid = entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?;
match mapping.get(&euid) {
Some(new_euid) => Ok(ResourceConstraint::Eq(EqConstraint::Entity {
entity: new_euid.into(),
})),
None => Ok(self.clone()),
}
}
ResourceConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }) => {
let euid = entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?;
match mapping.get(&euid) {
Some(new_euid) => Ok(ResourceConstraint::In(
PrincipalOrResourceInConstraint::Entity {
entity: new_euid.into(),
},
)),
None => Ok(self.clone()),
}
}
ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
entity_type: ety,
in_entity: Some(PrincipalOrResourceInConstraint::Entity { entity }),
}) => {
let euid = entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?;
match mapping.get(&euid) {
Some(new_euid) => Ok(ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
entity_type: ety,
in_entity: Some(PrincipalOrResourceInConstraint::Entity {
entity: new_euid.into(),
}),
})),
None => Ok(self.clone()),
}
}
}
}
}
impl ActionConstraint {
pub fn link(self, _vals: &HashMap<ast::SlotId, EntityUidJson>) -> Result<Self, LinkingError> {
Ok(self)
}
pub fn sub_entity_literals(
self,
mapping: &BTreeMap<EntityUID, EntityUID>,
) -> Result<Self, JsonDeserializationError> {
match self.clone() {
ActionConstraint::Eq(EqConstraint::Entity { entity }) => {
let euid = entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?;
match mapping.get(&euid) {
Some(new_euid) => Ok(ActionConstraint::Eq(EqConstraint::Entity {
entity: new_euid.into(),
})),
None => Ok(self.clone()),
}
}
ActionConstraint::In(ActionInConstraint::Single { entity }) => {
let euid = entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?;
match mapping.get(&euid) {
Some(new_euid) => Ok(ActionConstraint::In(ActionInConstraint::Single {
entity: new_euid.into(),
})),
None => Ok(self.clone()),
}
}
ActionConstraint::In(ActionInConstraint::Set { entities }) => {
let mut new_entities: Vec<EntityUidJson> = vec![];
for entity in entities {
let euid = entity
.clone()
.into_euid(|| JsonDeserializationErrorContext::EntityUid)?;
match mapping.get(&euid) {
Some(new_euid) => new_entities.push(new_euid.clone().into()),
None => new_entities.push(entity),
};
}
Ok(ActionConstraint::In(ActionInConstraint::Set {
entities: new_entities,
}))
}
ActionConstraint::All | ActionConstraint::Eq(EqConstraint::Slot { .. }) => {
Ok(self.clone())
}
}
}
}
impl std::fmt::Display for PrincipalConstraint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::All => write!(f, "principal"),
Self::Eq(ec) => {
write!(f, "principal ")?;
std::fmt::Display::fmt(ec, f)?;
Ok(())
}
Self::In(ic) => {
write!(f, "principal ")?;
std::fmt::Display::fmt(ic, f)?;
Ok(())
}
Self::Is(isc) => {
write!(f, "principal ")?;
std::fmt::Display::fmt(isc, f)?;
Ok(())
}
}
}
}
impl std::fmt::Display for ActionConstraint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::All => write!(f, "action"),
Self::Eq(ec) => {
write!(f, "action ")?;
std::fmt::Display::fmt(ec, f)?;
Ok(())
}
Self::In(aic) => {
write!(f, "action ")?;
std::fmt::Display::fmt(aic, f)?;
Ok(())
}
}
}
}
impl std::fmt::Display for ResourceConstraint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::All => write!(f, "resource"),
Self::Eq(ec) => {
write!(f, "resource ")?;
std::fmt::Display::fmt(ec, f)?;
Ok(())
}
Self::In(ic) => {
write!(f, "resource ")?;
std::fmt::Display::fmt(ic, f)?;
Ok(())
}
Self::Is(isc) => {
write!(f, "resource ")?;
std::fmt::Display::fmt(isc, f)?;
Ok(())
}
}
}
}
impl std::fmt::Display for EqConstraint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Entity { entity } => {
match entity
.clone()
.into_euid(|| JsonDeserializationErrorContext::EntityUid)
{
Ok(euid) => write!(f, "== {euid}"),
Err(e) => write!(f, "== (invalid entity uid: {e})"),
}
}
Self::Slot { slot } => write!(f, "== {slot}"),
}
}
}
impl std::fmt::Display for PrincipalOrResourceInConstraint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Entity { entity } => {
match entity
.clone()
.into_euid(|| JsonDeserializationErrorContext::EntityUid)
{
Ok(euid) => write!(f, "in {euid}"),
Err(e) => write!(f, "in (invalid entity uid: {e})"),
}
}
Self::Slot { slot } => write!(f, "in {slot}"),
}
}
}
impl std::fmt::Display for PrincipalOrResourceIsConstraint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "is {}", self.entity_type)?;
if let Some(in_entity) = &self.in_entity {
write!(f, " {}", in_entity)?;
}
Ok(())
}
}
impl std::fmt::Display for ActionInConstraint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Single { entity } => {
match entity
.clone()
.into_euid(|| JsonDeserializationErrorContext::EntityUid)
{
Ok(euid) => write!(f, "in {euid}"),
Err(e) => write!(f, "in (invalid entity uid: {e})"),
}
}
Self::Set { entities } => {
write!(f, "in [")?;
for (i, entity) in entities.iter().enumerate() {
match entity
.clone()
.into_euid(|| JsonDeserializationErrorContext::EntityUid)
{
Ok(euid) => write!(f, "{euid}"),
Err(e) => write!(f, "(invalid entity uid: {e})"),
}?;
if i < (entities.len() - 1) {
write!(f, ", ")?;
}
}
write!(f, "]")?;
Ok(())
}
}
}
}
impl From<ast::PrincipalConstraint> for PrincipalConstraint {
fn from(constraint: ast::PrincipalConstraint) -> PrincipalConstraint {
constraint.constraint.into()
}
}
impl TryFrom<PrincipalConstraint> for ast::PrincipalConstraint {
type Error = FromJsonError;
fn try_from(constraint: PrincipalConstraint) -> Result<ast::PrincipalConstraint, Self::Error> {
constraint.try_into().map(ast::PrincipalConstraint::new)
}
}
impl From<ast::ResourceConstraint> for ResourceConstraint {
fn from(constraint: ast::ResourceConstraint) -> ResourceConstraint {
constraint.constraint.into()
}
}
impl TryFrom<ResourceConstraint> for ast::ResourceConstraint {
type Error = FromJsonError;
fn try_from(constraint: ResourceConstraint) -> Result<ast::ResourceConstraint, Self::Error> {
constraint.try_into().map(ast::ResourceConstraint::new)
}
}
impl From<ast::PrincipalOrResourceConstraint> for PrincipalConstraint {
fn from(constraint: ast::PrincipalOrResourceConstraint) -> PrincipalConstraint {
match constraint {
ast::PrincipalOrResourceConstraint::Any => PrincipalConstraint::All,
ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::EUID(e)) => {
PrincipalConstraint::Eq(EqConstraint::Entity {
entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
})
}
ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::Slot) => {
PrincipalConstraint::Eq(EqConstraint::Slot {
slot: ast::SlotId::principal(),
})
}
ast::PrincipalOrResourceConstraint::In(ast::EntityReference::EUID(e)) => {
PrincipalConstraint::In(PrincipalOrResourceInConstraint::Entity {
entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
})
}
ast::PrincipalOrResourceConstraint::In(ast::EntityReference::Slot) => {
PrincipalConstraint::In(PrincipalOrResourceInConstraint::Slot {
slot: ast::SlotId::principal(),
})
}
ast::PrincipalOrResourceConstraint::IsIn(entity_type, euid) => {
PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
entity_type: entity_type.to_string().into(),
in_entity: Some(match euid {
ast::EntityReference::EUID(e) => PrincipalOrResourceInConstraint::Entity {
entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
},
ast::EntityReference::Slot => PrincipalOrResourceInConstraint::Slot {
slot: ast::SlotId::principal(),
},
}),
})
}
ast::PrincipalOrResourceConstraint::Is(entity_type) => {
PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
entity_type: entity_type.to_string().into(),
in_entity: None,
})
}
}
}
}
impl From<ast::PrincipalOrResourceConstraint> for ResourceConstraint {
fn from(constraint: ast::PrincipalOrResourceConstraint) -> ResourceConstraint {
match constraint {
ast::PrincipalOrResourceConstraint::Any => ResourceConstraint::All,
ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::EUID(e)) => {
ResourceConstraint::Eq(EqConstraint::Entity {
entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
})
}
ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::Slot) => {
ResourceConstraint::Eq(EqConstraint::Slot {
slot: ast::SlotId::resource(),
})
}
ast::PrincipalOrResourceConstraint::In(ast::EntityReference::EUID(e)) => {
ResourceConstraint::In(PrincipalOrResourceInConstraint::Entity {
entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
})
}
ast::PrincipalOrResourceConstraint::In(ast::EntityReference::Slot) => {
ResourceConstraint::In(PrincipalOrResourceInConstraint::Slot {
slot: ast::SlotId::resource(),
})
}
ast::PrincipalOrResourceConstraint::IsIn(entity_type, euid) => {
ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
entity_type: entity_type.to_string().into(),
in_entity: Some(match euid {
ast::EntityReference::EUID(e) => PrincipalOrResourceInConstraint::Entity {
entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
},
ast::EntityReference::Slot => PrincipalOrResourceInConstraint::Slot {
slot: ast::SlotId::resource(),
},
}),
})
}
ast::PrincipalOrResourceConstraint::Is(entity_type) => {
ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
entity_type: entity_type.to_string().into(),
in_entity: None,
})
}
}
}
}
impl TryFrom<PrincipalConstraint> for ast::PrincipalOrResourceConstraint {
type Error = FromJsonError;
fn try_from(
constraint: PrincipalConstraint,
) -> Result<ast::PrincipalOrResourceConstraint, Self::Error> {
match constraint {
PrincipalConstraint::All => Ok(ast::PrincipalOrResourceConstraint::Any),
PrincipalConstraint::Eq(EqConstraint::Entity { entity }) => Ok(
ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::EUID(Arc::new(
entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
))),
),
PrincipalConstraint::Eq(EqConstraint::Slot { slot }) => {
if slot == ast::SlotId::principal() {
Ok(ast::PrincipalOrResourceConstraint::Eq(
ast::EntityReference::Slot,
))
} else {
Err(Self::Error::InvalidSlotName)
}
}
PrincipalConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }) => Ok(
ast::PrincipalOrResourceConstraint::In(ast::EntityReference::EUID(Arc::new(
entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
))),
),
PrincipalConstraint::In(PrincipalOrResourceInConstraint::Slot { slot }) => {
if slot == ast::SlotId::principal() {
Ok(ast::PrincipalOrResourceConstraint::In(
ast::EntityReference::Slot,
))
} else {
Err(Self::Error::InvalidSlotName)
}
}
PrincipalConstraint::Is(PrincipalOrResourceIsConstraint {
entity_type,
in_entity,
}) => ast::EntityType::from_normalized_str(entity_type.as_str())
.map_err(Self::Error::InvalidEntityType)
.and_then(|entity_type| {
Ok(match in_entity {
None => ast::PrincipalOrResourceConstraint::is_entity_type(Arc::new(
entity_type,
)),
Some(PrincipalOrResourceInConstraint::Entity { entity }) => {
ast::PrincipalOrResourceConstraint::is_entity_type_in(
Arc::new(entity_type),
Arc::new(
entity
.into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
),
)
}
Some(PrincipalOrResourceInConstraint::Slot { .. }) => {
ast::PrincipalOrResourceConstraint::is_entity_type_in_slot(Arc::new(
entity_type,
))
}
})
}),
}
}
}
impl TryFrom<ResourceConstraint> for ast::PrincipalOrResourceConstraint {
type Error = FromJsonError;
fn try_from(
constraint: ResourceConstraint,
) -> Result<ast::PrincipalOrResourceConstraint, Self::Error> {
match constraint {
ResourceConstraint::All => Ok(ast::PrincipalOrResourceConstraint::Any),
ResourceConstraint::Eq(EqConstraint::Entity { entity }) => Ok(
ast::PrincipalOrResourceConstraint::Eq(ast::EntityReference::EUID(Arc::new(
entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
))),
),
ResourceConstraint::Eq(EqConstraint::Slot { slot }) => {
if slot == ast::SlotId::resource() {
Ok(ast::PrincipalOrResourceConstraint::Eq(
ast::EntityReference::Slot,
))
} else {
Err(Self::Error::InvalidSlotName)
}
}
ResourceConstraint::In(PrincipalOrResourceInConstraint::Entity { entity }) => Ok(
ast::PrincipalOrResourceConstraint::In(ast::EntityReference::EUID(Arc::new(
entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
))),
),
ResourceConstraint::In(PrincipalOrResourceInConstraint::Slot { slot }) => {
if slot == ast::SlotId::resource() {
Ok(ast::PrincipalOrResourceConstraint::In(
ast::EntityReference::Slot,
))
} else {
Err(Self::Error::InvalidSlotName)
}
}
ResourceConstraint::Is(PrincipalOrResourceIsConstraint {
entity_type,
in_entity,
}) => ast::EntityType::from_normalized_str(entity_type.as_str())
.map_err(Self::Error::InvalidEntityType)
.and_then(|entity_type| {
Ok(match in_entity {
None => ast::PrincipalOrResourceConstraint::is_entity_type(Arc::new(
entity_type,
)),
Some(PrincipalOrResourceInConstraint::Entity { entity }) => {
ast::PrincipalOrResourceConstraint::is_entity_type_in(
Arc::new(entity_type),
Arc::new(
entity
.into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
),
)
}
Some(PrincipalOrResourceInConstraint::Slot { .. }) => {
ast::PrincipalOrResourceConstraint::is_entity_type_in_slot(Arc::new(
entity_type,
))
}
})
}),
}
}
}
impl From<ast::ActionConstraint> for ActionConstraint {
fn from(constraint: ast::ActionConstraint) -> ActionConstraint {
match constraint {
ast::ActionConstraint::Any => ActionConstraint::All,
ast::ActionConstraint::Eq(e) => ActionConstraint::Eq(EqConstraint::Entity {
entity: EntityUidJson::ImplicitEntityEscape((&*e).into()),
}),
ast::ActionConstraint::In(es) => match &es[..] {
[e] => ActionConstraint::In(ActionInConstraint::Single {
entity: EntityUidJson::ImplicitEntityEscape((&**e).into()),
}),
es => ActionConstraint::In(ActionInConstraint::Set {
entities: es
.iter()
.map(|e| EntityUidJson::ImplicitEntityEscape((&**e).into()))
.collect(),
}),
},
}
}
}
impl TryFrom<ActionConstraint> for ast::ActionConstraint {
type Error = FromJsonError;
fn try_from(constraint: ActionConstraint) -> Result<ast::ActionConstraint, Self::Error> {
let ast_action_constraint = match constraint {
ActionConstraint::All => Ok(ast::ActionConstraint::Any),
ActionConstraint::Eq(EqConstraint::Entity { entity }) => Ok(ast::ActionConstraint::Eq(
Arc::new(entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?),
)),
ActionConstraint::Eq(EqConstraint::Slot { .. }) => Err(Self::Error::ActionSlot),
ActionConstraint::In(ActionInConstraint::Single { entity }) => {
Ok(ast::ActionConstraint::In(vec![Arc::new(
entity.into_euid(|| JsonDeserializationErrorContext::EntityUid)?,
)]))
}
ActionConstraint::In(ActionInConstraint::Set { entities }) => {
Ok(ast::ActionConstraint::In(
entities
.into_iter()
.map(|e| {
e.into_euid(|| JsonDeserializationErrorContext::EntityUid)
.map(Arc::new)
})
.collect::<Result<Vec<_>, _>>()?,
))
}
}?;
ast_action_constraint
.contains_only_action_types()
.map_err(|non_action_euids| {
parse_errors::InvalidActionType {
euids: non_action_euids,
}
.into()
})
}
}