-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add virtualfs crate with filesystem abstraction (#136)
* feat: add virtualfs crate with filesystem abstraction Add a new virtualfs crate that provides a generic virtual filesystem interface and an in-memory implementation. This abstraction will allow for different filesystem implementations while maintaining a consistent interface. Key changes: - Add virtualfs crate with VirtualFileSystem trait - Implement MemoryFileSystem as reference implementation - Add comprehensive test coverage for MemoryFileSystem - Fix error handling in monofs FsError::Custom - Add cfg-if as workspace dependency The virtualfs crate provides: - Async filesystem operations (read, write, create, delete, etc) - Path-based access with proper validation - Support for files, directories and symlinks - Metadata handling - Comprehensive error types * refactor: format code and improve documentation examples - Add working examples for Dir::find() and Dir::find_mut() - Add examples for Metadata methods - Remove redundant VirtualFileSystem trait documentation - Fix and expand documentation examples in virtualfs - Reorganize imports to be alphabetically sorted - Group related imports using nested paths
- Loading branch information
Showing
18 changed files
with
3,586 additions
and
31 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
[package] | ||
name = "virtualfs" | ||
version = "0.1.0" | ||
description = "`virtualfs` is a library for virtual file systems." | ||
authors.workspace = true | ||
repository.workspace = true | ||
license.workspace = true | ||
edition.workspace = true | ||
|
||
[lib] | ||
name = "virtualfs" | ||
path = "lib/lib.rs" | ||
|
||
[dependencies] | ||
async-trait.workspace = true | ||
pretty-error-debug.workspace = true | ||
thiserror.workspace = true | ||
anyhow.workspace = true | ||
tokio.workspace = true | ||
futures.workspace = true | ||
chrono.workspace = true | ||
getset.workspace = true | ||
cfg-if.workspace = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
use std::{ | ||
error::Error, | ||
fmt::{self, Display}, | ||
io, | ||
path::PathBuf, | ||
}; | ||
|
||
use thiserror::Error; | ||
|
||
//-------------------------------------------------------------------------------------------------- | ||
// Types | ||
//-------------------------------------------------------------------------------------------------- | ||
|
||
/// The result of a file system operation. | ||
pub type VfsResult<T> = Result<T, VfsError>; | ||
|
||
/// An error that occurred during a file system operation. | ||
#[derive(pretty_error_debug::Debug, Error)] | ||
pub enum VfsError { | ||
/// The parent directory does not exist | ||
#[error("parent directory does not exist: {0}")] | ||
ParentDirectoryNotFound(PathBuf), | ||
|
||
/// The path already exists | ||
#[error("path already exists: {0}")] | ||
AlreadyExists(PathBuf), | ||
|
||
/// The path does not exist | ||
#[error("path does not exist: {0}")] | ||
NotFound(PathBuf), | ||
|
||
/// The path is not a directory | ||
#[error("path is not a directory: {0}")] | ||
NotADirectory(PathBuf), | ||
|
||
/// The path is not a file | ||
#[error("path is not a file: {0}")] | ||
NotAFile(PathBuf), | ||
|
||
/// The path is not a symlink | ||
#[error("path is not a symlink: {0}")] | ||
NotASymlink(PathBuf), | ||
|
||
/// Invalid offset for read/write operation | ||
#[error("invalid offset {offset} for path: {path}")] | ||
InvalidOffset { | ||
/// The path of the file | ||
path: PathBuf, | ||
|
||
/// The offset that is invalid | ||
offset: u64, | ||
}, | ||
|
||
/// Insufficient permissions to perform the operation | ||
#[error("insufficient permissions for operation on: {0}")] | ||
PermissionDenied(PathBuf), | ||
|
||
/// The filesystem is read-only | ||
#[error("filesystem is read-only")] | ||
ReadOnlyFilesystem, | ||
|
||
/// Invalid symlink target | ||
#[error("invalid symlink target: {0}")] | ||
InvalidSymlinkTarget(PathBuf), | ||
|
||
/// Empty path segment | ||
#[error("empty path segment")] | ||
EmptyPathSegment, | ||
|
||
/// Invalid path component (e.g. ".", "..", "/") | ||
#[error("invalid path component: {0}")] | ||
InvalidPathComponent(String), | ||
|
||
/// IO error during filesystem operation | ||
#[error("io error: {0}")] | ||
Io(#[from] io::Error), | ||
|
||
/// Custom error. | ||
#[error(transparent)] | ||
Custom(#[from] AnyError), | ||
} | ||
|
||
/// An error that can represent any error. | ||
#[derive(Debug)] | ||
pub struct AnyError { | ||
error: anyhow::Error, | ||
} | ||
|
||
//-------------------------------------------------------------------------------------------------- | ||
// Methods | ||
//-------------------------------------------------------------------------------------------------- | ||
|
||
impl VfsError { | ||
/// Creates a new `Err` result. | ||
pub fn custom(error: impl Into<anyhow::Error>) -> VfsError { | ||
VfsError::Custom(AnyError { | ||
error: error.into(), | ||
}) | ||
} | ||
} | ||
|
||
impl AnyError { | ||
/// Downcasts the error to a `T`. | ||
pub fn downcast<T>(&self) -> Option<&T> | ||
where | ||
T: Display + fmt::Debug + Send + Sync + 'static, | ||
{ | ||
self.error.downcast_ref::<T>() | ||
} | ||
} | ||
|
||
//-------------------------------------------------------------------------------------------------- | ||
// Functions | ||
//-------------------------------------------------------------------------------------------------- | ||
|
||
/// Creates an `Ok` `VfsResult`. | ||
#[allow(non_snake_case)] | ||
pub fn Ok<T>(value: T) -> VfsResult<T> { | ||
Result::Ok(value) | ||
} | ||
|
||
//-------------------------------------------------------------------------------------------------- | ||
// Trait Implementations | ||
//-------------------------------------------------------------------------------------------------- | ||
|
||
impl PartialEq for AnyError { | ||
fn eq(&self, other: &Self) -> bool { | ||
self.error.to_string() == other.error.to_string() | ||
} | ||
} | ||
|
||
impl Display for AnyError { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
write!(f, "{}", self.error) | ||
} | ||
} | ||
|
||
impl Error for AnyError {} |
Oops, something went wrong.