file_graph_rs/
lib.rs

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