1use super::id::Id;
18use itertools::Itertools;
19use serde::{Deserialize, Deserializer, Serialize, Serializer};
20use smol_str::ToSmolStr;
21use std::sync::Arc;
22
23use crate::parser::err::ParseErrors;
24use crate::parser::Loc;
25use crate::FromNormalizedStr;
26
27use super::PrincipalOrResource;
28
29#[derive(Debug, Clone)]
33pub struct Name {
34 pub(crate) id: Id,
36 pub(crate) path: Arc<Vec<Id>>,
38 pub(crate) loc: Option<Loc>,
40}
41
42impl PartialEq for Name {
44 fn eq(&self, other: &Self) -> bool {
45 self.id == other.id && self.path == other.path
46 }
47}
48impl Eq for Name {}
49
50impl std::hash::Hash for Name {
51 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
52 self.id.hash(state);
55 self.path.hash(state);
56 }
57}
58
59impl PartialOrd for Name {
60 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
61 Some(self.cmp(other))
62 }
63}
64impl Ord for Name {
65 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
66 self.id.cmp(&other.id).then(self.path.cmp(&other.path))
67 }
68}
69
70impl From<Id> for Name {
72 fn from(value: Id) -> Self {
73 Self::unqualified_name(value)
74 }
75}
76
77impl TryFrom<Name> for Id {
81 type Error = ();
82 fn try_from(value: Name) -> Result<Self, Self::Error> {
83 if value.is_unqualified() {
84 Ok(value.id)
85 } else {
86 Err(())
87 }
88 }
89}
90
91impl Name {
92 pub fn new(basename: Id, path: impl IntoIterator<Item = Id>, loc: Option<Loc>) -> Self {
94 Self {
95 id: basename,
96 path: Arc::new(path.into_iter().collect()),
97 loc,
98 }
99 }
100
101 pub fn unqualified_name(id: Id) -> Self {
103 Self {
104 id,
105 path: Arc::new(vec![]),
106 loc: None,
107 }
108 }
109
110 pub fn parse_unqualified_name(s: &str) -> Result<Self, ParseErrors> {
113 Ok(Self {
114 id: s.parse()?,
115 path: Arc::new(vec![]),
116 loc: None,
117 })
118 }
119
120 pub fn type_in_namespace(basename: Id, namespace: Name, loc: Option<Loc>) -> Name {
123 let mut path = Arc::unwrap_or_clone(namespace.path);
124 path.push(namespace.id);
125 Name::new(basename, path, loc)
126 }
127
128 pub fn loc(&self) -> Option<&Loc> {
130 self.loc.as_ref()
131 }
132
133 pub fn basename(&self) -> &Id {
135 &self.id
136 }
137
138 pub fn namespace_components(&self) -> impl Iterator<Item = &Id> {
140 self.path.iter()
141 }
142
143 pub fn namespace(&self) -> String {
150 self.path.iter().join("::")
151 }
152
153 pub fn prefix_namespace_if_unqualified(&self, namespace: Option<Name>) -> Name {
160 if self.is_unqualified() {
161 match namespace {
163 Some(namespace) => Self::new(
164 self.basename().clone(),
165 namespace
166 .namespace_components()
167 .chain(std::iter::once(namespace.basename()))
168 .cloned(),
169 self.loc().cloned(),
170 ),
171 None => self.clone(),
172 }
173 } else {
174 self.clone()
175 }
176 }
177
178 pub fn is_unqualified(&self) -> bool {
180 self.path.is_empty()
181 }
182}
183
184impl std::fmt::Display for Name {
185 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
186 for elem in self.path.as_ref() {
187 write!(f, "{}::", elem)?;
188 }
189 write!(f, "{}", self.id)?;
190 Ok(())
191 }
192}
193
194impl Serialize for Name {
197 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
198 where
199 S: Serializer,
200 {
201 self.to_smolstr().serialize(serializer)
202 }
203}
204
205impl std::str::FromStr for Name {
207 type Err = ParseErrors;
208
209 fn from_str(s: &str) -> Result<Self, Self::Err> {
210 crate::parser::parse_name(s)
211 }
212}
213
214impl FromNormalizedStr for Name {
215 fn describe_self() -> &'static str {
216 "Name"
217 }
218}
219
220struct NameVisitor;
221
222impl<'de> serde::de::Visitor<'de> for NameVisitor {
223 type Value = Name;
224
225 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
226 formatter.write_str("a name consisting of an optional namespace and id")
227 }
228
229 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
230 where
231 E: serde::de::Error,
232 {
233 Name::from_normalized_str(value)
234 .map_err(|err| serde::de::Error::custom(format!("invalid name `{value}`: {err}")))
235 }
236}
237
238impl<'de> Deserialize<'de> for Name {
241 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
242 where
243 D: Deserializer<'de>,
244 {
245 deserializer.deserialize_str(NameVisitor)
246 }
247}
248
249#[cfg(feature = "arbitrary")]
250impl<'a> arbitrary::Arbitrary<'a> for Name {
251 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
252 Ok(Self {
253 id: u.arbitrary()?,
254 path: u.arbitrary()?,
255 loc: None,
256 })
257 }
258}
259
260#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
265#[serde(transparent)]
266pub struct SlotId(pub(crate) ValidSlotId);
267
268impl SlotId {
269 pub fn principal() -> Self {
271 Self(ValidSlotId::Principal)
272 }
273
274 pub fn resource() -> Self {
276 Self(ValidSlotId::Resource)
277 }
278
279 pub fn is_principal(&self) -> bool {
281 matches!(self, Self(ValidSlotId::Principal))
282 }
283
284 pub fn is_resource(&self) -> bool {
286 matches!(self, Self(ValidSlotId::Resource))
287 }
288}
289
290impl From<PrincipalOrResource> for SlotId {
291 fn from(v: PrincipalOrResource) -> Self {
292 match v {
293 PrincipalOrResource::Principal => SlotId::principal(),
294 PrincipalOrResource::Resource => SlotId::resource(),
295 }
296 }
297}
298
299impl std::fmt::Display for SlotId {
300 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
301 write!(f, "{}", self.0)
302 }
303}
304
305#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
307pub(crate) enum ValidSlotId {
308 #[serde(rename = "?principal")]
309 Principal,
310 #[serde(rename = "?resource")]
311 Resource,
312}
313
314impl std::fmt::Display for ValidSlotId {
315 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
316 let s = match self {
317 ValidSlotId::Principal => "principal",
318 ValidSlotId::Resource => "resource",
319 };
320 write!(f, "?{s}")
321 }
322}
323
324#[derive(Debug, Clone)]
326pub struct Slot {
327 pub id: SlotId,
329 pub loc: Option<Loc>,
331}
332
333impl PartialEq for Slot {
336 fn eq(&self, other: &Self) -> bool {
337 self.id == other.id
338 }
339}
340impl Eq for Slot {}
341
342impl std::hash::Hash for Slot {
343 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
344 self.id.hash(state);
347 }
348}
349
350#[cfg(test)]
351mod vars_test {
352 use super::*;
353 #[test]
355 fn vars_correct() {
356 SlotId::principal();
357 SlotId::resource();
358 }
359
360 #[test]
361 fn display() {
362 assert_eq!(format!("{}", SlotId::principal()), "?principal")
363 }
364}
365
366#[cfg(test)]
367mod test {
368 use super::*;
369
370 #[test]
371 fn normalized_name() {
372 Name::from_normalized_str("foo").expect("should be OK");
373 Name::from_normalized_str("foo::bar").expect("should be OK");
374 Name::from_normalized_str(r#"foo::"bar""#).expect_err("shouldn't be OK");
375 Name::from_normalized_str(" foo").expect_err("shouldn't be OK");
376 Name::from_normalized_str("foo ").expect_err("shouldn't be OK");
377 Name::from_normalized_str("foo\n").expect_err("shouldn't be OK");
378 Name::from_normalized_str("foo//comment").expect_err("shouldn't be OK");
379 }
380
381 #[test]
382 fn prefix_namespace() {
383 assert_eq!(
384 "foo::bar::baz",
385 Name::from_normalized_str("baz")
386 .unwrap()
387 .prefix_namespace_if_unqualified(Some("foo::bar".parse().unwrap()))
388 .to_smolstr()
389 );
390 assert_eq!(
391 "C::D",
392 Name::from_normalized_str("C::D")
393 .unwrap()
394 .prefix_namespace_if_unqualified(Some("A::B".parse().unwrap()))
395 .to_smolstr()
396 );
397 assert_eq!(
398 "A::B::C::D",
399 Name::from_normalized_str("D")
400 .unwrap()
401 .prefix_namespace_if_unqualified(Some("A::B::C".parse().unwrap()))
402 .to_smolstr()
403 );
404 assert_eq!(
405 "B::C::D",
406 Name::from_normalized_str("B::C::D")
407 .unwrap()
408 .prefix_namespace_if_unqualified(Some("A".parse().unwrap()))
409 .to_smolstr()
410 );
411 }
412}