qubit_fs/path/path_components.rs
1// =============================================================================
2// Copyright (c) 2025 - 2026 Haixing Hu.
3//
4// SPDX-License-Identifier: Apache-2.0
5//
6// Licensed under the Apache License, Version 2.0.
7// =============================================================================
8
9// facade tests.
10//! Iteration over lexical logical path components.
11
12/// Iterator over the path's lexical component boundaries.
13///
14/// # Examples
15///
16/// ```rust
17/// use qubit_fs::path::{Path, PathComponents};
18///
19/// let path = Path::parse("/a/b")?;
20/// let components: PathComponents<'_> = path.components();
21/// assert_eq!(2, components.count());
22/// # Ok::<(), qubit_fs::FsError>(())
23/// ```
24#[derive(Clone, Debug)]
25pub struct PathComponents<'a> {
26 /// Remaining lexical text with an absolute leading separator removed.
27 remaining: Option<&'a str>,
28}
29
30impl<'a> PathComponents<'a> {
31 /// Creates an iterator for `text`, removing only the absolute root marker.
32 pub(crate) fn new(text: &'a str, absolute: bool, literal: bool) -> Self {
33 let text = if absolute && !literal {
34 text.strip_prefix('/').unwrap_or(text)
35 } else {
36 text
37 };
38 Self {
39 remaining: (!text.is_empty()).then_some(text),
40 }
41 }
42}
43
44impl<'a> Iterator for PathComponents<'a> {
45 type Item = &'a str;
46
47 /// Returns the next lexical component, including empty literal components.
48 fn next(&mut self) -> Option<Self::Item> {
49 let remaining = self.remaining?;
50 match remaining.split_once('/') {
51 Some((component, rest)) => {
52 self.remaining = Some(rest);
53 Some(component)
54 }
55 None => {
56 self.remaining = None;
57 Some(remaining)
58 }
59 }
60 }
61}