scuffle_cedar_policy_codegen/
types.rs

1use std::collections::{BTreeMap, BTreeSet};
2use std::fmt::Write;
3
4use cedar_policy_core::ast::Id;
5use cedar_policy_core::validator::RawName;
6
7use crate::utils::{to_snake_ident, to_upper_camel_ident};
8
9/// Represents a reference to a Cedar type with its namespace
10#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Debug)]
11pub(crate) struct CedarRef {
12    pub(crate) id: Id,
13    pub(crate) namespace: NamespaceId,
14}
15
16impl From<RawName> for CedarRef {
17    fn from(value: RawName) -> Self {
18        let qualified_value = value.qualify_with(None);
19        Self {
20            id: qualified_value.basename().clone(),
21            namespace: NamespaceId {
22                items: qualified_value.namespace_components().cloned().collect(),
23            },
24        }
25    }
26}
27
28impl CedarRef {
29    /// Converts this reference to a CedarType
30    pub(crate) fn into_cedar_ty(self) -> CedarType {
31        match self.id.as_ref() {
32            "Bool" => CedarType::Bool,
33            "Long" => CedarType::Long,
34            "String" => CedarType::String,
35            _ => CedarType::Reference(self),
36        }
37    }
38
39    /// Gets the identifier path for this reference
40    pub(crate) fn ident_path(&self) -> Vec<syn::Ident> {
41        self.namespace
42            .items
43            .iter()
44            .map(to_snake_ident)
45            .chain(std::iter::once(&self.id).map(to_upper_camel_ident))
46            .collect()
47    }
48}
49
50/// Represents a namespace identifier with components
51#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Default, Clone)]
52pub(crate) struct NamespaceId {
53    pub items: Vec<Id>,
54}
55
56/// Represents a field within a Cedar record type
57#[derive(Debug)]
58pub(crate) struct CedarTypeStructField {
59    pub ty: CedarType,
60    pub optional: bool,
61}
62
63/// Represents an action entity identifier
64#[derive(Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
65pub(crate) struct ActionEid {
66    pub id: Option<CedarRef>,
67    pub name: String,
68}
69
70/// Represents different Cedar types
71#[derive(Debug)]
72pub(crate) enum CedarType {
73    String,
74    Long,
75    Bool,
76    Record {
77        fields: BTreeMap<String, CedarTypeStructField>,
78        allows_additional: bool,
79    },
80    Set(Box<CedarType>),
81    Enum(BTreeSet<String>),
82    Reference(CedarRef),
83    Entity {
84        parents: Vec<CedarRef>,
85        shape: Box<CedarType>,
86        tag_type: Option<Box<CedarType>>,
87    },
88}
89
90impl CedarType {
91    /// Returns true if this type represents an entity
92    pub(crate) fn is_entity(&self) -> bool {
93        matches!(self, Self::Entity { .. } | Self::Enum(_))
94    }
95}
96
97impl std::fmt::Display for ActionEid {
98    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99        if let Some(id) = &self.id {
100            id.fmt(f)?;
101            f.write_str("::")?;
102        }
103
104        f.write_char('"')?;
105        f.write_str(&self.name)?;
106        f.write_char('"')
107    }
108}
109
110impl std::fmt::Debug for NamespaceId {
111    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112        write!(f, "NamespaceId(\"{self}\")")
113    }
114}
115
116impl std::fmt::Display for CedarRef {
117    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
118        self.namespace.fmt(f)?;
119        if !self.namespace.items.is_empty() {
120            f.write_str("::")?;
121        }
122        self.id.fmt(f)
123    }
124}
125
126impl std::fmt::Display for NamespaceId {
127    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128        let mut first = true;
129        for part in &self.items {
130            if !first {
131                f.write_str("::")?;
132            }
133            part.fmt(f)?;
134            first = false;
135        }
136        Ok(())
137    }
138}