Skip to main content

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}