diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-07-28 11:42:27 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-07-28 11:42:27 +0800 |
| commit | 160460494f8c56fd42ff9ab96ace74cc4457f479 (patch) | |
| tree | c0434dae5760a4ce0462c89cddf0ca7091fcc971 /arg_picker/src/builtin/pick_paths.rs | |
| parent | 5229379afe1306c8d6ebea4e84418ba5caa475ae (diff) | |
feat(picker): add filesystem-aware path value types
Add `FilePath`, `NoFilePath`, `DirPath`, `NoDirPath`, `SymlinkPath`,
`NoSymlinkPath`, `NoPath`, and `RecursiveFiles` wrapper types with
filesystem validation at parse time. Each type implements
`SinglePickable`
and provides standard conversions via `From`, `AsRef`, `Deref`, and
`DerefMut`.
Diffstat (limited to 'arg_picker/src/builtin/pick_paths.rs')
| -rw-r--r-- | arg_picker/src/builtin/pick_paths.rs | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/arg_picker/src/builtin/pick_paths.rs b/arg_picker/src/builtin/pick_paths.rs new file mode 100644 index 0000000..8e6c0fd --- /dev/null +++ b/arg_picker/src/builtin/pick_paths.rs @@ -0,0 +1,167 @@ +use std::{ + fs, + path::{Path, PathBuf}, +}; + +use crate::{ + PickerArgResult::{self, NotFound, Parsed, Unparsed}, + SinglePickable, + value::{ + DirPath, FilePath, NoDirPath, NoFilePath, NoPath, NoSymlinkPath, RecursiveFiles, + SymlinkPath, + }, +}; + +impl SinglePickable for FilePath { + fn pick_single(str: Option<&str>) -> PickerArgResult<Self> { + match <PathBuf as SinglePickable>::pick_single(str) { + Parsed(path) => { + if path.exists() && path.is_file() { + Parsed(FilePath::from(path)) + } else { + NotFound + } + } + Unparsed => Unparsed, + NotFound => NotFound, + } + } +} + +impl SinglePickable for NoFilePath { + fn pick_single(str: Option<&str>) -> PickerArgResult<Self> { + match <PathBuf as SinglePickable>::pick_single(str) { + Parsed(path) => { + if !path.exists() || !path.is_file() { + Parsed(NoFilePath::from(path)) + } else { + NotFound + } + } + Unparsed => Unparsed, + NotFound => NotFound, + } + } +} + +impl SinglePickable for DirPath { + fn pick_single(str: Option<&str>) -> PickerArgResult<Self> { + match <PathBuf as SinglePickable>::pick_single(str) { + Parsed(path) => { + if path.exists() && path.is_dir() { + Parsed(DirPath::from(path)) + } else { + NotFound + } + } + Unparsed => Unparsed, + NotFound => NotFound, + } + } +} + +impl SinglePickable for NoDirPath { + fn pick_single(str: Option<&str>) -> PickerArgResult<Self> { + match <PathBuf as SinglePickable>::pick_single(str) { + Parsed(path) => { + if !path.exists() || !path.is_dir() { + Parsed(NoDirPath::from(path)) + } else { + NotFound + } + } + Unparsed => Unparsed, + NotFound => NotFound, + } + } +} + +impl SinglePickable for SymlinkPath { + fn pick_single(str: Option<&str>) -> PickerArgResult<Self> { + match <PathBuf as SinglePickable>::pick_single(str) { + Parsed(path) => { + if path.exists() && path.is_symlink() { + Parsed(SymlinkPath::from(path)) + } else { + NotFound + } + } + Unparsed => Unparsed, + NotFound => NotFound, + } + } +} + +impl SinglePickable for NoSymlinkPath { + fn pick_single(str: Option<&str>) -> PickerArgResult<Self> { + match <PathBuf as SinglePickable>::pick_single(str) { + Parsed(path) => { + if !path.exists() || !path.is_symlink() { + Parsed(NoSymlinkPath::from(path)) + } else { + NotFound + } + } + Unparsed => Unparsed, + NotFound => NotFound, + } + } +} + +impl SinglePickable for NoPath { + fn pick_single(str: Option<&str>) -> PickerArgResult<Self> { + match <PathBuf as SinglePickable>::pick_single(str) { + Parsed(path) => { + if !path.exists() { + Parsed(NoPath::from(path)) + } else { + NotFound + } + } + Unparsed => Unparsed, + NotFound => NotFound, + } + } +} + +impl SinglePickable for RecursiveFiles { + fn pick_single(str: Option<&str>) -> PickerArgResult<Self> { + match <PathBuf as SinglePickable>::pick_single(str) { + Parsed(path) => { + if !path.exists() { + return NotFound; + } + if path.is_file() || path.is_symlink() { + return Parsed(RecursiveFiles::from(vec![path])); + } + let mut entries = Vec::new(); + if let Ok(dir_entries) = fs::read_dir(&path) { + for entry in dir_entries.flatten() { + let entry_path = entry.path(); + if entry_path.is_file() || entry_path.is_symlink() { + entries.push(entry_path); + } else if entry_path.is_dir() { + collect_files(&entry_path, &mut entries); + } + } + } + Parsed(RecursiveFiles::from(entries)) + } + Unparsed => Unparsed, + NotFound => NotFound, + } + } +} + +fn collect_files(dir: &Path, entries: &mut Vec<PathBuf>) { + if let Ok(dir_entries) = fs::read_dir(dir) { + for entry in dir_entries.flatten() { + let entry_path = entry.path(); + if entry_path.is_file() || entry_path.is_symlink() { + entries.push(entry_path); + } else if entry_path.is_dir() { + collect_files(&entry_path, entries); + } + } + } +} |
