cedar_policy_validator/cedar_schema/
ast.rs1use std::iter::once;
18
19use cedar_policy_core::{
20 ast::{Id, InternalName},
21 parser::{Loc, Node},
22};
23use itertools::{Either, Itertools};
24use nonempty::NonEmpty;
25use smol_str::SmolStr;
26#[allow(unused_imports)]
28use smol_str::ToSmolStr;
29
30use crate::json_schema;
31
32pub const BUILTIN_TYPES: [&str; 3] = ["Long", "String", "Bool"];
33
34pub(super) const CEDAR_NAMESPACE: &str = "__cedar";
35
36pub type Schema = Vec<Node<Namespace>>;
37
38#[derive(Debug, Clone, PartialEq, Eq, Hash)]
40pub struct Path(Node<PathInternal>);
41impl Path {
42 pub fn single(basename: Id, loc: Loc) -> Self {
44 Self(Node::with_source_loc(
45 PathInternal {
46 basename,
47 namespace: vec![],
48 },
49 loc,
50 ))
51 }
52
53 pub fn new(basename: Id, namespace: impl IntoIterator<Item = Id>, loc: Loc) -> Self {
55 let namespace = namespace.into_iter().collect();
56 Self(Node::with_source_loc(
57 PathInternal {
58 basename,
59 namespace,
60 },
61 loc,
62 ))
63 }
64
65 pub fn iter(&self) -> impl Iterator<Item = &Id> {
67 self.0.node.iter()
68 }
69
70 pub fn loc(&self) -> &Loc {
72 &self.0.loc
73 }
74
75 pub fn into_iter(self) -> impl Iterator<Item = Node<Id>> {
77 let loc = self.0.loc;
78 self.0
79 .node
80 .into_iter()
81 .map(move |x| Node::with_source_loc(x, loc.clone()))
82 }
83
84 pub fn split_last(self) -> (Vec<Id>, Id) {
86 (self.0.node.namespace, self.0.node.basename)
87 }
88
89 pub fn is_in_cedar(&self) -> bool {
91 self.0.node.is_in_cedar()
92 }
93}
94
95impl From<Path> for InternalName {
96 fn from(value: Path) -> Self {
97 InternalName::new(
98 value.0.node.basename,
99 value.0.node.namespace,
100 Some(value.0.loc),
101 )
102 }
103}
104
105impl std::fmt::Display for Path {
106 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 write!(f, "{}", self.0.node)
108 }
109}
110
111#[derive(Debug, Clone, PartialEq, Eq, Hash)]
112struct PathInternal {
113 basename: Id,
114 namespace: Vec<Id>,
115}
116
117impl PathInternal {
118 fn iter(&self) -> impl Iterator<Item = &Id> {
119 self.namespace.iter().chain(once(&self.basename))
120 }
121
122 fn into_iter(self) -> impl Iterator<Item = Id> {
123 self.namespace.into_iter().chain(once(self.basename))
124 }
125
126 fn is_in_cedar(&self) -> bool {
128 match self.namespace.as_slice() {
129 [id] => id.as_ref() == CEDAR_NAMESPACE,
130 _ => false,
131 }
132 }
133}
134
135impl std::fmt::Display for PathInternal {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 if self.namespace.is_empty() {
138 write!(f, "{}", self.basename)
139 } else {
140 let namespace = self.namespace.iter().map(|id| id.as_ref()).join("::");
141 write!(f, "{namespace}::{}", self.basename)
142 }
143 }
144}
145
146#[derive(Debug, Clone)]
148pub struct QualName {
149 pub path: Option<Path>,
150 pub eid: SmolStr,
151}
152
153impl QualName {
154 pub fn unqualified(eid: SmolStr) -> Self {
155 Self { path: None, eid }
156 }
157
158 pub fn qualified(path: Path, eid: SmolStr) -> Self {
159 Self {
160 path: Some(path),
161 eid,
162 }
163 }
164}
165
166#[derive(Debug, Clone)]
170pub struct Namespace {
171 pub name: Option<Node<Path>>,
173 pub decls: Vec<Node<Declaration>>,
175}
176
177impl Namespace {
178 pub fn is_unqualified(&self) -> bool {
180 self.name.is_none()
181 }
182}
183
184pub trait Decl {
185 fn names(&self) -> Vec<Node<SmolStr>>;
186}
187
188#[derive(Debug, Clone)]
191pub enum Declaration {
192 Entity(EntityDecl),
193 Action(ActionDecl),
194 Type(TypeDecl),
195}
196
197#[derive(Debug, Clone)]
198pub struct TypeDecl {
199 pub name: Node<Id>,
200 pub def: Node<Type>,
201}
202
203impl Decl for TypeDecl {
204 fn names(&self) -> Vec<Node<SmolStr>> {
205 vec![self.name.clone().map(|id| id.to_smolstr())]
206 }
207}
208
209#[derive(Debug, Clone)]
211pub struct EntityDecl {
212 pub names: Vec<Node<Id>>,
215 pub member_of_types: Vec<Path>,
217 pub attrs: Vec<Node<AttrDecl>>,
219 pub tags: Option<Node<Type>>,
221}
222
223#[derive(Debug, Clone)]
225pub enum Type {
226 Set(Box<Node<Type>>),
228 Ident(Path),
230 Record(Vec<Node<AttrDecl>>),
232}
233
234#[derive(Debug, Clone)]
236pub enum PrimitiveType {
237 Long,
239 String,
241 Bool,
243}
244
245impl<N> From<PrimitiveType> for json_schema::TypeVariant<N> {
246 fn from(value: PrimitiveType) -> Self {
247 match value {
248 PrimitiveType::Long => json_schema::TypeVariant::Long,
249 PrimitiveType::String => json_schema::TypeVariant::String,
250 PrimitiveType::Bool => json_schema::TypeVariant::Boolean,
251 }
252 }
253}
254
255#[derive(Debug, Clone)]
258pub struct AttrDecl {
259 pub name: Node<SmolStr>,
261 pub required: bool,
263 pub ty: Node<Type>,
265}
266
267#[derive(Debug, Clone, Copy, PartialEq, Eq)]
269pub enum PR {
270 Principal,
272 Resource,
274}
275
276impl std::fmt::Display for PR {
277 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
278 match self {
279 PR::Principal => write!(f, "principal"),
280 PR::Resource => write!(f, "resource"),
281 }
282 }
283}
284
285#[derive(Debug, Clone)]
287pub struct PRAppDecl {
288 pub kind: Node<PR>,
290 pub entity_tys: NonEmpty<Path>,
292}
293
294#[derive(Debug, Clone)]
296pub enum AppDecl {
297 PR(PRAppDecl),
299 Context(Either<Path, Vec<Node<AttrDecl>>>),
301}
302
303#[derive(Debug, Clone)]
305pub struct ActionDecl {
306 pub names: NonEmpty<Node<SmolStr>>,
309 pub parents: Option<NonEmpty<Node<QualName>>>,
311 pub app_decls: Option<Node<NonEmpty<Node<AppDecl>>>>,
313}
314
315impl Decl for ActionDecl {
316 fn names(&self) -> Vec<Node<SmolStr>> {
317 self.names.iter().cloned().collect()
318 }
319}
320
321#[cfg(test)]
322mod test {
323 use std::sync::Arc;
324
325 use super::*;
326
327 fn loc() -> Loc {
328 Loc::new((1, 1), Arc::from("foo"))
329 }
330
331 #[test]
333 fn path_iter() {
334 let p = Path::new(
335 "baz".parse().unwrap(),
336 ["foo".parse().unwrap(), "bar".parse().unwrap()],
337 loc(),
338 );
339
340 let expected: Vec<Id> = vec![
341 "foo".parse().unwrap(),
342 "bar".parse().unwrap(),
343 "baz".parse().unwrap(),
344 ];
345
346 let expected_borrowed = expected.iter().collect::<Vec<_>>();
347
348 let borrowed = p.iter().collect::<Vec<_>>();
349 assert_eq!(borrowed, expected_borrowed);
350 let moved = p.into_iter().map(|n| n.node).collect::<Vec<_>>();
351 assert_eq!(moved, expected);
352 }
353}