github crates.io docs.rs

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 - WASM support

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"); ```

Note: using LocalFS requires the localfs feature

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.

WASM

For WASM builds, the Send and Sync bounds are removed from all parts of the interface.