{
127 | let updated_path = self.path_provider().combine(vec![path])?;
128 |
129 | let metadata = match stdfs::metadata(updated_path) {
130 | Ok(v) => v,
131 | Err(e) => {
132 | if e.kind() == stdio::ErrorKind::NotFound {
133 | return Ok(false);
134 | }
135 | return Err(e.into());
136 | }
137 | };
138 |
139 | Ok(metadata.is_file())
140 | }
141 |
142 | fn delete_file(&self, path: &str) -> anyhow::Result<()> {
143 | let updated_path = self.path_provider().combine(vec![path])?;
144 |
145 | stdfs::remove_file(updated_path)?;
146 |
147 | Ok(())
148 | }
149 | }
150 |
151 | #[derive(Copy, Clone, Debug, Eq, PartialEq)]
152 | pub struct DiskDirectoryManager
153 | where
154 | P: PathProvider + Send + Sync
155 | {
156 | path_provider: P,
157 | }
158 |
159 | impl
DiskDirectoryManager
160 | where
161 | P: PathProvider + Send + Sync
162 | {
163 | pub fn new(path_provider: P) -> DiskDirectoryManager
{
164 | DiskDirectoryManager {
165 | path_provider
166 | }
167 | }
168 | }
169 |
170 | #[async_trait]
171 | impl
DirectoryManager for DiskDirectoryManager
172 | where
173 | P: PathProvider + Send + Sync
174 | {
175 | fn path_provider(&self) -> &dyn PathProvider {
176 | &self.path_provider
177 | }
178 |
179 | async fn create_dir_async(&self, path: &str) -> anyhow::Result {
180 | let updated_path = self.path_provider().combine(vec![path])?;
181 |
182 | fs::create_dir(updated_path).await?;
183 |
184 | self.get_dir_async(path).await
185 | }
186 |
187 | async fn get_dir_async(&self, path: &str) -> anyhow::Result {
188 | let updated_path = self.path_provider().combine(vec![path])?;
189 |
190 | let metadata = fs::metadata(updated_path.clone()).await?;
191 |
192 | if !metadata.is_dir() {
193 | return Err(std::io::Error::from(std::io::ErrorKind::AlreadyExists).into());
194 | }
195 |
196 | Ok(DirectoryDetail {
197 | dir_manager: self,
198 | name: self.path_provider().get_object_name(&updated_path)?,
199 | path: self.path_provider().get_object_parent_path(&updated_path)?,
200 | }.clone())
201 | }
202 |
203 | async fn is_dir_exists_async(&self, path: &str) -> anyhow::Result {
204 | let updated_path = self.path_provider().combine(vec![path])?;
205 |
206 | let metadata = fs::metadata(updated_path).await;
207 |
208 | let metadata = match metadata {
209 | Ok(v) => v,
210 | Err(e) => {
211 | if e.kind() == std::io::ErrorKind::NotFound {
212 | return Ok(false);
213 | }
214 | return Err(e.into());
215 | }
216 | };
217 |
218 | Ok(metadata.is_dir())
219 | }
220 |
221 | async fn delete_dir_async(&self, path: &str, recursive: bool) -> anyhow::Result<()> {
222 | let updated_path = self.path_provider().combine(vec![path])?;
223 |
224 | if recursive {
225 | fs::remove_dir_all(updated_path).await?;
226 | } else {
227 | fs::remove_dir(updated_path).await?;
228 | }
229 |
230 | Ok(())
231 | }
232 |
233 | fn create_dir(&self, path: &str) -> anyhow::Result {
234 | let updated_path = self.path_provider().combine(vec![path])?;
235 |
236 | stdfs::create_dir(updated_path)?;
237 |
238 | self.get_dir(path)
239 | }
240 |
241 | fn get_dir(&self, path: &str) -> anyhow::Result {
242 | let updated_path = self.path_provider().combine(vec![path])?;
243 |
244 | let metadata = stdfs::metadata(updated_path.clone())?;
245 |
246 | if !metadata.is_dir() {
247 | return Err(stdio::Error::from(stdio::ErrorKind::AlreadyExists).into());
248 | }
249 |
250 | Ok(DirectoryDetail {
251 | dir_manager: self,
252 | name: self.path_provider().get_object_name(&updated_path)?,
253 | path: self.path_provider().get_object_parent_path(&updated_path)?,
254 | })
255 | }
256 |
257 | fn is_dir_exists(&self, path: &str) -> anyhow::Result {
258 | let updated_path = self.path_provider().combine(vec![path])?;
259 |
260 | let metadata = match stdfs::metadata(updated_path) {
261 | Ok(v) => v,
262 | Err(e) => {
263 | if e.kind() == stdio::ErrorKind::NotFound {
264 | return Ok(false);
265 | }
266 | return Err(e.into());
267 | }
268 | };
269 |
270 | Ok(metadata.is_dir())
271 | }
272 |
273 | fn delete_dir(&self, path: &str, recursive: bool) -> anyhow::Result<()> {
274 | let updated_path = self.path_provider().combine(vec![path])?;
275 |
276 | if recursive {
277 | stdfs::remove_dir_all(updated_path)?;
278 | } else {
279 | stdfs::remove_dir(updated_path)?;
280 | }
281 |
282 | Ok(())
283 | }
284 | }
285 |
286 | #[derive(Copy, Clone, Debug, Eq, PartialEq)]
287 | pub struct SystemPathProvider {}
288 |
289 | impl SystemPathProvider {
290 | pub fn new() -> SystemPathProvider {
291 | SystemPathProvider {}
292 | }
293 | }
294 |
295 | impl Default for SystemPathProvider {
296 | fn default() -> Self {
297 | Self::new()
298 | }
299 | }
300 |
301 | impl PathProvider for SystemPathProvider {
302 | fn combine(&self, paths: Vec<&str>) -> anyhow::Result {
303 | let mut buf = path::PathBuf::new();
304 |
305 | for path in paths {
306 | buf.push(path)
307 | }
308 |
309 | match buf.to_str() {
310 | Some(v) => Ok(normalize_path(v.to_string())),
311 | None => bail!("empty or invalid paths"),
312 | }
313 | }
314 |
315 | fn get_object_name(&self, path: &str) -> anyhow::Result {
316 | let normalized_path = normalize_path(path.to_string());
317 | let p = path::Path::new(&normalized_path);
318 |
319 | if let Some(v) = p.file_name() {
320 | if let Some(v) = v.to_str() {
321 | return Ok(v.to_string());
322 | }
323 | }
324 |
325 | bail!("invalid path: {}", path)
326 | }
327 |
328 | fn get_object_parent_path(&self, path: &str) -> anyhow::Result {
329 | let normalized_path = normalize_path(path.to_string());
330 | let p = path::Path::new(&normalized_path);
331 |
332 | if let Some(v) = p.parent() {
333 | if let Some(v) = v.to_str() {
334 | if v.is_empty() {
335 | bail!("invalid path: {}", path);
336 | }
337 | return Ok(v.to_string());
338 | }
339 | }
340 |
341 | bail!("invalid path: {}", path)
342 | }
343 | }
344 |
345 | fn normalize_path(mut path: String) -> String {
346 | let mut i: usize = 0;
347 | while let Some(pos) = path.chars().skip(i).collect::().find("/..") {
348 | if let Some(v) = path.chars().nth(pos + 3) {
349 | if v != '/' {
350 | i = pos + 1;
351 | continue;
352 | }
353 | }
354 |
355 | let tmp_path: String = path.chars().take(pos).collect();
356 | if let Some(parent_pos) = tmp_path.rfind('/') {
357 | let a: String = tmp_path.chars().take(parent_pos).collect::();
358 | let b: String = path.chars().skip(pos + 3).collect::();
359 | path = a;
360 | path.push_str(&b);
361 | } else {
362 | i = pos + 1;
363 | }
364 | }
365 |
366 | i = 0;
367 | while let Some(pos) = path.chars().skip(i).collect::().find("/.") {
368 | if let Some(v) = path.chars().nth(pos + 2) {
369 | if v == '/' {
370 | path = path.replace("/.", "");
371 | }
372 | } else {
373 | path = path.replace("/.", "");
374 | }
375 | i = pos + 1;
376 | }
377 |
378 | if path.is_empty() {
379 | path += "./"
380 | };
381 |
382 | path
383 | }
384 |
385 | #[cfg(test)]
386 | #[path = "./lib_test.rs"]
387 | mod lib_test;
--------------------------------------------------------------------------------
/src/Rust/src/disk/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod lib;
--------------------------------------------------------------------------------
/src/Rust/src/lib.rs:
--------------------------------------------------------------------------------
1 | pub mod providers;
2 | pub mod models;
3 | pub mod disk;
4 |
5 | use anyhow::Result;
6 |
7 | use crate::models::{DirectoryDetail, FileDetail};
8 | use crate::providers::{FileManager, DirectoryManager};
9 |
10 | // Async functions
11 | pub async fn create_dir_async<'a>(path: &str, dir_manager: &'a dyn DirectoryManager) -> Result> {
12 | dir_manager.create_dir_async(path).await
13 | }
14 |
15 | pub async fn get_dir_async<'a>(path: &str, dir_manager: &'a dyn DirectoryManager) -> Result> {
16 | dir_manager.get_dir_async(path).await
17 | }
18 |
19 | pub async fn is_dir_exists_async(path: &str, dir_manager: &dyn DirectoryManager) -> Result {
20 | dir_manager.is_dir_exists_async(path).await
21 | }
22 |
23 | pub async fn delete_dir_async(path: &str, recursive: bool, dir_manager: &dyn DirectoryManager) -> Result<()> {
24 | dir_manager.delete_dir_async(path, recursive).await
25 | }
26 |
27 | pub async fn get_file_async<'a>(path: &str, file_manager: &'a dyn FileManager) -> Result> {
28 | file_manager.get_file_async(path).await
29 | }
30 |
31 | pub async fn create_file_async<'a>(path: &str, file_manager: &'a dyn FileManager) -> Result> {
32 | file_manager.create_file_async(path).await
33 | }
34 |
35 | pub async fn is_file_exists_async(path: &str, file_manager: &dyn FileManager) -> Result {
36 | file_manager.is_file_exists_async(path).await
37 | }
38 |
39 | pub async fn delete_file_async(path: &str, file_manager: &dyn FileManager) -> Result<()> {
40 | file_manager.delete_file_async(path).await
41 | }
42 |
43 | // Sync functions
44 | pub fn create_dir<'a>(path: &str, dir_manager: &'a dyn DirectoryManager) -> Result> {
45 | dir_manager.create_dir(path)
46 | }
47 |
48 | pub fn get_dir<'a>(path: &str, dir_manager: &'a dyn DirectoryManager) -> Result> {
49 | dir_manager.get_dir(path)
50 | }
51 |
52 | pub fn is_dir_exists(path: &str, dir_manager: &dyn DirectoryManager) -> Result {
53 | dir_manager.is_dir_exists(path)
54 | }
55 |
56 | pub fn delete_dir(path: &str, recursive: bool, dir_manager: &dyn DirectoryManager) -> Result<()> {
57 | dir_manager.delete_dir(path, recursive)
58 | }
59 |
60 | pub fn get_file<'a>(path: &str, file_manager: &'a dyn FileManager) -> Result> {
61 | file_manager.get_file(path)
62 | }
63 |
64 | pub fn create_file<'a>(path: &str, file_manager: &'a dyn FileManager) -> Result> {
65 | file_manager.create_file(path)
66 | }
67 |
68 | pub fn is_file_exists(path: &str, file_manager: &dyn FileManager) -> Result {
69 | file_manager.is_file_exists(path)
70 | }
71 |
72 | pub fn delete_file(path: &str, file_manager: &dyn FileManager) -> Result<()> {
73 | file_manager.delete_file(path)
74 | }
75 |
--------------------------------------------------------------------------------
/src/Rust/src/models.rs:
--------------------------------------------------------------------------------
1 | use anyhow::Result;
2 |
3 | use crate::{DirectoryManager, FileManager};
4 |
5 | #[derive(Clone, Debug)]
6 | pub struct FileDetail<'a> {
7 | pub file_manager: &'a dyn FileManager,
8 | pub name: String,
9 | pub path: String,
10 | pub len: u64,
11 | }
12 |
13 | impl FileDetail<'_> {
14 | pub fn new(file_manager: &dyn FileManager) -> FileDetail {
15 | FileDetail {
16 | file_manager,
17 | name: String::new(),
18 | path: String::new(),
19 | len: 0,
20 | }
21 | }
22 |
23 | pub fn full_path(&self) -> Result {
24 | self.file_manager.path_provider().combine(
25 | vec![&self.name, &self.path]
26 | )
27 | }
28 | }
29 |
30 | #[derive(Clone, Debug)]
31 | pub struct DirectoryDetail<'a> {
32 | pub dir_manager: &'a dyn DirectoryManager,
33 | pub name: String,
34 | pub path: String,
35 | }
36 |
37 | impl DirectoryDetail<'_> {
38 | pub fn new(dir_manager: &dyn DirectoryManager) -> DirectoryDetail {
39 | DirectoryDetail {
40 | dir_manager,
41 | name: String::new(),
42 | path: String::new(),
43 | }
44 | }
45 |
46 | pub fn full_path(&self) -> Result {
47 | self.dir_manager.path_provider().combine(
48 | vec![&self.name, &self.path]
49 | )
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Rust/src/providers.rs:
--------------------------------------------------------------------------------
1 | use std::fmt::Debug;
2 | use anyhow::Result;
3 | use async_trait::async_trait;
4 |
5 | use crate::models::{DirectoryDetail, FileDetail};
6 |
7 | pub trait PathProvider: Send + Sync + Debug + helper::AsAny {
8 | fn combine(&self, paths: Vec<&str>) -> Result;
9 | fn get_object_name(&self, path: &str) -> Result;
10 | fn get_object_parent_path(&self, path: &str) -> Result;
11 | }
12 |
13 | #[async_trait]
14 | pub trait DirectoryManager: Send + Sync + Debug + helper::AsAny {
15 | fn path_provider(&self) -> &dyn PathProvider;
16 | // Sync methods
17 | async fn create_dir_async(&self, path: &str) -> Result;
18 | async fn get_dir_async(&self, path: &str) -> Result;
19 | async fn is_dir_exists_async(&self, path: &str) -> Result;
20 | async fn delete_dir_async(&self, path: &str, recursive: bool) -> Result<()>;
21 | // Async methods
22 | fn create_dir(&self, path: &str) -> Result;
23 | fn get_dir(&self, path: &str) -> Result;
24 | fn is_dir_exists(&self, path: &str) -> Result;
25 | fn delete_dir(&self, path: &str, recursive: bool) -> Result<()>;
26 | }
27 |
28 | #[async_trait]
29 | pub trait FileManager: Send + Sync + Debug + helper::AsAny {
30 | fn path_provider(&self) -> &dyn PathProvider;
31 | fn dir_manager(&self) -> &dyn DirectoryManager;
32 | // Async methods
33 | async fn get_file_async(&self, path: &str) -> Result;
34 | async fn create_file_async(&self, path: &str) -> Result;
35 | async fn is_file_exists_async(&self, path: &str) -> Result;
36 | async fn delete_file_async(&self, path: &str) -> Result<()>;
37 | // Sync methods
38 | fn get_file(&self, path: &str) -> Result;
39 | fn create_file(&self, path: &str) -> Result;
40 | fn is_file_exists(&self, path: &str) -> Result;
41 | fn delete_file(&self, path: &str) -> Result<()>;
42 | }
43 |
44 |
45 | mod helper {
46 | use core::any::Any;
47 |
48 | pub trait AsAny: Any {
49 | fn as_any(&self) -> &dyn Any;
50 | fn as_any_mut(&mut self) -> &mut dyn Any;
51 | }
52 |
53 | impl AsAny for T {
54 | fn as_any(&self) -> &dyn Any {
55 | self
56 | }
57 |
58 | fn as_any_mut(&mut self) -> &mut dyn Any {
59 | self
60 | }
61 | }
62 | }
--------------------------------------------------------------------------------