scuffle_cedar_policy_codegen/
codegen.rs1use std::collections::BTreeMap;
2
3use cedar_policy_core::ast::Id;
4
5use crate::Config;
6use crate::cedar_action::CedarAction;
7use crate::cedar_namespace::CedarNamespace;
8use crate::error::CodegenError;
9use crate::module::Module;
10use crate::types::{ActionEid, CedarRef, CedarType, NamespaceId};
11
12pub(crate) struct Codegen<'a> {
14 config: &'a Config,
15 namespaces: BTreeMap<NamespaceId, CedarNamespace>,
16}
17
18impl<'a> Codegen<'a> {
19 pub(crate) fn new(config: &'a Config) -> Self {
20 Self {
21 config,
22 namespaces: BTreeMap::default(),
23 }
24 }
25
26 pub(crate) fn config(&self) -> &'a Config {
27 self.config
28 }
29
30 pub(crate) fn add_namespace(&mut self, id: NamespaceId, ns: CedarNamespace) {
31 self.namespaces.insert(id, ns);
32 }
33
34 pub(crate) fn generate(&self) -> Result<syn::File, CodegenError> {
35 let mut root = Module::default();
36
37 for (ns_id, ns) in &self.namespaces {
38 let module = self.get_namespace_module(&mut root, ns_id);
39 self.generate_types(ns_id, module, &ns.types)?;
40 self.generate_actions(ns_id, module, &ns.actions)?;
41 }
42
43 Ok(syn::File {
44 attrs: Vec::new(),
45 items: root.into_items(),
46 shebang: None,
47 })
48 }
49
50 fn get_namespace_module<'b>(&self, root: &'b mut Module, ns_id: &NamespaceId) -> &'b mut Module {
51 ns_id.items.iter().fold(root, |module, id| module.sub_module(id))
52 }
53
54 fn generate_types(
55 &self,
56 ns_id: &NamespaceId,
57 module: &mut Module,
58 types: &BTreeMap<Id, CedarType>,
59 ) -> Result<(), CodegenError> {
60 for (id, ty) in types {
61 module.handle_type(self, ns_id, id, ty)?;
62 }
63 Ok(())
64 }
65
66 fn generate_actions(
67 &self,
68 ns_id: &NamespaceId,
69 module: &mut Module,
70 actions: &BTreeMap<String, CedarAction>,
71 ) -> Result<(), CodegenError> {
72 for (action, ty) in actions {
73 module.sub_module("action").handle_action(self, ns_id, action, ty)?;
74 }
75 Ok(())
76 }
77
78 pub(crate) fn resolve_ref(&self, reference: &CedarRef) -> Option<&CedarType> {
79 self.namespaces.get(&reference.namespace)?.types.get(&reference.id)
80 }
81
82 pub(crate) fn contains_action(&self, ns: &NamespaceId, action: &ActionEid) -> bool {
83 if action.id.as_ref().is_some_and(|id| id.id.as_ref() != "Action") {
84 return false;
85 }
86
87 self.namespaces
88 .get(action.id.as_ref().map(|i| &i.namespace).unwrap_or(ns))
89 .is_some_and(|ns| ns.actions.contains_key(&action.name))
90 }
91}