arch_pkg_db/text/
local.rs1use super::{Text, TextCollection};
2use core::error::Error;
3use derive_more::{Display, Error};
4use pipe_trait::Pipe;
5use rayon::prelude::*;
6use std::{
7 fs::{read_dir, read_to_string},
8 io::{self, ErrorKind},
9 path::{Path, PathBuf},
10};
11
12#[derive(Debug, Display, Error)]
14#[display("Failed to read {path:?} as a directory: {error}")]
15pub struct ReadLocalDbDirError<'a> {
16 #[error(source)]
17 error: io::Error,
18 path: &'a Path,
19}
20
21impl<'a> ReadLocalDbDirError<'a> {
22 fn new(error: io::Error, path: &'a Path) -> Self {
24 Self { error, path }
25 }
26
27 pub fn source(&self) -> &io::Error {
29 &self.error
30 }
31
32 pub fn path(&self) -> &Path {
34 self.path
35 }
36}
37
38#[derive(Debug, Display, Error)]
40#[display("Failed to read {path:?} as a text file: {error}")]
41pub struct ReadLocalDbFileError {
42 #[error(source)]
43 error: io::Error,
44 path: PathBuf,
45}
46
47impl ReadLocalDbFileError {
48 fn new(error: io::Error, path: PathBuf) -> Self {
50 Self { error, path }
51 }
52
53 pub fn source(&self) -> &io::Error {
55 &self.error
56 }
57
58 pub fn path(&self) -> &Path {
60 &self.path
61 }
62}
63
64#[derive(Debug, Display)]
66pub enum LoadLocalDbError<'a> {
67 ReadDir(ReadLocalDbDirError<'a>),
68 ReadFile(ReadLocalDbFileError),
69}
70
71impl<'a> Error for LoadLocalDbError<'a> {
74 fn source(&self) -> Option<&(dyn Error + 'static)> {
75 match self {
76 LoadLocalDbError::ReadDir(error) => Error::source(error),
77 LoadLocalDbError::ReadFile(error) => Error::source(error),
78 }
79 }
80}
81
82impl TextCollection {
83 pub fn extend_from_local_db<'path>(
87 &mut self,
88 local_db_path: &'path Path,
89 ) -> Result<(), LoadLocalDbError<'path>> {
90 let entries = local_db_path
91 .pipe(read_dir)
92 .map_err(|error| ReadLocalDbDirError::new(error, local_db_path))
93 .map_err(LoadLocalDbError::ReadDir)?;
94
95 for entry in entries {
96 let Ok(entry) = entry else { continue };
97 let Ok(file_type) = entry.file_type() else {
98 continue;
99 };
100 if !file_type.is_dir() {
101 continue;
102 }
103 let file_path = entry.path().join("desc");
104 match read_to_string(&file_path) {
105 Ok(text) => self.insert(text.into()),
106 Err(error) if error.kind() == ErrorKind::NotFound => continue,
107 Err(error) => {
108 return ReadLocalDbFileError::new(error, file_path)
109 .pipe(LoadLocalDbError::ReadFile)
110 .pipe(Err);
111 }
112 };
113 }
114
115 Ok(())
116 }
117
118 pub fn add_local_db(mut self, local_db_path: &'_ Path) -> Result<Self, LoadLocalDbError<'_>> {
122 self.extend_from_local_db(local_db_path)?;
123 Ok(self)
124 }
125
126 pub fn from_local_db(local_db_path: &'_ Path) -> Result<Self, LoadLocalDbError<'_>> {
130 TextCollection::new().add_local_db(local_db_path)
131 }
132
133 pub fn par_extend_from_local_db<'path>(
137 &mut self,
138 local_db_path: &'path Path,
139 ) -> Result<(), LoadLocalDbError<'path>> {
140 let texts = local_db_path
141 .pipe(read_dir)
142 .map_err(|error| ReadLocalDbDirError::new(error, local_db_path))
143 .map_err(LoadLocalDbError::ReadDir)?
144 .par_bridge()
145 .flatten()
146 .filter(|entry| {
147 entry
148 .file_type()
149 .ok()
150 .map(|file_type| file_type.is_dir())
151 .unwrap_or(false)
152 })
153 .map(|entry| -> Result<Option<String>, LoadLocalDbError> {
154 let file_path = entry.path().join("desc");
155 match read_to_string(&file_path) {
156 Ok(text) => Ok(Some(text)),
157 Err(error) if error.kind() == ErrorKind::NotFound => Ok(None),
158 Err(error) => ReadLocalDbFileError::new(error, file_path)
159 .pipe(LoadLocalDbError::ReadFile)
160 .pipe(Err),
161 }
162 })
163 .collect::<Result<Vec<Option<String>>, LoadLocalDbError>>()?
164 .into_iter()
165 .flatten()
166 .map(Text::from);
167 self.extend(texts);
168 Ok(())
169 }
170
171 pub fn par_add_local_db(
175 mut self,
176 local_db_path: &'_ Path,
177 ) -> Result<Self, LoadLocalDbError<'_>> {
178 self.par_extend_from_local_db(local_db_path)?;
179 Ok(self)
180 }
181
182 pub fn par_from_local_db(local_db_path: &Path) -> Result<Self, LoadLocalDbError<'_>> {
186 TextCollection::new().par_add_local_db(local_db_path)
187 }
188}