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;
25
26#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Hash, PartialOrd, Ord)]
30#[cfg_attr(fuzzing, derive(arbitrary::Arbitrary))]
31pub struct Name {
32 pub(crate) id: Id,
34 pub(crate) path: Arc<Vec<Id>>,
36}
37
38impl Name {
39 pub fn new(id: Id, path: impl IntoIterator<Item = Id>) -> Self {
41 Self {
42 id,
43 path: Arc::new(path.into_iter().collect()),
44 }
45 }
46
47 pub fn unqualified_name(id: Id) -> Self {
49 Self {
50 id,
51 path: Arc::new(vec![]),
52 }
53 }
54
55 pub fn parse_unqualified_name(s: &str) -> Result<Self, Vec<ParseError>> {
58 Ok(Self {
59 id: s.parse()?,
60 path: Arc::new(vec![]),
61 })
62 }
63
64 pub fn basename(&self) -> &Id {
66 &self.id
67 }
68
69 pub fn namespace_components(&self) -> impl Iterator<Item = &Id> {
71 self.path.iter()
72 }
73
74 pub fn namespace(&self) -> String {
81 self.path.iter().join("::")
82 }
83}
84
85impl std::fmt::Display for Name {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 for elem in self.path.as_ref() {
88 write!(f, "{}::", elem)?;
89 }
90 write!(f, "{}", self.id)?;
91 Ok(())
92 }
93}
94
95impl std::str::FromStr for Name {
97 type Err = Vec<ParseError>;
98
99 fn from_str(s: &str) -> Result<Self, Vec<ParseError>> {
100 crate::parser::parse_name(s)
101 }
102}
103
104#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
109#[serde(transparent)]
110pub struct SlotId(ValidSlotId);
111
112impl SlotId {
113 pub fn principal() -> Self {
115 Self(ValidSlotId::Principal)
116 }
117
118 pub fn resource() -> Self {
120 Self(ValidSlotId::Resource)
121 }
122
123 pub fn is_principal(&self) -> bool {
125 matches!(self, Self(ValidSlotId::Principal))
126 }
127
128 pub fn is_resource(&self) -> bool {
130 matches!(self, Self(ValidSlotId::Resource))
131 }
132}
133
134impl From<PrincipalOrResource> for SlotId {
135 fn from(v: PrincipalOrResource) -> Self {
136 match v {
137 PrincipalOrResource::Principal => SlotId::principal(),
138 PrincipalOrResource::Resource => SlotId::resource(),
139 }
140 }
141}
142
143impl std::fmt::Display for SlotId {
144 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 write!(f, "{}", self.0)
146 }
147}
148
149#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
151enum ValidSlotId {
152 #[serde(rename = "?principal")]
153 Principal,
154 #[serde(rename = "?resource")]
155 Resource,
156}
157
158impl std::fmt::Display for ValidSlotId {
159 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
160 let s = match self {
161 ValidSlotId::Principal => "principal",
162 ValidSlotId::Resource => "resource",
163 };
164 write!(f, "?{s}")
165 }
166}
167
168#[cfg(test)]
169mod test {
170 use super::*;
171 #[test]
173 fn vars_correct() {
174 SlotId::principal();
175 SlotId::resource();
176 }
177
178 #[test]
179 fn display() {
180 assert_eq!(format!("{}", SlotId::principal()), "?principal")
181 }
182}
183
184#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Hash, PartialOrd, Ord)]
189pub struct Id(SmolStr);
190
191impl Id {
192 pub(crate) fn new_unchecked(s: impl Into<SmolStr>) -> Id {
206 Id(s.into())
207 }
208
209 pub fn to_smolstr(self) -> SmolStr {
211 self.0
212 }
213}
214
215impl AsRef<str> for Id {
216 fn as_ref(&self) -> &str {
217 &self.0
218 }
219}
220
221impl std::fmt::Display for Id {
222 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
223 write!(f, "{}", &self.0)
224 }
225}
226
227impl std::str::FromStr for Id {
229 type Err = Vec<ParseError>;
230
231 fn from_str(s: &str) -> Result<Self, Vec<ParseError>> {
232 crate::parser::parse_ident(s)
233 }
234}
235
236#[cfg(fuzzing)]
237impl<'a> arbitrary::Arbitrary<'a> for Id {
238 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
239 let construct_list = |s: &str| s.chars().collect::<Vec<char>>();
245 let list_concat = |s1: &[char], s2: &[char]| [s1, s2].concat();
246 let head_letters = construct_list("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_");
248 let tail_letters = list_concat(&construct_list("0123456789"), &head_letters);
250 let remaining_length = u.int_in_range(0..=16)?;
252 let mut cs = vec![*u.choose(&head_letters)?];
253 cs.extend(
254 (0..remaining_length)
255 .map(|_| u.choose(&tail_letters))
256 .collect::<Result<Vec<&char>, _>>()?,
257 );
258 let mut s: String = cs.into_iter().collect();
259 if crate::parser::parse_ident(&s).is_err() {
262 s.push('_');
263 }
264 Ok(Self::new_unchecked(s))
265 }
266
267 fn size_hint(depth: usize) -> (usize, Option<usize>) {
268 arbitrary::size_hint::and_all(&[
269 <usize as arbitrary::Arbitrary>::size_hint(depth),
271 <Vec<u8> as arbitrary::Arbitrary>::size_hint(depth),
274 ])
275 }
276}