strict_path/path/virtual_path/iter.rs
1//! `VirtualReadDir` iterator for `VirtualPath`.
2//!
3//! Wraps `std::fs::ReadDir` and re-validates each directory entry through `virtual_join`,
4//! so callers get `VirtualPath` values directly. This prevents a listing from exposing
5//! raw `DirEntry` paths that would require the caller to re-validate manually.
6use super::VirtualPath;
7
8// ============================================================
9// VirtualReadDir — Iterator for validated virtual directory entries
10// ============================================================
11
12/// Iterator over directory entries that yields validated `VirtualPath` values.
13///
14/// Created by `VirtualPath::virtual_read_dir()`. Each iteration automatically validates
15/// the directory entry through `virtual_join()`, so you get `VirtualPath` values directly
16/// instead of raw `std::fs::DirEntry` that would require manual re-validation.
17///
18/// # Examples
19/// ```rust
20/// # use strict_path::{VirtualRoot, VirtualPath};
21/// # let temp = tempfile::tempdir()?;
22/// # let vroot: VirtualRoot = VirtualRoot::try_new(temp.path())?;
23/// # let dir = vroot.virtual_join("assets")?;
24/// # dir.create_dir_all()?;
25/// # vroot.virtual_join("assets/logo.png")?.write(b"PNG")?;
26/// for entry in dir.virtual_read_dir()? {
27/// let child: VirtualPath = entry?;
28/// if child.is_file() {
29/// println!("File: {}", child.virtualpath_display());
30/// }
31/// }
32/// # Ok::<_, Box<dyn std::error::Error>>(())
33/// ```
34pub struct VirtualReadDir<'vpath, Marker> {
35 pub(super) inner: std::fs::ReadDir,
36 pub(super) parent: &'vpath VirtualPath<Marker>,
37}
38
39impl<Marker> std::fmt::Debug for VirtualReadDir<'_, Marker> {
40 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41 f.debug_struct("VirtualReadDir")
42 .field("parent", &self.parent.virtualpath_display().to_string())
43 .finish_non_exhaustive()
44 }
45}
46
47impl<Marker: Clone> Iterator for VirtualReadDir<'_, Marker> {
48 type Item = std::io::Result<VirtualPath<Marker>>;
49
50 fn next(&mut self) -> Option<Self::Item> {
51 match self.inner.next()? {
52 Ok(entry) => {
53 let file_name = entry.file_name();
54 match self.parent.virtual_join(file_name) {
55 Ok(virtual_path) => Some(Ok(virtual_path)),
56 Err(e) => Some(Err(std::io::Error::new(std::io::ErrorKind::InvalidData, e))),
57 }
58 }
59 Err(e) => Some(Err(e)),
60 }
61 }
62}