opendal/services/compfs/
lister.rs1use std::fs::ReadDir;
19use std::path::Path;
20use std::sync::Arc;
21
22use super::core::CompfsCore;
23use crate::raw::*;
24use crate::*;
25
26#[derive(Debug)]
27pub struct CompfsLister {
28 core: Arc<CompfsCore>,
29 root: Option<String>,
30 read_dir: Option<ReadDir>,
31}
32
33impl CompfsLister {
34 pub(super) fn new(core: Arc<CompfsCore>, root: &Path, read_dir: ReadDir) -> Self {
35 let root = normalize(root, &core.root);
36 Self {
37 core,
38 root: Some(root),
39 read_dir: Some(read_dir),
40 }
41 }
42}
43
44fn normalize(path: &Path, root: &Path) -> String {
45 normalize_path(
46 &path
47 .strip_prefix(root)
48 .expect("cannot fail because the prefix is iterated")
49 .to_string_lossy()
50 .replace('\\', "/"),
51 )
52}
53
54fn next_entry(read_dir: &mut ReadDir, root: &Path) -> std::io::Result<Option<oio::Entry>> {
55 let Some(entry) = read_dir.next().transpose()? else {
56 return Ok(None);
57 };
58 let path = entry.path();
59 let rel_path = normalize(&path, root);
60
61 let file_type = entry.file_type()?;
62
63 let entry = if file_type.is_file() {
64 oio::Entry::new(&rel_path, Metadata::new(EntryMode::FILE))
65 } else if file_type.is_dir() {
66 oio::Entry::new(&format!("{rel_path}/"), Metadata::new(EntryMode::DIR))
67 } else {
68 oio::Entry::new(&rel_path, Metadata::new(EntryMode::Unknown))
69 };
70
71 Ok(Some(entry))
72}
73
74impl oio::List for CompfsLister {
75 async fn next(&mut self) -> Result<Option<oio::Entry>> {
76 if let Some(root) = self.root.take() {
77 return Ok(Some(oio::Entry::new(
78 &format!("{root}/"),
79 Metadata::new(EntryMode::DIR),
80 )));
81 }
82 let Some(mut read_dir) = self.read_dir.take() else {
83 return Ok(None);
84 };
85 let root = self.core.root.clone();
86 let (entry, read_dir) = self
87 .core
88 .exec_blocking(move || {
89 let entry = next_entry(&mut read_dir, &root).map_err(new_std_io_error);
90 (entry, read_dir)
91 })
92 .await?;
93 if !matches!(entry, Ok(None)) {
94 self.read_dir = Some(read_dir);
95 }
96 entry
97 }
98}