Skip to main content

MapFS

Struct MapFS 

Source
pub struct MapFS { /* private fields */ }
Expand description

A virtual file system (VFS) implementation that stores file and directory entries in memory using a hierarchical map structure.

MapFS provides a POSIX‑like file system interface where all data is kept in‑process, allowing operations such as file creation, directory traversal, path resolution, and metadata inspection without touching the host filesystem.

§Internal state

  • root — An absolute, normalized path associated with the host that serves as the physical anchor of the virtual file system (VFS). It has no effect on VFS operation under typical usage scenarios. This path determines how virtual paths are mapped to host paths (e.g., for synchronization or persistent storage layers).

    • Must be absolute and normalized (no .., no redundant separators).
    • Example: /tmp/my_vfs_root on Unix, C:\\vfs\\root on Windows.
  • cwd — Current Working Directory, expressed as an inner absolute normalized path within the virtual file system.

    • Determines how relative paths (e.g., docs/file.txt) are resolved.
    • Always starts with / (or \ on Windows) and is normalized.
    • Default value: / (the virtual root).
    • Changed via methods like cd().
  • entries — The core storage map that holds all virtual file and directory entries.

    • Key: PathBuf representing inner absolute normalized paths (always start with /).
    • Value: Entry struct containing type, metadata, and (for files) content.

