miden_assembly_syntax/ast/path/
path.rs1use alloc::{
2 borrow::{Borrow, Cow, ToOwned},
3 string::{String, ToString},
4};
5use core::fmt;
6
7use super::{Iter, PathBuf, PathComponent, PathError, StartsWith};
8use crate::ast::Ident;
9
10#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
12#[repr(transparent)]
13pub struct Path {
14 inner: str,
16}
17
18impl fmt::Debug for Path {
19 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20 fmt::Debug::fmt(&self.inner, f)
21 }
22}
23
24#[cfg(feature = "serde")]
25impl serde::Serialize for Path {
26 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
27 where
28 S: serde::Serializer,
29 {
30 serializer.serialize_str(&self.inner)
31 }
32}
33
34#[cfg(feature = "serde")]
35impl<'de> serde::Deserialize<'de> for &'de Path {
36 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
37 where
38 D: serde::Deserializer<'de>,
39 {
40 let inner = <&'de str as serde::Deserialize<'de>>::deserialize(deserializer)?;
41
42 Ok(Path::new(inner))
43 }
44}
45
46impl ToOwned for Path {
47 type Owned = PathBuf;
48 #[inline]
49 fn to_owned(&self) -> PathBuf {
50 self.to_path_buf()
51 }
52 #[inline]
53 fn clone_into(&self, target: &mut Self::Owned) {
54 self.inner.clone_into(&mut target.inner)
55 }
56}
57
58impl Borrow<Path> for PathBuf {
59 fn borrow(&self) -> &Path {
60 Path::new(self)
61 }
62}
63
64impl AsRef<str> for Path {
65 #[inline]
66 fn as_ref(&self) -> &str {
67 &self.inner
68 }
69}
70
71impl AsRef<Path> for str {
72 #[inline(always)]
73 fn as_ref(&self) -> &Path {
74 unsafe { &*(self as *const str as *const Path) }
75 }
76}
77
78impl AsRef<Path> for Ident {
79 #[inline(always)]
80 fn as_ref(&self) -> &Path {
81 self.as_str().as_ref()
82 }
83}
84
85impl AsRef<Path> for crate::ast::ProcedureName {
86 #[inline(always)]
87 fn as_ref(&self) -> &Path {
88 let ident: &Ident = self.as_ref();
89 ident.as_str().as_ref()
90 }
91}
92
93impl AsRef<Path> for crate::ast::QualifiedProcedureName {
94 #[inline(always)]
95 fn as_ref(&self) -> &Path {
96 self.as_path()
97 }
98}
99
100impl AsRef<Path> for Path {
101 #[inline(always)]
102 fn as_ref(&self) -> &Path {
103 self
104 }
105}
106
107impl From<&Path> for alloc::sync::Arc<Path> {
108 fn from(path: &Path) -> Self {
109 path.to_path_buf().into()
110 }
111}
112
113impl Path {
115 pub const MAX_COMPONENT_LENGTH: usize = u8::MAX as usize;
117
118 pub const EMPTY: &Path = unsafe { &*("" as *const str as *const Path) };
120
121 pub const KERNEL_PATH: &str = "$kernel";
123 pub const ABSOLUTE_KERNEL_PATH: &str = "::$kernel";
124 pub const KERNEL: &Path =
125 unsafe { &*(Self::ABSOLUTE_KERNEL_PATH as *const str as *const Path) };
126
127 pub const EXEC_PATH: &str = "$exec";
129 pub const ABSOLUTE_EXEC_PATH: &str = "::$exec";
130 pub const EXEC: &Path = unsafe { &*(Self::ABSOLUTE_EXEC_PATH as *const str as *const Path) };
131
132 pub fn new<S: AsRef<str> + ?Sized>(path: &S) -> &Path {
133 unsafe { &*(path.as_ref() as *const str as *const Path) }
135 }
136
137 pub fn from_mut(path: &mut str) -> &mut Path {
138 unsafe { &mut *(path as *mut str as *mut Path) }
140 }
141
142 pub fn validate(path: &str) -> Result<&Path, PathError> {
144 match path {
145 "" => return Err(PathError::Empty),
146 "::" => return Err(PathError::EmptyComponent),
147 _ => (),
148 }
149
150 for result in Iter::new(path) {
151 result?;
152 }
153
154 Ok(Path::new(path))
155 }
156
157 pub const fn kernel_path() -> &'static Path {
159 Path::KERNEL
160 }
161
162 pub const fn exec_path() -> &'static Path {
164 Path::EXEC
165 }
166
167 #[inline]
168 pub const fn as_str(&self) -> &str {
169 &self.inner
170 }
171
172 #[inline]
173 pub fn as_mut_str(&mut self) -> &mut str {
174 &mut self.inner
175 }
176
177 pub fn as_ident(&self) -> Option<Ident> {
182 let mut components = self.components().filter_map(|c| c.ok());
183 match components.next()? {
184 component @ PathComponent::Normal(_) => {
185 if components.next().is_none() {
186 component.to_ident()
187 } else {
188 None
189 }
190 },
191 PathComponent::Root => None,
192 }
193 }
194
195 pub fn to_path_buf(&self) -> PathBuf {
197 PathBuf { inner: self.inner.to_string() }
198 }
199}
200
201impl Path {
203 pub fn is_empty(&self) -> bool {
205 self.inner.is_empty() || &self.inner == "::"
206 }
207
208 pub fn len(&self) -> usize {
210 self.components().count()
211 }
212
213 pub fn char_len(&self) -> usize {
215 self.inner.chars().count()
216 }
217
218 #[inline]
220 pub fn byte_len(&self) -> usize {
221 self.inner.len()
222 }
223
224 pub fn is_absolute(&self) -> bool {
226 matches!(
227 self.components().next(),
228 Some(Ok(PathComponent::Root))
229 | Some(Ok(PathComponent::Normal(Self::KERNEL_PATH | Self::EXEC_PATH))),
230 )
231 }
232
233 pub fn to_absolute(&self) -> Cow<'_, Path> {
237 if self.is_absolute() {
238 Cow::Borrowed(self)
239 } else {
240 let mut inner = String::with_capacity(self.byte_len() + 2);
241 inner.push_str("::");
242 inner.push_str(&self.inner);
243 Cow::Owned(PathBuf { inner })
244 }
245 }
246
247 pub fn to_relative(&self) -> &Path {
249 match self.inner.strip_prefix("::") {
250 Some(rest) => Path::new(rest),
251 None => self,
252 }
253 }
254
255 pub fn parent(&self) -> Option<&Path> {
261 let mut components = self.components();
262 match components.next_back()?.ok()? {
263 PathComponent::Root => None,
264 _ => Some(components.as_path()),
265 }
266 }
267
268 pub fn components(&self) -> Iter<'_> {
270 Iter::new(&self.inner)
271 }
272
273 pub fn first(&self) -> Option<&str> {
277 self.split_first().map(|(first, _)| first)
278 }
279
280 pub fn last(&self) -> Option<&str> {
284 self.split_last().map(|(last, _)| last)
285 }
286
287 pub fn split_first(&self) -> Option<(&str, &Path)> {
292 let mut components = self.components();
293 match components.next()?.ok()? {
294 PathComponent::Root => {
295 let first = components.next().and_then(|c| c.ok()).map(|c| c.as_str())?;
296 Some((first, components.as_path()))
297 },
298 PathComponent::Normal(first) => Some((first, components.as_path())),
299 }
300 }
301
302 pub fn split_last(&self) -> Option<(&str, &Path)> {
307 let mut components = self.components();
308 match components.next_back()?.ok()? {
309 PathComponent::Root => None,
310 PathComponent::Normal(last) => Some((last, components.as_path())),
311 }
312 }
313
314 pub fn is_kernel_path(&self) -> bool {
316 match self.inner.strip_prefix("::") {
317 Some(Self::KERNEL_PATH) => true,
318 Some(_) => false,
319 None => &self.inner == Self::KERNEL_PATH,
320 }
321 }
322
323 pub fn is_in_kernel(&self) -> bool {
325 if self.is_kernel_path() {
326 return true;
327 }
328
329 match self.split_last() {
330 Some((_, prefix)) => Self::KERNEL == prefix,
331 None => false,
332 }
333 }
334
335 pub fn is_exec_path(&self) -> bool {
337 match self.inner.strip_prefix("::") {
338 Some(Self::EXEC_PATH) => true,
339 Some(_) => false,
340 None => &self.inner == Self::EXEC_PATH,
341 }
342 }
343
344 #[inline]
346 pub fn starts_with<Prefix>(&self, prefix: &Prefix) -> bool
347 where
348 Prefix: ?Sized,
349 Self: StartsWith<Prefix>,
350 {
351 <Self as StartsWith<Prefix>>::starts_with(self, prefix)
352 }
353
354 #[inline]
356 pub fn starts_with_exactly<Prefix>(&self, prefix: &Prefix) -> bool
357 where
358 Prefix: ?Sized,
359 Self: StartsWith<Prefix>,
360 {
361 <Self as StartsWith<Prefix>>::starts_with_exactly(self, prefix)
362 }
363
364 pub fn join(&self, path: impl AsRef<Path>) -> PathBuf {
370 let path = path.as_ref();
371
372 if path.is_empty() {
373 return self.to_path_buf();
374 }
375
376 if self.is_empty() || path.is_absolute() {
377 return path.to_path_buf();
378 }
379
380 let mut buf = self.to_path_buf();
381 buf.push(path);
382
383 buf
384 }
385}
386
387impl StartsWith<str> for Path {
388 fn starts_with(&self, prefix: &str) -> bool {
389 if prefix.is_empty() {
390 return true;
391 }
392 if prefix.starts_with("::") {
393 self.inner.starts_with(prefix)
394 } else {
395 match self.inner.strip_prefix("::") {
396 Some(rest) => rest.starts_with(prefix),
397 None => self.inner.starts_with(prefix),
398 }
399 }
400 }
401
402 #[inline]
403 fn starts_with_exactly(&self, prefix: &str) -> bool {
404 self.inner.starts_with(prefix)
405 }
406}
407
408impl StartsWith<Path> for Path {
409 fn starts_with(&self, prefix: &Path) -> bool {
410 <Self as StartsWith<str>>::starts_with(self, prefix.as_str())
411 }
412
413 #[inline]
414 fn starts_with_exactly(&self, prefix: &Path) -> bool {
415 <Self as StartsWith<str>>::starts_with_exactly(self, prefix.as_str())
416 }
417}
418
419impl PartialEq<str> for Path {
420 fn eq(&self, other: &str) -> bool {
421 &self.inner == other
422 }
423}
424
425impl PartialEq<PathBuf> for Path {
426 fn eq(&self, other: &PathBuf) -> bool {
427 &self.inner == other.inner.as_str()
428 }
429}
430
431impl PartialEq<&PathBuf> for Path {
432 fn eq(&self, other: &&PathBuf) -> bool {
433 &self.inner == other.inner.as_str()
434 }
435}
436
437impl PartialEq<Path> for PathBuf {
438 fn eq(&self, other: &Path) -> bool {
439 self.inner.as_str() == &other.inner
440 }
441}
442
443impl PartialEq<&Path> for Path {
444 fn eq(&self, other: &&Path) -> bool {
445 self.inner == other.inner
446 }
447}
448
449impl PartialEq<alloc::boxed::Box<Path>> for Path {
450 fn eq(&self, other: &alloc::boxed::Box<Path>) -> bool {
451 self.inner == other.inner
452 }
453}
454
455impl PartialEq<alloc::rc::Rc<Path>> for Path {
456 fn eq(&self, other: &alloc::rc::Rc<Path>) -> bool {
457 self.inner == other.inner
458 }
459}
460
461impl PartialEq<alloc::sync::Arc<Path>> for Path {
462 fn eq(&self, other: &alloc::sync::Arc<Path>) -> bool {
463 self.inner == other.inner
464 }
465}
466
467impl PartialEq<alloc::borrow::Cow<'_, Path>> for Path {
468 fn eq(&self, other: &alloc::borrow::Cow<'_, Path>) -> bool {
469 self.inner == other.as_ref().inner
470 }
471}
472
473impl fmt::Display for Path {
474 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
475 f.write_str(&self.inner)
476 }
477}