An async virtual filesystem interface in Rust.

Lunchbox provides a common interface that can be used to interact with any filesystem (e.g. a local FS, in-memory FS, zip filesystem, etc). This interface closely matches tokio::fs:: so it's easy to get started with.

High level features: - Support for read only filesystems and read/write filesystems - A built-in implementation for local filesystems - An async interface

Getting started

Add lunchbox to your Cargo.toml:

toml [dependencies] lunchbox = "0.1"

Step 1: Load a filesystem

At its core, Lunchbox provides a ReadableFileSystem and a WritableFileSystem trait. These traits provide analogues for all the functions available in tokio::fs.

We'll use the built in LocalFS, but you can use anything that implements one of the filesystem traits above.

```rust use lunchbox::ReadableFileSystem; use lunchbox::LocalFS;

// Create a lunchbox filesystem that uses the root of your local filesystem as its root let local_fs = LocalFS::new();

// Create a lunchbox filesystem that uses /tmp as its root. // /some/path inside the filesystem would be translated to /tmp/some/path // on your local filesystem let localfs = LocalFS::withbase_dir("/tmp"); ```

Step 2: Use it instead of tokio::fs::...

Instead of rust tokio::fs::canonicalize("/some/path").await

you'd write

rust local_fs.canonicalize("/some/path").await

Details

Paths

We can't use std::path::Path directly because it contains methods that directly access the filesystem (e.g. exists) and is not portable across OSs (e.g. a path on Windows is different than a path on Unix).

As an alternative, we use the relative_path crate to give us platform-independent paths. We also provide an extension trait (LunchboxPathUtils) to add methods like exists. This is available as lunchbox::path::Path and lunchbox::path::PathBuf.

Methods in the lunchbox traits generally accept anything that implements AsRef<lunchbox::path::Path>. This means you can use str or String directly as you would with standard library paths. See the relative_path docs for more details.

Trait methods

In the below methods, note that PathType is just an alias for AsRef<lunchbox::path::Path> + Send.

ReadableFileSystem contains the following methods ```rust // Open a file async fn open(&self, path: impl PathType) -> Result where Self::FileType: ReadableFile;

// These are almost identical to tokio::fs::... async fn canonicalize(&self, path: impl PathType) -> Result; async fn metadata(&self, path: impl PathType) -> Result; async fn read(&self, path: impl PathType) -> Result>; async fn readdir(&self, path: impl PathType) -> Result; async fn readlink(&self, path: impl PathType) -> Result; async fn readtostring(&self, path: impl PathType) -> Result; async fn symlink_metadata(&self, path: impl PathType) -> Result; ```

WritableFileSystem contains ```rust // Create a file async fn create(&self, path: impl PathType) -> Result where Self::FileType: WritableFile;

// Open a file with options async fn openwithopts( &self, opts: &OpenOptions, path: impl PathType, ) -> Result where Self::FileType: WritableFile;

// These are almost identical to tokio::fs::... async fn copy(&self, from: impl PathType, to: impl PathType) -> Result; async fn createdir(&self, path: impl PathType) -> Result<()>; async fn createdirall(&self, path: impl PathType) -> Result<()>; async fn hardlink(&self, src: impl PathType, dst: impl PathType) -> Result<()>; async fn removedir(&self, path: impl PathType) -> Result<()>; async fn removedirall(&self, path: impl PathType) -> Result<()>; async fn removefile(&self, path: impl PathType) -> Result<()>; async fn rename(&self, from: impl PathType, to: impl PathType) -> Result<()>; async fn set_permissions(&self, path: impl PathType, perm: Permissions) -> Result<()>; async fn symlink(&self, src: impl PathType, dst: impl PathType) -> Result<()>; async fn write(&self, path: impl PathType, contents: impl AsRef<[u8]> + Send) -> Result<()>; ```

These work with ReadableFiles and WritableFiles respectively:

```rust /// A readable file

[async_trait]

pub trait ReadableFile: AsyncRead where Self: Sized, { // These are almost identical to tokio::fs::File::... async fn metadata(&self) -> Result; async fn try_clone(&self) -> Result; }

/// A file that supports both reads and writes

[async_trait]

pub trait WritableFile: ReadableFile + AsyncWrite { // These are almost identical to tokio::fs::File::... async fn syncall(&self) -> Result<()>; async fn syncdata(&self) -> Result<()>; async fn setlen(&self, size: u64) -> Result<()>; async fn setpermissions(&self, perm: Permissions) -> Result<()>; } ```

Note that all WritableFiles must be ReadableFiles and all WritableFileSystems must be ReadableFileSystems as well.