§Invariants

  1. Root existence: The path / is always present in entries and has type Directory.
  2. Path normalization: All keys in entries, as well as cwd and root, are normalized (no .., no //, trailing / removed except for root).
  3. Parent consistency: For any entry at /a/b/c, there must exist an entry /a/b of type Directory (except for the root /).
  4. Uniqueness: No duplicate paths; each path maps to exactly one Entry.

§Lifecycle

  • On creation: root and cwd is set to /. If you want, you may set root to a user‑supplied host path;
  • As files/directories are added via methods (e.g., mkfile(), mkdir(), add()), they are inserted into entries with inner absolute paths.
  • Path resolution (e.g., in is_file(), ls()) combines cwd with input paths to produce inner absolute paths before querying entries.

§Thread Safety

This struct is not thread‑safe by default. If concurrent access is required, wrap it in a synchronization primitive (e.g., Arc<Mutex<MapFS>> or RwLock<MapFS>) at the application level.

§Example

let fs = MapFS::new();

fs.mkdir("/docs").unwrap();
fs.mkfile("/docs/note.txt", Some(b"Hello")).unwrap();

assert!(fs.exists("/docs/note.txt"));

fs.rm("/docs/note.txt").unwrap();

Implementations§

Source§

impl MapFS

Source

pub fn new() -> Self

Creates new MapFS instance. By default, the root directory and current working directory are set to /.

Source

pub fn set_root<P: AsRef<Path>>(&mut self, path: P) -> Result<()>

Changes root path.

  • path must be an absolute If path isn’t an absolute error returns.

Trait Implementations§

Source§

impl FsBackend for MapFS

Source§

fn root(&self) -> &Path

Returns root path.

Source§

fn cwd(&self) -> &Path

Returns current working directory related to the vfs root.

Source§

fn to_host<P: AsRef<Path>>(&self, inner_path: P) -> Result<PathBuf>

Returns a hypothetical “host-path” joining root and inner_path.

  • inner_path must exist in VFS
Source§

fn cd<P: AsRef<Path>>(&mut self, path: P) -> Result<()>

Changes the current working directory.

  • path can be in relative or absolute form, but in both cases it must exist in VFS. An error is returned if the specified path does not exist.
Source§

fn exists<P: AsRef<Path>>(&self, path: P) -> bool

Checks if a path exists in the VFS. The path can be in relative or absolute form.

Source§

fn is_dir<P: AsRef<Path>>(&self, path: P) -> Result<bool>

Checks if path is a directory.

Source§

fn is_file<P: AsRef<Path>>(&self, path: P) -> Result<bool>

Checks if path is a regular file.

Source§

fn ls<P: AsRef<Path>>(&self, path: P) -> Result<impl Iterator<Item = &Path>>

Returns an iterator over directory entries at a specific depth (shallow listing).

This method lists only the immediate children of the given directory, i.e., entries that are exactly one level below the specified path. It does not recurse into subdirectories (see tree() if you need recurse).

§Arguments
  • path - path to the directory to list (must exist in VFS).
§Returns
  • Ok(impl Iterator<Item = &Path>) - Iterator over entries of immediate children (relative to VFS root). The yielded paths are inside the target directory but do not include deeper nesting.
  • Err(anyhow::Error) - If the specified path does not exist in VFS.
§Example:
 fs.mkdir("/docs/subdir");
 fs.mkfile("/docs/document.txt", None);

 // List root contents
 for path in fs.ls("/").unwrap() {
     println!("{:?}", path);
 }

 // List contents of "/docs"
 for path in fs.ls("/docs").unwrap() {
     if path.is_file() {
         println!("File: {:?}", path);
     } else {
         println!("Dir:  {:?}", path);
     }
 }
§Notes
  • No recursion: Unlike tree(), this method does not traverse subdirectories.
  • Path ownership: The returned iterator borrows from the VFS’s internal state. It is valid as long as self lives.
  • Excludes root: The input directory itself is not included in the output.
  • Error handling: If path does not exist, an error is returned before iteration.
  • Performance: The filtering is done in‑memory; no additional filesystem I/O occurs during iteration.
Source§

fn tree<P: AsRef<Path>>(&self, path: P) -> Result<impl Iterator<Item = &Path>>

Returns a recursive iterator over the directory tree starting from a given path.

The iterator yields all entries (files and directories) that are inside the specified directory (i.e., the starting directory itself is not included).

§Arguments
  • path - path to the directory to traverse (must exist in VFS).
§Returns
  • Ok(impl Iterator<Item = &Path>) - Iterator over all entries within the tree (relative to VFS root), excluding the root of the traversal.
  • Err(anyhow::Error) - If:
    • The specified path does not exist in VFS.
    • The path is not a directory (implicitly checked via exists and tree structure).
§Behavior
  • Recursive traversal: Includes all nested files and directories.
  • Excludes root: The starting directory path is not yielded (only its contents).
  • Path normalization: Input path is normalized.
  • VFS-only: Only returns paths tracked in VFS.
  • Performance: The filtering is done in‑memory; no additional filesystem I/O occurs during iteration.
§Example:
fs.mkdir("/docs/subdir");
fs.mkfile("/docs/document.txt", None);

// Iterate over current working directory
for path in fs.tree("/").unwrap() {
    println!("{:?}", path);
}

// Iterate over a specific directory
for path in fs.tree("/docs").unwrap() {
    if path.is_file() {
        println!("File: {:?}", path);
    }
}
§Notes
  • The iterator borrows data from VFS. The returned iterator is valid as long as self is alive.
  • Symbolic links are treated as regular entries (no follow/resolve).
  • Use MapFS methods (e.g., is_file(), is_dir()) for yielded items for type checks.
Source§

fn mkdir<P: AsRef<Path>>(&mut self, path: P) -> Result<()>

Creates directory and all it parents (if needed).

  • path - inner vfs path.
Source§

fn mkfile<P: AsRef<Path>>( &mut self, file_path: P, content: Option<&[u8]>, ) -> Result<()>

Creates new file in VFS.

  • file_path must be inner VFS path. It must contain the name of the file, optionally preceded by parent directory. If the parent directory does not exist, it will be created.
Source§

fn read<P: AsRef<Path>>(&self, path: P) -> Result<Vec<u8>>

Reads the entire contents of a file into a byte vector.

  • path is the inner VFS path.
§Returns
  • Ok(Vec<u8>) - File content as a byte vector if successful.
  • Err(anyhow::Error) - If any of the following occurs:
    • File does not exist in VFS (file does not exist: ...)
    • Path points to a directory (... is a directory)
§Notes
  • Does not follow symbolic links on the host filesystem (reads the link itself).
  • Returns an empty vector for empty files.
Source§

fn write<P: AsRef<Path>>(&mut self, path: P, content: &[u8]) -> Result<()>

Writes bytes to an existing file, replacing its entire contents.

  • path - Path to the file.
  • content - Byte slice (&[u8]) to write to the file.
§Returns
  • Ok(()) - If the write operation succeeded.
  • Err(anyhow::Error) - If any of the following occurs:
    • File does not exist in VFS (file does not exist: ...)
    • Path points to a directory (... is a directory)
§Behavior
  • Overwrites completely: The entire existing content is replaced.
  • No file creation: File must exist (use mkfile() first).
Source§

fn append<P: AsRef<Path>>(&mut self, path: P, content: &[u8]) -> Result<()>

Appends bytes to the end of an existing file, preserving its old contents.

§Arguments
  • path - Path to the existing file.
  • content - Byte slice (&[u8]) to append to the file.
§Returns
  • Ok(()) - If the append operation succeeded.
  • Err(anyhow::Error) - If any of the following occurs:
    • File does not exist in VFS (file does not exist: ...)
    • Path points to a directory (... is a directory)
§Behavior
  • Appends only: Existing content is preserved; new bytes are added at the end.
  • File creation: Does NOT create the file if it doesn’t exist (returns error).
Source§

fn rm<P: AsRef<Path>>(&mut self, path: P) -> Result<()>

Removes a file or directory at the specified path.

  • path: can be absolute (starting with ‘/’) or relative to the current working directory (cwd). If the path is a directory, all its contents are removed recursively.

Returns:

  • Ok(()) on successful removal.
  • Err(_) if the path does not exist in the VFS;
Source§

fn cleanup(&mut self) -> bool

Removes all artifacts (dirs and files) in vfs.

Auto Trait Implementations§

§

impl Freeze for MapFS

§

impl RefUnwindSafe for MapFS

§

impl Send for MapFS

§

impl Sync for MapFS

§

impl Unpin for MapFS

§

impl UnsafeUnpin for MapFS

§

impl UnwindSafe for MapFS

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.