1use crate::BoxSlice;
2use bumpalo::Bump;
3use solar_data_structures::{BumpExt, smallvec::SmallVec};
4use solar_interface::{Ident, Span, Symbol};
5use std::{cmp::Ordering, fmt};
6
7#[derive(Debug)]
9pub struct AstPath<'ast>(BoxSlice<'ast, Ident>);
10
11impl std::ops::Deref for AstPath<'_> {
12 type Target = PathSlice;
13
14 #[inline]
15 fn deref(&self) -> &Self::Target {
16 unsafe { PathSlice::from_slice_unchecked(self.0) }
17 }
18}
19
20impl std::ops::DerefMut for AstPath<'_> {
21 #[inline]
22 fn deref_mut(&mut self) -> &mut Self::Target {
23 unsafe { PathSlice::from_mut_slice_unchecked(self.0) }
24 }
25}
26
27impl PartialEq for AstPath<'_> {
28 #[inline]
29 fn eq(&self, other: &Self) -> bool {
30 self.as_slice() == other.as_slice()
31 }
32}
33
34impl Eq for AstPath<'_> {}
35
36impl PartialOrd for AstPath<'_> {
37 #[inline]
38 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
39 Some(self.cmp(other))
40 }
41}
42
43impl Ord for AstPath<'_> {
44 #[inline]
45 fn cmp(&self, other: &Self) -> Ordering {
46 self.as_slice().cmp(other.as_slice())
47 }
48}
49
50impl std::hash::Hash for AstPath<'_> {
51 #[inline]
52 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
53 self.as_slice().hash(state)
54 }
55}
56
57impl<'ast> AstPath<'ast> {
58 #[inline]
60 pub fn new_in(arena: &'ast Bump, segments: &[Ident]) -> Self {
61 Self(arena.alloc_thin_slice_copy((), segments))
62 }
63
64 #[inline]
66 pub fn as_slice(&self) -> &PathSlice {
67 self
68 }
69
70 #[inline]
72 pub fn as_mut_slice(&mut self) -> &mut PathSlice {
73 self
74 }
75}
76
77#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
81#[repr(transparent)]
82pub struct PathSlice([Ident]);
83
84impl ToOwned for PathSlice {
85 type Owned = Path;
86
87 #[inline]
88 fn to_owned(&self) -> Self::Owned {
89 Path::new(&self.0)
90 }
91}
92
93impl fmt::Debug for PathSlice {
94 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95 fmt::Display::fmt(self, f)
96 }
97}
98
99impl fmt::Display for PathSlice {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 for (i, ident) in self.segments().iter().enumerate() {
102 if i != 0 {
103 f.write_str(".")?;
104 }
105 write!(f, "{ident}")?;
106 }
107 Ok(())
108 }
109}
110
111impl PartialEq<Ident> for PathSlice {
112 fn eq(&self, other: &Ident) -> bool {
113 match self.get_ident() {
114 Some(ident) => ident == other,
115 None => false,
116 }
117 }
118}
119
120impl PartialEq<Symbol> for PathSlice {
121 fn eq(&self, other: &Symbol) -> bool {
122 match self.get_ident() {
123 Some(ident) => ident.name == *other,
124 None => false,
125 }
126 }
127}
128
129impl PathSlice {
130 #[inline]
132 pub fn from_ref(segment: &Ident) -> &Self {
133 unsafe { Self::from_slice_unchecked(std::slice::from_ref(segment)) }
134 }
135
136 #[inline]
138 pub fn from_mut(segment: &mut Ident) -> &mut Self {
139 unsafe { Self::from_mut_slice_unchecked(std::slice::from_mut(segment)) }
140 }
141
142 #[inline]
148 pub fn from_slice(segments: &[Ident]) -> &Self {
149 if segments.is_empty() {
150 panic_empty_path();
151 }
152 unsafe { Self::from_slice_unchecked(segments) }
154 }
155
156 #[inline]
162 pub unsafe fn from_slice_unchecked(segments: &[Ident]) -> &Self {
163 debug_assert!(!segments.is_empty());
164 unsafe { &*(segments as *const _ as *const Self) }
166 }
167
168 #[inline]
174 pub fn from_mut_slice(segments: &mut [Ident]) -> &mut Self {
175 assert!(!segments.is_empty());
176 unsafe { Self::from_mut_slice_unchecked(segments) }
178 }
179
180 #[inline]
186 pub unsafe fn from_mut_slice_unchecked(segments: &mut [Ident]) -> &mut Self {
187 unsafe { &mut *(segments as *mut _ as *mut Self) }
189 }
190
191 #[inline]
193 #[cfg_attr(debug_assertions, track_caller)]
194 pub fn span(&self) -> Span {
195 match self.segments() {
196 [] => panic_empty_path(),
197 [ident] => ident.span,
198 [first, .., last] => first.span.with_hi(last.span.hi()),
199 }
200 }
201
202 #[inline]
204 pub fn segments(&self) -> &[Ident] {
205 &self.0
206 }
207
208 #[inline]
210 pub fn segments_mut(&mut self) -> &mut [Ident] {
211 &mut self.0
212 }
213
214 #[inline]
216 pub fn get_ident(&self) -> Option<&Ident> {
217 match self.segments() {
218 [ident] => Some(ident),
219 _ => None,
220 }
221 }
222
223 #[inline]
225 pub fn get_ident_mut(&mut self) -> Option<&mut Ident> {
226 match self.segments_mut() {
227 [ident] => Some(ident),
228 _ => None,
229 }
230 }
231
232 #[inline]
234 #[cfg_attr(debug_assertions, track_caller)]
235 pub fn first(&self) -> &Ident {
236 self.segments().first().unwrap_or_else(|| panic_empty_path())
237 }
238
239 #[inline]
241 #[cfg_attr(debug_assertions, track_caller)]
242 pub fn first_mut(&mut self) -> &mut Ident {
243 self.segments_mut().first_mut().unwrap_or_else(|| panic_empty_path())
244 }
245
246 #[inline]
248 #[cfg_attr(debug_assertions, track_caller)]
249 pub fn last(&self) -> &Ident {
250 self.segments().last().unwrap_or_else(|| panic_empty_path())
251 }
252
253 #[inline]
255 #[cfg_attr(debug_assertions, track_caller)]
256 pub fn last_mut(&mut self) -> &mut Ident {
257 self.segments_mut().last_mut().unwrap_or_else(|| panic_empty_path())
258 }
259}
260
261#[inline(never)]
262#[cold]
263#[cfg_attr(debug_assertions, track_caller)]
264fn panic_empty_path() -> ! {
265 panic!("paths cannot be empty");
266}
267
268#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
272pub struct Path(SmallVec<[Ident; 1]>);
273
274impl fmt::Debug for Path {
275 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
276 fmt::Debug::fmt(self.as_slice(), f)
277 }
278}
279
280impl fmt::Display for Path {
281 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
282 fmt::Display::fmt(self.as_slice(), f)
283 }
284}
285
286impl PartialEq<Ident> for Path {
287 fn eq(&self, other: &Ident) -> bool {
288 PartialEq::eq(self.as_slice(), other)
289 }
290}
291
292impl PartialEq<Symbol> for Path {
293 fn eq(&self, other: &Symbol) -> bool {
294 PartialEq::eq(self.as_slice(), other)
295 }
296}
297
298impl FromIterator<Ident> for Path {
299 fn from_iter<T: IntoIterator<Item = Ident>>(iter: T) -> Self {
305 let mut iter = iter.into_iter();
306 let first = iter.next().expect("paths cannot be empty");
307 match iter.next() {
308 Some(second) => Self(SmallVec::from_iter([first, second].into_iter().chain(iter))),
309 None => Self::new_single(first),
310 }
311 }
312}
313
314impl std::ops::Deref for Path {
315 type Target = PathSlice;
316
317 #[inline]
318 fn deref(&self) -> &Self::Target {
319 self.as_slice()
320 }
321}
322
323impl std::ops::DerefMut for Path {
324 #[inline]
325 fn deref_mut(&mut self) -> &mut Self::Target {
326 self.as_mut_slice()
327 }
328}
329
330impl std::borrow::Borrow<PathSlice> for Path {
331 #[inline]
332 fn borrow(&self) -> &PathSlice {
333 self.as_slice()
334 }
335}
336
337impl Path {
338 #[inline]
344 pub fn new(segments: &[Ident]) -> Self {
345 assert!(!segments.is_empty());
346 Self(SmallVec::from_slice(segments))
347 }
348
349 #[inline]
355 pub fn from_vec(segments: Vec<Ident>) -> Self {
356 assert!(!segments.is_empty());
357 Self(SmallVec::from_vec(segments))
358 }
359
360 #[inline]
366 pub fn from_ast(ast: AstPath<'_>) -> Self {
367 Self::new(ast.segments())
368 }
369
370 #[inline]
372 pub fn new_single(ident: Ident) -> Self {
373 Self(SmallVec::from_buf_and_len([ident], 1))
374 }
375
376 #[inline]
378 pub fn as_slice(&self) -> &PathSlice {
379 unsafe { PathSlice::from_slice_unchecked(&self.0) }
380 }
381
382 #[inline]
384 pub fn as_mut_slice(&mut self) -> &mut PathSlice {
385 unsafe { PathSlice::from_mut_slice_unchecked(&mut self.0) }
386 }
387}