Skip to main content

asimov_directory/fs/
module_iterators.rs

1// This is free and unencumbered software released into the public domain.
2
3use asimov_core::ModuleName;
4use asimov_module::InstalledModuleManifest;
5use camino::Utf8PathBuf;
6use std::io::Result;
7use tokio::fs::ReadDir;
8
9/// An iterator over module names in a module directory.
10#[derive(Debug)]
11pub struct ModuleNameIterator {
12    dir: ReadDir,
13}
14
15impl ModuleNameIterator {
16    pub async fn new(path: Utf8PathBuf) -> Result<Self> {
17        Ok(ModuleNameIterator {
18            dir: tokio::fs::read_dir(path).await?,
19        })
20    }
21}
22
23impl crate::ModuleNameIterator for ModuleNameIterator {
24    async fn next(&mut self) -> Option<ModuleName> {
25        while let Some(entry) = self.dir.next_entry().await.transpose() {
26            if let Ok(entry) = entry
27                && let Some(entry_name) = entry.file_name().to_str()
28                && !entry_name.starts_with(".")
29                && let Ok(entry_type) = entry.file_type().await
30                && (entry_type.is_dir() || entry_type.is_symlink())
31                && let Ok(module_name) = ModuleName::try_from(entry_name)
32            {
33                return Some(module_name);
34            }
35        }
36        None
37    }
38}
39
40/// An iterator over module manifests in a module directory.
41#[derive(Debug)]
42pub struct ModuleManifestIterator {
43    dir: ReadDir,
44}
45
46impl ModuleManifestIterator {
47    pub async fn new(path: Utf8PathBuf) -> Result<Self> {
48        Ok(ModuleManifestIterator {
49            dir: tokio::fs::read_dir(path).await?,
50        })
51    }
52}
53
54impl crate::ModuleManifestIterator for ModuleManifestIterator {
55    async fn next(&mut self) -> Option<InstalledModuleManifest> {
56        while let Some(entry) = self.dir.next_entry().await.transpose() {
57            if let Ok(entry) = entry
58                && let Some(entry_name) = entry.file_name().to_str()
59                && !entry_name.starts_with(".")
60                && let Ok(entry_type) = entry.file_type().await
61                && (entry_type.is_dir() || entry_type.is_symlink())
62                && let Ok(content) = tokio::fs::read(entry.path().join("manifest.json")).await
63                && let Ok(manifest) = serde_json::from_slice(&content)
64            {
65                return Some(manifest);
66            }
67        }
68        None
69    }
70}