Skip to main content

qubit_fs/path/
path_component.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//! One validated logical path component.
10
11use std::fmt::Display;
12use std::fmt::Formatter;
13use std::fmt::Result as FmtResult;
14
15use crate::error::FsError;
16use crate::error::FsOperation;
17use crate::error::FsResult;
18
19/// A non-empty logical component that cannot express hierarchy or traversal.
20///
21/// # Examples
22///
23/// ```rust
24/// use qubit_fs::path::PathComponent;
25///
26/// let component = PathComponent::parse("reports")?;
27/// assert_eq!("reports", component.as_str());
28/// # Ok::<(), qubit_fs::FsError>(())
29/// ```
30#[derive(Clone, Debug, Eq, Hash, PartialEq)]
31pub struct PathComponent(
32    /// Validated component text containing no hierarchy or traversal marker.
33    String,
34);
35
36impl PathComponent {
37    /// Parses one logical component.
38    ///
39    /// Returns an invalid-path error for empty input, separators, traversal
40    /// markers, or NUL. This method performs no native-path conversion.
41    ///
42    /// # Parameters
43    /// - `text`: Component text to validate.
44    ///
45    /// # Errors
46    /// Returns an invalid-path error when `text` is empty, contains a
47    /// separator, is a traversal marker, or contains NUL.
48    pub fn parse(text: &str) -> FsResult<Self> {
49        if text.is_empty() || matches!(text, "." | "..") || text.contains('/') || text.contains('\0') {
50            return Err(FsError::invalid_path(
51                FsOperation::ParsePath,
52                "path component must be a non-empty non-traversal component",
53            ));
54        }
55        Ok(Self(text.to_owned()))
56    }
57
58    /// Returns the validated logical component text.
59    #[inline]
60    #[must_use]
61    pub fn as_str(&self) -> &str {
62        &self.0
63    }
64}
65
66impl Display for PathComponent {
67    /// Formats the validated component without changing its lexical spelling.
68    #[inline]
69    fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
70        formatter.write_str(self.as_str())
71    }
72}