1use std::fmt;
2use std::{fs, path::Path};
3
4type Result<T> = std::result::Result<T, FileTreeError>;
5
6#[derive(Debug, Clone)]
7enum FileTreeError {
8 SymlinkError(String),
9 UnknownEntryType,
10 FilePathError,
11}
12
13impl fmt::Display for FileTreeError {
14 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
15 match self {
16 FileTreeError::SymlinkError(err) => write!(f, "Symlink found {err}"),
17 FileTreeError::UnknownEntryType => write!(f, "Entry is not a File, Folder or Symlink"),
18 FileTreeError::FilePathError => write!(f, "Failed to coerce &Path into String"),
19 }
20 }
21}
22
23#[derive(Debug)]
24struct Entry {
25 name: String,
26 kind: EntryKind,
27}
28
29#[derive(Debug)]
30enum EntryKind {
31 File,
32 Folder(Vec<Entry>),
33}
34
35fn read_entry(path: &Path) -> Result<Entry> {
36 let name = path
37 .file_name()
38 .ok_or(FileTreeError::FilePathError)?
39 .to_str()
40 .ok_or(FileTreeError::FilePathError)?
41 .to_string();
42
43 let ty = fs::metadata(path).unwrap().file_type();
44 if ty.is_file() {
45 Ok(Entry {
46 name,
47 kind: EntryKind::File,
48 })
49 } else if ty.is_dir() {
50 Ok(Entry {
51 name,
52 kind: EntryKind::Folder(read_folder(path)?),
53 })
54 } else if ty.is_symlink() {
55 Err(FileTreeError::SymlinkError(name))
56 } else {
57 Err(FileTreeError::UnknownEntryType)
58 }
59}
60
61fn read_folder<P: AsRef<Path>>(path: P) -> Result<Vec<Entry>> {
62 let mut out = Vec::new();
63 for entry in fs::read_dir(path).unwrap() {
64 let entry = entry.unwrap();
65 out.push(read_entry(&entry.path())?);
66 }
67 Ok(out)
68}
69
70
71