1use anyfs_backend::*;
9use std::collections::HashMap;
10use std::io::{Read, Write};
11use std::path::{Path, PathBuf};
12use std::sync::RwLock;
13use std::time::SystemTime;
14
15struct SimpleFs {
24 files: RwLock<HashMap<PathBuf, Vec<u8>>>,
25 dirs: RwLock<std::collections::HashSet<PathBuf>>,
26}
27
28impl SimpleFs {
29 fn new() -> Self {
30 let fs = Self {
31 files: RwLock::new(HashMap::new()),
32 dirs: RwLock::new(std::collections::HashSet::new()),
33 };
34 fs.dirs.write().unwrap().insert(PathBuf::from("/"));
36 fs
37 }
38}
39
40impl FsRead for SimpleFs {
42 fn read(&self, path: &Path) -> Result<Vec<u8>, FsError> {
43 self.files
44 .read()
45 .unwrap()
46 .get(path)
47 .cloned()
48 .ok_or_else(|| FsError::NotFound {
49 path: path.to_path_buf(),
50 })
51 }
52
53 fn read_to_string(&self, path: &Path) -> Result<String, FsError> {
54 let bytes = self.read(path)?;
55 String::from_utf8(bytes).map_err(|_| FsError::InvalidData {
56 path: path.to_path_buf(),
57 details: "not valid UTF-8".into(),
58 })
59 }
60
61 fn read_range(&self, path: &Path, offset: u64, len: usize) -> Result<Vec<u8>, FsError> {
62 let data = self.read(path)?;
63 let start = offset as usize;
64 if start >= data.len() {
65 return Ok(Vec::new());
66 }
67 let end = (start + len).min(data.len());
68 Ok(data[start..end].to_vec())
69 }
70
71 fn exists(&self, path: &Path) -> Result<bool, FsError> {
72 Ok(self.files.read().unwrap().contains_key(path)
73 || self.dirs.read().unwrap().contains(path))
74 }
75
76 fn metadata(&self, path: &Path) -> Result<Metadata, FsError> {
77 if self.dirs.read().unwrap().contains(path) {
78 Ok(Metadata {
79 file_type: FileType::Directory,
80 size: 0,
81 permissions: Permissions::default_dir(),
82 created: SystemTime::UNIX_EPOCH,
83 modified: SystemTime::UNIX_EPOCH,
84 accessed: SystemTime::UNIX_EPOCH,
85 inode: 0,
86 nlink: 1,
87 })
88 } else if let Some(data) = self.files.read().unwrap().get(path) {
89 Ok(Metadata {
90 file_type: FileType::File,
91 size: data.len() as u64,
92 permissions: Permissions::default_file(),
93 created: SystemTime::UNIX_EPOCH,
94 modified: SystemTime::UNIX_EPOCH,
95 accessed: SystemTime::UNIX_EPOCH,
96 inode: 0,
97 nlink: 1,
98 })
99 } else {
100 Err(FsError::NotFound {
101 path: path.to_path_buf(),
102 })
103 }
104 }
105
106 fn open_read(&self, path: &Path) -> Result<Box<dyn Read + Send>, FsError> {
107 let data = self.read(path)?;
108 Ok(Box::new(std::io::Cursor::new(data)))
109 }
110}
111
112impl FsWrite for SimpleFs {
114 fn write(&self, path: &Path, data: &[u8]) -> Result<(), FsError> {
115 self.files
116 .write()
117 .unwrap()
118 .insert(path.to_path_buf(), data.to_vec());
119 Ok(())
120 }
121
122 fn append(&self, path: &Path, data: &[u8]) -> Result<(), FsError> {
123 self.files
124 .write()
125 .unwrap()
126 .entry(path.to_path_buf())
127 .or_default()
128 .extend_from_slice(data);
129 Ok(())
130 }
131
132 fn remove_file(&self, path: &Path) -> Result<(), FsError> {
133 self.files
134 .write()
135 .unwrap()
136 .remove(path)
137 .map(|_| ())
138 .ok_or_else(|| FsError::NotFound {
139 path: path.to_path_buf(),
140 })
141 }
142
143 fn rename(&self, from: &Path, to: &Path) -> Result<(), FsError> {
144 let mut files = self.files.write().unwrap();
145 let data = files.remove(from).ok_or_else(|| FsError::NotFound {
146 path: from.to_path_buf(),
147 })?;
148 files.insert(to.to_path_buf(), data);
149 Ok(())
150 }
151
152 fn copy(&self, from: &Path, to: &Path) -> Result<(), FsError> {
153 let data = self.read(from)?;
154 self.write(to, &data)
155 }
156
157 fn truncate(&self, path: &Path, size: u64) -> Result<(), FsError> {
158 let mut files = self.files.write().unwrap();
159 let data = files.get_mut(path).ok_or_else(|| FsError::NotFound {
160 path: path.to_path_buf(),
161 })?;
162 data.resize(size as usize, 0);
163 Ok(())
164 }
165
166 fn open_write(&self, _path: &Path) -> Result<Box<dyn Write + Send>, FsError> {
167 Ok(Box::new(std::io::Cursor::new(Vec::new())))
168 }
169}
170
171impl FsDir for SimpleFs {
173 fn read_dir(&self, path: &Path) -> Result<ReadDirIter, FsError> {
174 if !self.dirs.read().unwrap().contains(path) {
175 return Err(FsError::NotFound {
176 path: path.to_path_buf(),
177 });
178 }
179
180 let mut entries = Vec::new();
181
182 for (file_path, data) in self.files.read().unwrap().iter() {
184 if let Some(parent) = file_path.parent() {
185 if parent == path {
186 if let Some(name) = file_path.file_name() {
187 entries.push(Ok(DirEntry {
188 name: name.to_string_lossy().into_owned(),
189 path: file_path.clone(),
190 file_type: FileType::File,
191 size: data.len() as u64,
192 inode: 0,
193 }));
194 }
195 }
196 }
197 }
198
199 for dir_path in self.dirs.read().unwrap().iter() {
201 if let Some(parent) = dir_path.parent() {
202 if parent == path && dir_path != path {
203 if let Some(name) = dir_path.file_name() {
204 entries.push(Ok(DirEntry {
205 name: name.to_string_lossy().into_owned(),
206 path: dir_path.clone(),
207 file_type: FileType::Directory,
208 size: 0,
209 inode: 0,
210 }));
211 }
212 }
213 }
214 }
215
216 Ok(ReadDirIter::from_vec(entries))
217 }
218
219 fn create_dir(&self, path: &Path) -> Result<(), FsError> {
220 let mut dirs = self.dirs.write().unwrap();
221 if dirs.contains(path) {
222 return Err(FsError::AlreadyExists {
223 path: path.to_path_buf(),
224 operation: "create_dir",
225 });
226 }
227 dirs.insert(path.to_path_buf());
228 Ok(())
229 }
230
231 fn create_dir_all(&self, path: &Path) -> Result<(), FsError> {
232 let mut current = PathBuf::new();
233 for component in path.components() {
234 current.push(component);
235 self.dirs.write().unwrap().insert(current.clone());
236 }
237 Ok(())
238 }
239
240 fn remove_dir(&self, path: &Path) -> Result<(), FsError> {
241 if !self.dirs.write().unwrap().remove(path) {
242 return Err(FsError::NotFound {
243 path: path.to_path_buf(),
244 });
245 }
246 Ok(())
247 }
248
249 fn remove_dir_all(&self, path: &Path) -> Result<(), FsError> {
250 self.dirs.write().unwrap().remove(path);
251 self.files
252 .write()
253 .unwrap()
254 .retain(|p, _| !p.starts_with(path));
255 Ok(())
256 }
257}
258
259fn main() {
264 println!("=== anyfs-backend Basic Usage Example ===\n");
265
266 let fs = SimpleFs::new();
268
269 println!("1. Writing files...");
271 fs.write(Path::new("/hello.txt"), b"Hello, World!").unwrap();
272 fs.write(Path::new("/data.bin"), &[0x00, 0x01, 0x02, 0x03])
273 .unwrap();
274 println!(" Created /hello.txt and /data.bin");
275
276 println!("\n2. Reading files...");
278 let text = fs.read_to_string(Path::new("/hello.txt")).unwrap();
279 println!(" /hello.txt contains: {text}");
280
281 let binary = fs.read(Path::new("/data.bin")).unwrap();
282 println!(" /data.bin contains: {binary:?}");
283
284 println!("\n3. Checking existence...");
286 println!(
287 " /hello.txt exists: {}",
288 fs.exists(Path::new("/hello.txt")).unwrap()
289 );
290 println!(
291 " /missing.txt exists: {}",
292 fs.exists(Path::new("/missing.txt")).unwrap()
293 );
294
295 println!("\n4. Getting metadata...");
297 let meta = fs.metadata(Path::new("/hello.txt")).unwrap();
298 println!(
299 " /hello.txt: type={:?}, size={}",
300 meta.file_type, meta.size
301 );
302
303 println!("\n5. Directory operations...");
305 fs.create_dir(Path::new("/subdir")).unwrap();
306 fs.write(Path::new("/subdir/nested.txt"), b"Nested file")
307 .unwrap();
308
309 println!(" Created /subdir/nested.txt");
310 println!(" Contents of /:");
311 for entry in fs.read_dir(Path::new("/")).unwrap() {
312 let entry = entry.unwrap();
313 println!(" - {} ({:?})", entry.name, entry.file_type);
314 }
315
316 println!("\n6. Copy and rename...");
318 fs.copy(Path::new("/hello.txt"), Path::new("/hello_copy.txt"))
319 .unwrap();
320 fs.rename(Path::new("/hello_copy.txt"), Path::new("/greeting.txt"))
321 .unwrap();
322 println!(" Copied /hello.txt to /greeting.txt (via rename)");
323
324 println!("\n7. Appending to files...");
326 fs.append(Path::new("/hello.txt"), b" Appended!").unwrap();
327 let updated = fs.read_to_string(Path::new("/hello.txt")).unwrap();
328 println!(" /hello.txt now contains: {updated}");
329
330 println!("\n8. Error handling...");
332 match fs.read(Path::new("/nonexistent.txt")) {
333 Ok(_) => println!(" Unexpected success"),
334 Err(FsError::NotFound { path }) => {
335 println!(" Correctly got NotFound for: {}", path.display());
336 }
337 Err(e) => println!(" Unexpected error: {e}"),
338 }
339
340 println!("\n9. Using generic functions...");
342 fn count_files<B: Fs>(fs: &B, dir: &Path) -> usize {
343 fs.read_dir(dir)
344 .map(|iter| iter.filter(|e| e.is_ok()).count())
345 .unwrap_or(0)
346 }
347 println!(" Files in /: {}", count_files(&fs, Path::new("/")));
348
349 println!("\n=== Example complete! ===");
350}