cedar_policy_core/ast/
name.rs1use std::sync::Arc;
18
19use itertools::Itertools;
20use serde::{Deserialize, Serialize};
21use smol_str::SmolStr;
22
23use super::PrincipalOrResource;
24use crate::{parser::err::ParseError, FromNormalizedStr};
25
26pub fn unwrap_or_clone<T: Clone>(arc: Arc<T>) -> T {
30 Arc::try_unwrap(arc).unwrap_or_else(|arc| (*arc).clone())
31}
32
33#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Hash, PartialOrd, Ord)]
37#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
38pub struct Name {
39 pub(crate) id: Id,
41 pub(crate) path: Arc<Vec<Id>>,
43}
44
45impl Name {
46 pub fn new(basename: Id, path: impl IntoIterator<Item = Id>) -> Self {
48 Self {
49 id: basename,
50 path: Arc::new(path.into_iter().collect()),
51 }
52 }
53
54 pub fn unqualified_name(id: Id) -> Self {
56 Self {
57 id,
58 path: Arc::new(vec![]),
59 }
60 }
61
62 pub fn parse_unqualified_name(s: &str) -> Result<Self, Vec<ParseError>> {
65 Ok(Self {
66 id: s.parse()?,
67 path: Arc::new(vec![]),
68 })
69 }
70
71 pub fn type_in_namespace(basename: Id, namespace: Name) -> Name {
74 let mut path = unwrap_or_clone(namespace.path);
75 path.push(namespace.id);
76 Name::new(basename, path)
77 }
78
79 pub fn basename(&self) -> &Id {
81 &self.id
82 }
83
84 pub fn namespace_components(&self) -> impl Iterator<Item = &Id> {
86 self.path.iter()
87 }
88
89 pub fn namespace(&self) -> String {
96 self.path.iter().join("::")
97 }
98}
99
100impl std::fmt::Display for Name {
101 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102 for elem in self.path.as_ref() {
103 write!(f, "{}::", elem)?;
104 }
105 write!(f, "{}", self.id)?;
106 Ok(())
107 }
108}
109
110impl std::str::FromStr for Name {
112 type Err = Vec<ParseError>;
113
114 fn from_str(s: &str) -> Result<Self, Vec<ParseError>> {
115 crate::parser::parse_name(s)
116 }
117}
118
119impl FromNormalizedStr for Name {
120 fn describe_self() -> &'static str {
121 "Name"
122 }
123}
124
125#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
130#[serde(transparent)]
131pub struct SlotId(ValidSlotId);
132
133impl SlotId {
134 pub fn principal() -> Self {
136 Self(ValidSlotId::Principal)
137 }
138
139 pub fn resource() -> Self {
141 Self(ValidSlotId::Resource)
142 }
143
144 pub fn is_principal(&self) -> bool {
146 matches!(self, Self(ValidSlotId::Principal))
147 }
148
149 pub fn is_resource(&self) -> bool {
151 matches!(self, Self(ValidSlotId::Resource))
152 }
153}
154
155impl From<PrincipalOrResource> for SlotId {
156 fn from(v: PrincipalOrResource) -> Self {
157 match v {
158 PrincipalOrResource::Principal => SlotId::principal(),
159 PrincipalOrResource::Resource => SlotId::resource(),
160 }
161 }
162}
163
164impl std::fmt::Display for SlotId {
165 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166 write!(f, "{}", self.0)
167 }
168}
169
170#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
172enum ValidSlotId {
173 #[serde(rename = "?principal")]
174 Principal,
175 #[serde(rename = "?resource")]
176 Resource,
177}
178
179impl std::fmt::Display for ValidSlotId {
180 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181 let s = match self {
182 ValidSlotId::Principal => "principal",
183 ValidSlotId::Resource => "resource",
184 };
185 write!(f, "?{s}")
186 }
187}
188
189#[cfg(test)]
190mod vars_test {
191 use super::*;
192 #[test]
194 fn vars_correct() {
195 SlotId::principal();
196 SlotId::resource();
197 }
198
199 #[test]
200 fn display() {
201 assert_eq!(format!("{}", SlotId::principal()), "?principal")
202 }
203}
204
205#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Hash, PartialOrd, Ord)]
210pub struct Id(SmolStr);
211
212impl Id {
213 pub(crate) fn new_unchecked(s: impl Into<SmolStr>) -> Id {
227 Id(s.into())
228 }
229
230 pub fn to_smolstr(self) -> SmolStr {
232 self.0
233 }
234}
235
236impl AsRef<str> for Id {
237 fn as_ref(&self) -> &str {
238 &self.0
239 }
240}
241
242impl std::fmt::Display for Id {
243 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
244 write!(f, "{}", &self.0)
245 }
246}
247
248impl std::str::FromStr for Id {
250 type Err = Vec<ParseError>;
251
252 fn from_str(s: &str) -> Result<Self, Vec<ParseError>> {
253 crate::parser::parse_ident(s)
254 }
255}
256
257impl FromNormalizedStr for Id {
258 fn describe_self() -> &'static str {
259 "Id"
260 }
261}
262
263#[cfg(feature = "arbitrary")]
264impl<'a> arbitrary::Arbitrary<'a> for Id {
265 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
266 let construct_list = |s: &str| s.chars().collect::<Vec<char>>();
272 let list_concat = |s1: &[char], s2: &[char]| [s1, s2].concat();
273 let head_letters = construct_list("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_");
275 let tail_letters = list_concat(&construct_list("0123456789"), &head_letters);
277 let remaining_length = u.int_in_range(0..=16)?;
279 let mut cs = vec![*u.choose(&head_letters)?];
280 cs.extend(
281 (0..remaining_length)
282 .map(|_| u.choose(&tail_letters))
283 .collect::<Result<Vec<&char>, _>>()?,
284 );
285 let mut s: String = cs.into_iter().collect();
286 if crate::parser::parse_ident(&s).is_err() {
289 s.push('_');
290 }
291 Ok(Self::new_unchecked(s))
292 }
293
294 fn size_hint(depth: usize) -> (usize, Option<usize>) {
295 arbitrary::size_hint::and_all(&[
296 <usize as arbitrary::Arbitrary>::size_hint(depth),
298 <Vec<u8> as arbitrary::Arbitrary>::size_hint(depth),
301 ])
302 }
303}
304
305#[cfg(test)]
306mod test {
307
308 use super::*;
309
310 #[test]
311 fn normalized_id() {
312 Id::from_normalized_str("foo").expect("should be OK");
313 Id::from_normalized_str("foo::bar").expect_err("shouldn't be OK");
314 Id::from_normalized_str(r#"foo::"bar""#).expect_err("shouldn't be OK");
315 Id::from_normalized_str(" foo").expect_err("shouldn't be OK");
316 Id::from_normalized_str("foo ").expect_err("shouldn't be OK");
317 Id::from_normalized_str("foo\n").expect_err("shouldn't be OK");
318 Id::from_normalized_str("foo//comment").expect_err("shouldn't be OK");
319 }
320
321 #[test]
322 fn normalized_name() {
323 Name::from_normalized_str("foo").expect("should be OK");
324 Name::from_normalized_str("foo::bar").expect("should be OK");
325 Name::from_normalized_str(r#"foo::"bar""#).expect_err("shouldn't be OK");
326 Name::from_normalized_str(" foo").expect_err("shouldn't be OK");
327 Name::from_normalized_str("foo ").expect_err("shouldn't be OK");
328 Name::from_normalized_str("foo\n").expect_err("shouldn't be OK");
329 Name::from_normalized_str("foo//comment").expect_err("shouldn't be OK");
330 }
331}