scuffle_cedar_policy_codegen/
cedar_namespace.rs1use std::collections::BTreeMap;
2
3use cedar_policy_core::ast::{Id, UnreservedId};
4use cedar_policy_core::validator::RawName;
5use cedar_policy_core::validator::json_schema::{self, ActionType, CommonType, CommonTypeId, EntityType};
6
7use crate::cedar_action::CedarAction;
8use crate::error::CodegenError;
9use crate::types::{ActionEid, CedarType};
10use crate::utils::convert_cedar_to_rust;
11
12#[derive(Default, Debug)]
14pub(crate) struct CedarNamespace {
15 pub types: BTreeMap<Id, CedarType>,
16 pub actions: BTreeMap<String, CedarAction>,
17}
18
19impl CedarNamespace {
20 pub(crate) fn handle_common_type(&mut self, id: &CommonTypeId, ty: &CommonType<RawName>) -> Result<(), CodegenError> {
22 let id = id.as_ref().clone().into();
23 if self.types.contains_key(&id) {
24 return Err(CodegenError::DuplicateType(id));
25 }
26
27 self.types.insert(id, convert_cedar_to_rust(&ty.ty)?);
28 Ok(())
29 }
30
31 pub(crate) fn handle_entity_type(&mut self, id: &UnreservedId, ty: &EntityType<RawName>) -> Result<(), CodegenError> {
33 let id = id.clone().into();
34 if self.types.contains_key(&id) {
35 return Err(CodegenError::DuplicateType(id));
36 }
37
38 let cedar_type = match &ty.kind {
39 json_schema::EntityTypeKind::Enum { choices } => {
40 CedarType::Enum(choices.iter().map(|c| c.to_string()).collect())
41 }
42 json_schema::EntityTypeKind::Standard(std) => CedarType::Entity {
43 parents: std.member_of_types.iter().cloned().map(Into::into).collect(),
44 tag_type: std.tags.as_ref().map(convert_cedar_to_rust).transpose()?.map(Box::new),
45 shape: Box::new(convert_cedar_to_rust(&std.shape.0)?),
46 },
47 };
48
49 self.types.insert(id, cedar_type);
50 Ok(())
51 }
52
53 pub(crate) fn handle_action(&mut self, action: &str, ty: &ActionType<RawName>) -> Result<(), CodegenError> {
55 if self.actions.contains_key(action) {
56 return Err(CodegenError::DuplicateAction(action.to_string()));
57 }
58
59 let member_of = ty
60 .member_of
61 .as_ref()
62 .map(|m| m.iter())
63 .into_iter()
64 .flatten()
65 .map(|m| ActionEid {
66 id: m.ty.clone().map(Into::into),
67 name: m.id.to_string(),
68 })
69 .collect();
70
71 let mut cedar_action = CedarAction {
72 parents: member_of,
73 ..Default::default()
74 };
75
76 if let Some(applies_to) = &ty.applies_to {
77 cedar_action.context = self.extract_context_type(&applies_to.context.0)?;
78 cedar_action.principals = applies_to.principal_types.iter().cloned().map(Into::into).collect();
79 cedar_action.resources = applies_to.resource_types.iter().cloned().map(Into::into).collect();
80 }
81
82 self.actions.insert(action.to_owned(), cedar_action);
83 Ok(())
84 }
85
86 fn extract_context_type(&self, context_type: &json_schema::Type<RawName>) -> Result<Option<CedarType>, CodegenError> {
88 match context_type {
89 json_schema::Type::Type {
90 ty: json_schema::TypeVariant::Record(r),
91 ..
92 } if !r.additional_attributes && r.attributes.is_empty() => Ok(None),
93 r => Ok(Some(convert_cedar_to_rust(r)?)),
94 }
95 }
96}