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