1use alloc::{string::ToString, sync::Arc};
2use core::{fmt, iter::FusedIterator};
3
4use super::{Path, PathError};
5use crate::{ast::Ident, debuginfo::Span};
6
7#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
12pub enum PathComponent<'a> {
13 Root,
15 Normal(&'a str),
17}
18
19impl<'a> PathComponent<'a> {
20 pub fn as_str(&self) -> &'a str {
26 match self {
27 Self::Root => "::",
28 Self::Normal(id) if id.starts_with('"') && id.ends_with('"') => &id[1..(id.len() - 1)],
29 Self::Normal(id) => id,
30 }
31 }
32
33 #[inline]
35 pub fn to_ident(&self) -> Option<Ident> {
36 if matches!(self, Self::Root) {
37 None
38 } else {
39 Some(Ident::from_raw_parts(Span::unknown(Arc::from(
40 self.as_str().to_string().into_boxed_str(),
41 ))))
42 }
43 }
44
45 pub fn char_len(&self) -> usize {
47 self.as_str().chars().count()
48 }
49
50 pub fn is_quoted(&self) -> bool {
52 matches!(self, Self::Normal(component) if component.starts_with('"') && component.ends_with('"'))
53 }
54
55 pub fn requires_quoting(&self) -> bool {
57 match self {
58 Self::Root => false,
59 Self::Normal(Path::KERNEL_PATH | Path::EXEC_PATH) => false,
60 Self::Normal(component)
61 if component.contains("::") || Ident::requires_quoting(component) =>
62 {
63 true
64 },
65 Self::Normal(_) => false,
66 }
67 }
68}
69
70impl PartialEq<str> for PathComponent<'_> {
71 fn eq(&self, other: &str) -> bool {
72 self.as_str().eq(other)
73 }
74}
75
76impl AsRef<str> for PathComponent<'_> {
77 #[inline(always)]
78 fn as_ref(&self) -> &str {
79 self.as_str()
80 }
81}
82
83impl fmt::Display for PathComponent<'_> {
84 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
85 f.write_str(self.as_str())
86 }
87}
88
89#[derive(Debug)]
111pub struct Iter<'a> {
112 components: Components<'a>,
113}
114
115impl<'a> Iter<'a> {
116 pub fn new(path: &'a str) -> Self {
117 Self {
118 components: Components {
119 path,
120 original: path,
121 front_pos: 0,
122 front: State::Start,
123 back_pos: path.len(),
124 back: State::Body,
125 },
126 }
127 }
128
129 #[inline]
130 pub fn as_path(&self) -> &'a Path {
131 Path::new(self.components.path)
132 }
133}
134
135impl FusedIterator for Iter<'_> {}
136
137impl<'a> Iterator for Iter<'a> {
138 type Item = Result<PathComponent<'a>, PathError>;
139
140 fn next(&mut self) -> Option<Self::Item> {
141 match self.components.next() {
142 Some(Ok(component @ PathComponent::Normal(_)))
143 if component.as_str().chars().count() > Path::MAX_COMPONENT_LENGTH =>
144 {
145 Some(Err(PathError::InvalidComponent(crate::ast::IdentError::InvalidLength {
146 max: Path::MAX_COMPONENT_LENGTH,
147 })))
148 },
149 next => next,
150 }
151 }
152}
153
154impl<'a> DoubleEndedIterator for Iter<'a> {
155 fn next_back(&mut self) -> Option<Self::Item> {
156 match self.components.next_back() {
157 Some(Ok(component @ PathComponent::Normal(_)))
158 if component.as_str().chars().count() > Path::MAX_COMPONENT_LENGTH =>
159 {
160 Some(Err(PathError::InvalidComponent(crate::ast::IdentError::InvalidLength {
161 max: Path::MAX_COMPONENT_LENGTH,
162 })))
163 },
164 next => next,
165 }
166 }
167}
168
169#[derive(Debug)]
171struct Components<'a> {
172 original: &'a str,
173 path: &'a str,
175 front_pos: usize,
178 front: State,
179 back_pos: usize,
180 back: State,
181}
182
183#[derive(Debug, Copy, Clone, PartialEq)]
184enum State {
185 Start,
187 Body,
189 QuoteOpened(usize),
191 QuoteClosed(usize),
193 Done,
195}
196
197impl<'a> Components<'a> {
198 fn finished(&self) -> bool {
199 match (self.front, self.back) {
200 (State::Done, _) => true,
201 (_, State::Done) => true,
202 (State::Body | State::QuoteOpened(_) | State::QuoteClosed(_), State::Start) => true,
203 (..) => false,
204 }
205 }
206}
207
208impl<'a> Iterator for Components<'a> {
209 type Item = Result<PathComponent<'a>, PathError>;
210
211 fn next(&mut self) -> Option<Self::Item> {
212 let mut quote_opened = None;
216 while !self.finished() || quote_opened.is_some() {
217 match self.front {
218 State::Start => match self.path.strip_prefix("::") {
219 Some(rest) => {
220 self.path = rest;
221 self.front = State::Body;
222 self.front_pos += 2;
223 return Some(Ok(PathComponent::Root));
224 },
225 None => {
226 self.front = State::Body;
227 },
228 },
229 State::Body => {
230 if let Some(rest) = self.path.strip_prefix('"') {
231 self.front = State::QuoteOpened(self.front_pos);
232 self.front_pos += 1;
233 self.path = rest;
234 continue;
235 }
236 match self.path.split_once("::") {
237 Some(("", rest)) => {
238 self.path = rest;
239 self.front_pos += 2;
240 return Some(Err(PathError::InvalidComponent(
241 crate::ast::IdentError::Empty,
242 )));
243 },
244 Some((component, rest)) => {
245 self.front_pos += component.len() + 2;
246 if rest.is_empty() {
247 self.path = "::";
248 } else {
249 self.path = rest;
250 }
251 if let Err(err) =
252 Ident::validate(component).map_err(PathError::InvalidComponent)
253 {
254 return Some(Err(err));
255 }
256 return Some(Ok(PathComponent::Normal(component)));
257 },
258 None if self.path.is_empty() => {
259 self.front = State::Done;
260 },
261 None => {
262 self.front = State::Done;
263 let component = self.path;
264 self.path = "";
265 if let Err(err) =
266 Ident::validate(component).map_err(PathError::InvalidComponent)
267 {
268 return Some(Err(err));
269 }
270 self.front_pos += component.len();
271 return Some(Ok(PathComponent::Normal(component)));
272 },
273 }
274 },
275 State::QuoteOpened(opened_at) => match self.path.split_once('"') {
276 Some(("", rest)) => {
277 self.path = rest;
278 self.front = State::QuoteClosed(self.front_pos);
279 self.front_pos += 1;
280 quote_opened = Some(Err(PathError::EmptyComponent));
281 },
282 Some((quoted, rest)) => {
283 self.path = rest;
284 self.front_pos += quoted.len();
285 self.front = State::QuoteClosed(self.front_pos);
286 self.front_pos += 1;
287 let quoted = &self.original[opened_at..self.front_pos];
288 quote_opened = Some(Ok(PathComponent::Normal(quoted)));
289 },
290 None => {
291 self.front = State::Done;
292 self.front_pos += self.path.len();
293 return Some(Err(PathError::UnclosedQuotedComponent));
294 },
295 },
296 State::QuoteClosed(_) => {
297 if self.path.is_empty() {
298 self.front = State::Done;
299 } else {
300 match self.path.strip_prefix("::") {
301 Some(rest) => {
302 self.path = rest;
303 self.front = State::Body;
304 self.front_pos += 2;
305 },
306 None if quote_opened.is_some() => (),
310 None => {
311 self.front = State::Done;
312 return Some(Err(PathError::MissingPathSeparator));
313 },
314 }
315 }
316
317 if quote_opened.is_some() {
318 return quote_opened;
319 }
320 },
321 State::Done => break,
322 }
323 }
324
325 None
326 }
327}
328
329impl<'a> DoubleEndedIterator for Components<'a> {
330 fn next_back(&mut self) -> Option<Self::Item> {
331 let mut quote_closed = None;
335 while !self.finished() || quote_closed.is_some() {
336 match self.back {
337 State::Start => {
338 self.back = State::Done;
339 match self.path {
340 "" => break,
341 "::" => {
342 self.back_pos = 0;
343 return Some(Ok(PathComponent::Root));
344 },
345 other => {
346 return Some(Ok(PathComponent::Normal(other)));
347 },
348 }
349 },
350 State::Body => {
351 if let Some(rest) = self.path.strip_suffix('"') {
352 self.back = State::QuoteClosed(self.back_pos);
353 self.back_pos -= 1;
354 self.path = rest;
355 continue;
356 }
357 match self.path.rsplit_once("::") {
358 Some(("", "")) => {
359 self.back = State::Start;
360 self.back_pos -= 2;
361 },
362 Some((prefix, component)) => {
363 self.back_pos -= component.len() + 2;
364 if prefix.is_empty() {
365 self.path = "::";
366 self.back = State::Start;
367 } else {
368 self.path = prefix;
369 }
370 if let Err(err) =
371 Ident::validate(component).map_err(PathError::InvalidComponent)
372 {
373 return Some(Err(err));
374 }
375 return Some(Ok(PathComponent::Normal(component)));
376 },
377 None if self.path.is_empty() => {
378 self.back = State::Start;
379 },
380 None => {
381 self.back = State::Start;
382 let component = self.path;
383 self.path = "";
384 self.back_pos = 0;
385 if let Err(err) =
386 Ident::validate(component).map_err(PathError::InvalidComponent)
387 {
388 return Some(Err(err));
389 }
390 return Some(Ok(PathComponent::Normal(component)));
391 },
392 }
393 },
394 State::QuoteOpened(_) => {
395 if self.path.is_empty() {
396 self.back = State::Start;
397 } else {
398 match self.path.strip_suffix("::") {
399 Some("") => {
400 self.back = State::Start;
401 self.back_pos -= 2;
402 },
403 Some(rest) => {
404 self.back_pos -= 2;
405 self.path = rest;
406 self.back = State::Body;
407 },
408 None if quote_closed.is_some() => (),
412 None => {
413 self.back = State::Done;
414 return Some(Err(PathError::MissingPathSeparator));
415 },
416 }
417 }
418
419 if quote_closed.is_some() {
420 return quote_closed;
421 }
422 },
423 State::QuoteClosed(closed_at) => match self.path.rsplit_once('"') {
424 Some((rest, "")) => {
425 self.back_pos -= 1;
426 self.path = rest;
427 self.back = State::QuoteOpened(self.back_pos);
428 quote_closed = Some(Err(PathError::EmptyComponent));
429 },
430 Some((rest, quoted)) => {
431 self.back_pos -= quoted.len() + 1;
432 let quoted = &self.original[self.back_pos..closed_at];
433 self.path = rest;
434 self.back = State::QuoteOpened(self.back_pos);
435 quote_closed = Some(Ok(PathComponent::Normal(quoted)));
436 },
437 None => {
438 self.back = State::Done;
439 self.back_pos = 0;
440 return Some(Err(PathError::UnclosedQuotedComponent));
441 },
442 },
443 State::Done => break,
444 }
445 }
446 None
447 }
448}
449
450#[cfg(test)]
451mod tests {
452 use core::assert_matches;
453
454 use super::*;
455
456 #[test]
457 fn empty_path() {
458 let mut components = Iter::new("");
459 assert_matches!(components.next(), None);
460 }
461
462 #[test]
463 fn empty_path_back() {
464 let mut components = Iter::new("");
465 assert_matches!(components.next_back(), None);
466 }
467
468 #[test]
469 fn root_prefix_path() {
470 let mut components = Iter::new("::");
471 assert_matches!(components.next(), Some(Ok(PathComponent::Root)));
472 assert_matches!(components.next(), None);
473 }
474
475 #[test]
476 fn root_prefix_path_back() {
477 let mut components = Iter::new("::");
478 assert_matches!(components.next_back(), Some(Ok(PathComponent::Root)));
479 assert_matches!(components.next_back(), None);
480 }
481
482 #[test]
483 fn absolute_path() {
484 let mut components = Iter::new("::foo");
485 assert_matches!(components.next(), Some(Ok(PathComponent::Root)));
486 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("foo"))));
487 assert_matches!(components.next(), None);
488 }
489
490 #[test]
491 fn absolute_path_back() {
492 let mut components = Iter::new("::foo");
493 assert_matches!(components.next_back(), Some(Ok(PathComponent::Normal("foo"))));
494 assert_matches!(components.next_back(), Some(Ok(PathComponent::Root)));
495 assert_matches!(components.next_back(), None);
496 }
497
498 #[test]
499 fn absolute_nested_path() {
500 let mut components = Iter::new("::foo::bar");
501 assert_matches!(components.next(), Some(Ok(PathComponent::Root)));
502 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("foo"))));
503 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("bar"))));
504 assert_matches!(components.next(), None);
505 }
506
507 #[test]
508 fn absolute_nested_path_back() {
509 let mut components = Iter::new("::foo::bar");
510 assert_matches!(components.next_back(), Some(Ok(PathComponent::Normal("bar"))));
511 assert_matches!(components.next_back(), Some(Ok(PathComponent::Normal("foo"))));
512 assert_matches!(components.next_back(), Some(Ok(PathComponent::Root)));
513 assert_matches!(components.next_back(), None);
514 }
515
516 #[test]
517 fn relative_path() {
518 let mut components = Iter::new("foo");
519 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("foo"))));
520 assert_matches!(components.next(), None);
521 }
522
523 #[test]
524 fn relative_path_back() {
525 let mut components = Iter::new("foo");
526 assert_matches!(components.next_back(), Some(Ok(PathComponent::Normal("foo"))));
527 assert_matches!(components.next_back(), None);
528 }
529
530 #[test]
531 fn relative_nested_path() {
532 let mut components = Iter::new("foo::bar");
533 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("foo"))));
534 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("bar"))));
535 assert_matches!(components.next(), None);
536 }
537
538 #[test]
539 fn relative_nested_path_back() {
540 let mut components = Iter::new("foo::bar");
541 assert_matches!(components.next_back(), Some(Ok(PathComponent::Normal("bar"))));
542 assert_matches!(components.next_back(), Some(Ok(PathComponent::Normal("foo"))));
543 assert_matches!(components.next_back(), None);
544 }
545
546 #[test]
547 fn special_path() {
548 let mut components = Iter::new("$kernel");
549 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("$kernel"))));
550 assert_matches!(components.next(), None);
551
552 let mut components = Iter::new("::$kernel");
553 assert_matches!(components.next(), Some(Ok(PathComponent::Root)));
554 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("$kernel"))));
555 assert_matches!(components.next(), None);
556 }
557
558 #[test]
559 fn special_path_back() {
560 let mut components = Iter::new("$kernel");
561 assert_matches!(components.next_back(), Some(Ok(PathComponent::Normal("$kernel"))));
562 assert_matches!(components.next_back(), None);
563
564 let mut components = Iter::new("::$kernel");
565 assert_matches!(components.next_back(), Some(Ok(PathComponent::Normal("$kernel"))));
566 assert_matches!(components.next_back(), Some(Ok(PathComponent::Root)));
567 assert_matches!(components.next_back(), None);
568 }
569
570 #[test]
571 fn special_nested_path() {
572 let mut components = Iter::new("$kernel::bar");
573 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("$kernel"))));
574 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("bar"))));
575 assert_matches!(components.next(), None);
576
577 let mut components = Iter::new("::$kernel::bar");
578 assert_matches!(components.next(), Some(Ok(PathComponent::Root)));
579 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("$kernel"))));
580 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("bar"))));
581 assert_matches!(components.next(), None);
582 }
583
584 #[test]
585 fn special_nested_path_back() {
586 let mut components = Iter::new("$kernel::bar");
587 assert_matches!(components.next_back(), Some(Ok(PathComponent::Normal("bar"))));
588 assert_matches!(components.next_back(), Some(Ok(PathComponent::Normal("$kernel"))));
589 assert_matches!(components.next_back(), None);
590
591 let mut components = Iter::new("::$kernel::bar");
592 assert_matches!(components.next_back(), Some(Ok(PathComponent::Normal("bar"))));
593 assert_matches!(components.next_back(), Some(Ok(PathComponent::Normal("$kernel"))));
594 assert_matches!(components.next_back(), Some(Ok(PathComponent::Root)));
595 assert_matches!(components.next_back(), None);
596 }
597
598 #[test]
599 fn path_with_quoted_component() {
600 let mut components = Iter::new("\"foo\"");
601 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("\"foo\""))));
602 assert_matches!(components.next(), None);
603 }
604
605 #[test]
606 fn path_with_quoted_component_back() {
607 let mut components = Iter::new("\"foo\"");
608 assert_matches!(components.next_back(), Some(Ok(PathComponent::Normal("\"foo\""))));
609 assert_matches!(components.next_back(), None);
610 }
611
612 #[test]
613 fn nested_path_with_quoted_component() {
614 let mut components = Iter::new("foo::\"bar\"");
615 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("foo"))));
616 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("\"bar\""))));
617 assert_matches!(components.next(), None);
618 }
619
620 #[test]
621 fn nested_path_with_quoted_component_back() {
622 let mut components = Iter::new("foo::\"bar\"");
623 assert_matches!(components.next_back(), Some(Ok(PathComponent::Normal("\"bar\""))));
624 assert_matches!(components.next_back(), Some(Ok(PathComponent::Normal("foo"))));
625 assert_matches!(components.next_back(), None);
626 }
627
628 #[test]
629 fn nested_path_with_interspersed_quoted_component() {
630 let mut components = Iter::new("foo::\"bar\"::baz");
631 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("foo"))));
632 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("\"bar\""))));
633 assert_matches!(components.next(), Some(Ok(PathComponent::Normal("baz"))));
634 assert_matches!(components.next(), None);
635 }
636
637 #[test]
638 fn nested_path_with_interspersed_quoted_component_back() {
639 let mut components = Iter::new("foo::\"bar\"::baz");
640 assert_matches!(components.next_back(), Some(Ok(PathComponent::Normal("baz"))));
641 assert_matches!(components.next_back(), Some(Ok(PathComponent::Normal("\"bar\""))));
642 assert_matches!(components.next_back(), Some(Ok(PathComponent::Normal("foo"))));
643 assert_matches!(components.next_back(), None);
644 }
645}