# Qubit FS
[](https://github.com/qubit-ltd/rs-fs/actions/workflows/ci.yml)
[](https://qubit-ltd.github.io/rs-fs/coverage/)
[](https://crates.io/crates/qubit-fs)
[](https://www.rust-lang.org)
[](LICENSE)
[](README.zh_CN.md)
`qubit-fs` is a provider-neutral, synchronous and asynchronous filesystem
abstraction for Rust 1.94 or later. It supplies application-facing concrete
facades—`FileSystem` and `AsyncFileSystem`—instead of choosing a storage backend
or an async runtime for you.
## Installation
```toml
[dependencies]
qubit-fs = "0.2"
```
Synchronous APIs are enabled by default. Enable the asynchronous facade
explicitly when it is needed:
```toml
qubit-fs = { version = "0.2", features = ["async"] }
```
## Quick Start
A report job can keep its reads and writes on `FileSystem` while provider setup
chooses the storage authority. This executable demo creates an isolated local
root, writes a report, reads it with a 1 KiB limit, and prints `report ready`.
The temporary directory is removed when the demo ends.
```toml
[dependencies]
qubit-fs = "0.2"
qubit-fs-local = "0.10"
tempfile = "3"
```
```rust
use qubit_fs::Path;
use qubit_fs::copy::CopyExecutionRoute;
use qubit_fs::copy::CopyOptions;
use qubit_fs::directory::ListScope;
use qubit_fs::read::ReadOptions;
use qubit_fs::read::PrefixReadTermination;
use qubit_fs::write::WriteOptions;
use qubit_fs_local::LocalFileSystems;
use qubit_fs_local::LocalResourcePolicy;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let directory = tempfile::tempdir()?;
let policy = LocalResourcePolicy::standard();
let filesystem = LocalFileSystems::rooted(directory.path(), policy)?;
let path = Path::parse("/report.txt")?;
filesystem.write_all(&path, b"report ready", WriteOptions::default())?;
let bytes = filesystem.read_all(&path, ReadOptions::default(), 1024)?;
assert_eq!(b"report ready", bytes.as_slice());
let prefix = filesystem.read_prefix(&path, ReadOptions::default(), 6)?;
assert_eq!(prefix.bytes(), b"report");
assert_eq!(prefix.termination(), PrefixReadTermination::LimitReached);
let target = Path::parse("/report-copy.txt")?;
let assessment = filesystem.assess_copy(&path, &target, &CopyOptions::default())?;
assert_eq!(assessment.route(), CopyExecutionRoute::ProviderThenStream);
assert_eq!(assessment.fallback_rejection(), None);
let scope = ListScope::Path(Path::root());
let mut entries = filesystem.list(&scope, Default::default())?;
assert_eq!(entries.next_entry()?.expect("published report").path, path);
assert!(entries.next_entry()?.is_none());
println!("{}", String::from_utf8(bytes)?);
Ok(())
}
```
For a report assembled in several writes, create a temporary file under the
same logical parent, write through its returned path, and call `persist` only
when generation is complete. The final report name then stays free of
incomplete output. If publication fails, use the retained publication fact,
source qualification, and `publication_target()` to decide between retry,
cleanup, and read-only reconciliation.
## Why This Project Exists
Application code often needs the same read, write, copy, and listing workflow
across local disks, object stores, and hosted filesystems, but provider SDKs
expose different path models, error shapes, and recovery behavior. Scattering
provider details through business logic makes retries, cleanup, and cancellation
hard to reason about after a partial failure.
`qubit-fs` keeps applications on concrete `FileSystem` and `AsyncFileSystem`
facades while providers implement extension contracts under `qubit_fs::spi`.
Provider discovery, configuration, and credential handling stay in
`qubit-fs-registry`, so the core crate does not embed a backend or async runtime.
## What It Provides—and What It Does Not
The stable application surface is the public facade API, typed paths and URIs,
explicit listing scopes, bounded reads, and recovery objects that retain
publication facts across failed writes, copies, and cancellations. Detailed
workflows, error tables, and operational limits are in the user guide; provider
integration is documented separately.
The facade makes these semantics explicit:
- `Path` is a logical name inside one configured filesystem. `Uri` is the
secret-free canonical addressing form, while `ConnectionUri` is configuration
ingress: it may accept credentials but redacts them in `Display` and `Debug`.
- Default URI parsing uses the fixed standard redaction policy; pass an explicit
policy to `Uri::parse_with_policy` or `ConnectionUri::parse_with_policy` when
application-specific query names must be protected.
- Copy, rename, writes, and temporary-resource publication (including `keep`)
preserve typed recovery facts. Temporary persistence reports target
publication separately from source qualification, and
`publication_target()` retains an earlier confirmed target across rejected
retries, cleanup failures, and asynchronous cancellation. Inspect both facts
before retrying, cleaning up, or reconciling a visible target.
- `exists` returns `false` only when `stat` reports `NotFound`; permission,
authentication, timeout, and I/O failures remain errors.
- `DirectoryStream` reads entries incrementally. Consume it in a bounded loop
instead of assuming that a directory is a preloaded collection.
- Listing uses explicit `ListScope::Path` or flat `ListScope::Namespace`; prefix
reads add a byte range only when `RangeRead` is Guaranteed.
The core crate has no built-in backend and does not select an async runtime.
It does not implement cross-filesystem move, guarantee every provider capability,
or turn object keys into hierarchical paths without provider-specific rules.
Platform roots and authority boundaries come from the configured provider.
## Learn More
- [English user guide](doc/user_guide.md)
- [中文用户手册](doc/user_guide.zh_CN.md)
- [English provider guide](doc/provider_guide.md)
- [中文 provider 指南](doc/provider_guide.zh_CN.md)
- [Architecture design](doc/file_system_design.md)
- [中文架构设计](doc/file_system_design.zh_CN.md)
- [API documentation on docs.rs](https://docs.rs/qubit-fs)
- [中文 README](README.zh_CN.md)
- [Repository](https://github.com/qubit-ltd/rs-fs)
## Testing
```bash
# Run tests with the default feature set
cargo test
# Run tests with all declared features
cargo test --all-features
# Project CI checks
./ci-check.sh
# Check code coverage
./coverage.sh
```
## License
Copyright (c) 2025 - 2026. Haixing Hu. All rights reserved.
Licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for the
full license text.
## Contributing
Contributions are welcome. Please follow the Rust API guidelines, keep public
API documentation and tests current, and run `./align-ci.sh` to format code and
`./ci-check.sh` to satisfy CI requirements before submitting a pull request.
## Author
**Haixing Hu** - *Qubit Co. Ltd.*
Repository: [https://github.com/qubit-ltd/rs-fs](https://github.com/qubit-ltd/rs-fs)