PathBuf into directory structure, virtual filesystem

If I have multiple PathBuf's (in memory, this is not a stored filesystem), is there a library to create a filesystem struct so that I can walk the directory tree?

Such that

[
    PathBuf::from("one/two/file1");
    PathBuf::from("one/file2");
    PathBuf::from("file3");
]

turns into some sort of:

for dir in dirs {
    for file in dir.files {
    }
}

I recently made a crate for manipulating path-like objects (that don't necessarily point to existing files), but it's going to change soon (because I'm writting my own alternative to the Rust Standard Library). https://docs.rs/rialight_filesystem/1.0.0/rialight_filesystem/, it'd look like this:

use rialight_filesystem::File;

// dirs: Vec<File>
for dir in dirs {
    for file in dir.get_directory_listing()? {
        // file: File
    }
}

Is that what you wanted? (As I said, File is a path-like object. It points to either a file, directory or nothing (in case it points to a non-existing resource).)

I have to check and see here.. Your code failed to compile:

fn main() {
    use rialight_filesystem::File;

    let dirs = [
        File::new("a/b/file"),
        File::new("a/c"),
        File::new("file"),
    ];
    for dir in dirs {
        for file in dir.get_directory_listing()? {
            // file: File
        }
    }
}
error[E0599]: no associated item named `From` found for struct `SvStr` in the current scope
   --> /home/wcampbell/.cargo/registry/src/github.com-1ecc6299db9ec823/rialight_filesystem-1.0.0/src/path_helpers.rs:482:64
    |
482 |     path = normalize_string(path.clone(), !is_absolute, SvStr::From("/"), is_posix_path_separator);
    |

Fixed! Can you now try it again? Upgrade version to 1.0.1.

Since Path has a components() iterator, this is pretty trivial to DIY using only the standard library. The idea is to create children on the fly for each component if they don't exist, recursively:

#[derive(Debug)]
struct Node<'a> {
    name: &'a OsStr,
    children: BTreeMap<&'a OsStr, Node<'a>>,
}

impl<'a> Node<'a> {
    fn insert(&mut self, components: &[&'a OsStr]) {
        if let Some ((first, rest)) = components.split_first() {
            self.children
                .entry(first)
                .or_insert(Node { name: first, children: BTreeMap::new() })
                .insert(rest);
        }
    }
}

This Playground contains a complete example.

4 Likes

Thanks, this is exactly what I needed.