Skip to main content

path_rs/
lib.rs

1//! Cross-platform path expansion, normalization, resolution,
2//! traversal, searching, and caching.
3//!
4//! `path-rs` complements [`std::path::Path`] and [`std::path::PathBuf`].
5//! It does **not** replace them.
6//!
7//! # Distinguished operations
8//!
9//! | Operation | Filesystem access | Requires existence | Resolves symlinks |
10//! | --- | ---: | ---: | ---: |
11//! | [`expand_input`] | No\* | No | No |
12//! | [`normalize`] | No | No | No |
13//! | [`resolve_against`] | No | No | No |
14//! | [`canonicalize_existing`] | Yes | Yes | Yes |
15//! | [`path_identity_key`] | Configurable | No† | Configurable |
16//! | [`app_paths`] | Platform APIs | No | No |
17//! | [`inspect_directory`] | Yes | No | Partial |
18//! | `list` / `discover_*` (feature `listing`) | Yes | Root yes | Configurable |
19//! | `search` (feature `search`) | Yes | Root yes | Configurable |
20//!
21//! \* Home directory resolution may consult environment / platform APIs.  
22//! † Unless symlink resolution is enabled on the identity options.
23//!
24//! # Architectural boundary
25//!
26//! This crate provides **generic path mechanics** only. Product-specific logic
27//! (repository inventories, VCS roots, watchers, cloud remotes, mutation stores)
28//! belongs in application adapters that *compose* these APIs.
29//!
30//! # Example
31//!
32//! ```
33//! use path_rs::{expand_input, normalize, ExpandOptions};
34//!
35//! let expanded = expand_input("~", &ExpandOptions::default()).unwrap();
36//! let normalized = normalize("foo/./bar/../baz").unwrap();
37//! assert_eq!(normalized, std::path::PathBuf::from("foo/baz"));
38//! let _ = expanded;
39//! ```
40//!
41//! # Security
42//!
43//! Lexical normalization is not canonicalization. Lexical root containment is
44//! not symlink-safe. Cached discovery results are not authoritative. Path
45//! identity keys are comparison keys, not filesystem identity proofs. See
46//! `SECURITY.md` in the repository.
47//!
48//! # Feature flags
49//!
50//! - `listing` (default): directory listing / discovery (`walkdir`)
51//! - `search` (default): glob and predicate search (`globset`, implies `listing`)
52//! - `persistent-cache`: on-disk discovery cache (`serde`, `serde_json`)
53//! - `unicode`: Unicode NFC logical path keys
54//! - `async`: `spawn_blocking` wrappers for list/search
55//!
56//! # Parallelism
57//!
58//! APIs do not spawn threads unless an explicit `async` helper is used.
59//! Returned types and the in-memory cache are safe to use from parallel callers
60//! (`Send` + `Sync` where applicable). The crate does not invoke external
61//! processes, network clients, or VCS tools.
62
63#![cfg_attr(docsrs, feature(doc_cfg))]
64#![deny(missing_docs)]
65#![warn(rust_2018_idioms)]
66
67mod containment;
68mod dirs;
69mod error;
70mod expand;
71mod identity;
72mod inspect;
73mod internal;
74mod match_path;
75mod metadata;
76mod normalize;
77mod platform;
78mod resolve;
79mod text;
80mod utf8;
81
82#[cfg(feature = "listing")]
83#[cfg_attr(docsrs, doc(cfg(feature = "listing")))]
84pub mod discovery;
85
86#[cfg(feature = "listing")]
87#[cfg_attr(docsrs, doc(cfg(feature = "listing")))]
88pub mod listing;
89
90#[cfg(feature = "search")]
91#[cfg_attr(docsrs, doc(cfg(feature = "search")))]
92pub mod search;
93
94pub mod cache;
95
96pub use containment::{ensure_inside, is_lexically_inside};
97pub use dirs::{
98    AppPaths, AppPathsOptions, AppRootPolicy, PlatformDirs, app_paths, app_paths_with_options,
99    app_paths_with_policy, cache_dir, config_dir, data_dir, platform_dirs, temp_dir,
100};
101pub use error::PathError;
102pub use expand::{
103    ExpandOptions, expand_dollar_variables, expand_input, expand_percent_variables, expand_tilde,
104};
105pub use identity::{
106    PathIdentityOptions, PathRecord, deduplicate_paths, path_display_string, path_identity_key,
107};
108pub use inspect::{
109    DirectoryInspection, MetadataSummary, directory_exists, inspect_directory,
110    is_existing_directory, require_directory,
111};
112pub use match_path::{
113    CommandLinePathMatchOptions, ExecutableMatchOptions, command_line_contains_path,
114    executable_paths_match,
115};
116pub use metadata::{EntryKind, FileEntry, SortMode, TraversalErrorPolicy, sort_entries};
117pub use normalize::{canonicalize_existing, normalize};
118pub use platform::{
119    is_device_namespace, is_drive_relative, is_reserved_windows_name, is_unc, is_verbatim,
120    path_contains_reserved_name, simplify_for_display, translate_wsl_path,
121};
122pub use resolve::{absolute, join_relative, resolve_against, resolve_inside};
123pub use text::{CaseNormalization, TextNormalizationOptions, normalize_path_token};
124pub use utf8::{path_to_string_lossy, path_to_utf8};
125
126#[cfg(feature = "unicode")]
127#[cfg_attr(docsrs, doc(cfg(feature = "unicode")))]
128pub use utf8::logical_path_key;
129
130pub use cache::{
131    CacheKey, CacheMode, CacheOptions, CachePolicy, CacheValue, DiscoveryCache, MemoryCache,
132};
133
134#[cfg(feature = "persistent-cache")]
135#[cfg_attr(docsrs, doc(cfg(feature = "persistent-cache")))]
136pub use cache::PersistentCache;
137
138#[cfg(feature = "listing")]
139#[cfg_attr(docsrs, doc(cfg(feature = "listing")))]
140pub use discovery::{
141    DirectoryVisitor, DiscoveryOptions, VisitControl, discover_directories, discover_where,
142    visit_directories,
143};
144
145#[cfg(feature = "listing")]
146#[cfg_attr(docsrs, doc(cfg(feature = "listing")))]
147pub use listing::{ListOptions, WalkIter, list, walk};
148
149#[cfg(feature = "search")]
150#[cfg_attr(docsrs, doc(cfg(feature = "search")))]
151pub use search::{SearchRequest, search, search_with, search_with_cache};