scuffle_cedar_policy_codegen/
codegen.rs

1use 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
12/// Main code generation structure
13pub(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}