1use crate::{Error, Etc, Meta};
3use std::{convert::AsRef, fs, ops::FnOnce, path::PathBuf};
4
5pub trait FileSystem: Meta {
7 fn drain(&self) -> Result<(), Error> {
9 let path = self.real_path()?;
10
11 if path.is_dir() {
12 fs::remove_dir_all(path)?;
13 } else {
14 fs::remove_file(path)?;
15 }
16
17 Ok(())
18 }
19
20 fn back(&self) -> Result<Etc, Error> {
22 Ok(Etc::from(self.base()?))
23 }
24
25 fn entry<F>(&self, name: &str, f: F) -> Result<(), Error>
27 where
28 F: FnOnce(Etc),
29 {
30 let mut path = self.real_path()?;
31 path.push(name);
32
33 f(path.into());
34 Ok(())
35 }
36
37 fn find(&self, src: &str) -> Result<PathBuf, Error> {
39 for f in fs::read_dir(self.real_path()?)? {
40 let path = f?.path();
41 if let Some(s) = path.file_name() {
42 if src == s {
43 return Ok(path);
44 } else if path.is_dir() {
45 let source: Etc = path.into();
46 let res = FileSystem::find(&source, src);
47 if res.is_ok() {
48 return res;
49 }
50 }
51 }
52 }
53
54 Err(Error::Custom(format!("error: {} not found", src)))
55 }
56
57 fn find_all(&self, src: &str, res: &mut Vec<PathBuf>) -> Result<(), Error> {
59 for f in fs::read_dir(self.real_path()?)? {
60 let path = f?.path();
61 if let Some(s) = path.file_name() {
62 if src == s {
63 res.push(path);
64 } else if path.is_dir() {
65 let source: Etc = path.into();
66 FileSystem::find_all(&source, src, res)?;
67 }
68 }
69 }
70
71 Ok(())
72 }
73
74 fn ls(&self) -> Result<Vec<String>, Error> {
76 let mut res = vec![];
77 for f in fs::read_dir(self.real_path()?)? {
78 if let Some(name) = f?.path().file_name() {
79 if let Ok(string) = name.to_os_string().into_string() {
80 res.push(string);
81 } else {
82 return Err(Error::Custom(format!(
83 "error: convert OsString {:?} failed",
84 name,
85 )));
86 }
87 } else {
88 return Err(Error::Custom(format!(
89 "error: ls {} failed",
90 self.real_path()?.to_string_lossy()
91 )));
92 }
93 }
94
95 Ok(res)
96 }
97
98 fn mkdir<P>(&self, path: P) -> Result<(), Error>
100 where
101 P: AsRef<str>,
102 {
103 let mut dir = self.real_path()?;
104 dir.push(path.as_ref());
105 if !dir.exists() {
106 Ok(fs::create_dir_all(dir)?)
107 } else {
108 Ok(())
109 }
110 }
111
112 fn open(&self, name: &str) -> Result<Etc, Error> {
114 let mut path = self.real_path()?;
115 path.push(name);
116
117 Ok(path.into())
118 }
119
120 fn rm(&self, path: &str) -> Result<(), Error> {
122 let base = self.real_path();
123
124 if base.is_err() {
126 return Ok(());
127 }
128
129 let mut full = base?;
130 full.push(path);
131
132 if full.is_dir() {
133 fs::remove_dir_all(full)?;
134 } else {
135 fs::remove_file(full)?;
136 }
137
138 Ok(())
139 }
140}
141
142impl<T> FileSystem for T where T: Meta {}