Conversation
|
Codecov Report❌ Patch coverage is ❌ Your project check has failed because the head coverage (96.9%) is below the target coverage (100.0%). You can increase the head coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #295 +/- ##
========================================
- Coverage 100.0% 96.9% -3.1%
========================================
Files 144 168 +24
Lines 8918 11358 +2440
========================================
+ Hits 8918 11007 +2089
- Misses 0 351 +351 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
2e7d9f7 to
5419b43
Compare
There was a problem hiding this comment.
Pull request overview
Adds a new file crate providing a capability-scoped, zero-copy, fully-async filesystem API (plus docs/examples/benchmarks) and wires it into the workspace.
Changes:
- Introduces the
crates/filelibrary (Directory/Root capabilities, typed file handles, dispatcher, path sandboxing, etc.). - Adds extensive integration tests, examples, and a benchmark suite for ecosystem performance comparison.
- Updates workspace metadata/docs (root README, changelog index, spelling dictionary, workspace Cargo deps).
Reviewed changes
Copilot reviewed 34 out of 36 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| crates/seatbelt/src/context.rs | Import formatting cleanup (no functional change). |
| crates/file/tests/integration.rs | Adds large integration test suite for file APIs. |
| crates/file/src/write_only_file.rs | Implements WriteOnlyFile typed handle and traits. |
| crates/file/src/shared_memory.rs | Adds type-erased, cloneable memory provider wrapper. |
| crates/file/src/root.rs | Adds Root::bind entrypoint for capability-based access. |
| crates/file/src/read_write_file.rs | Implements ReadWriteFile typed handle + rich read/write APIs. |
| crates/file/src/read_only_file.rs | Implements ReadOnlyFile typed handle + rich read APIs. |
| crates/file/src/read_dir.rs | Adds async directory iterator wrapper (ReadDir). |
| crates/file/src/path_utils.rs | Adds safe_join lexical sandboxing for relative paths. |
| crates/file/src/open_options.rs | Adds async OpenOptions builder for opening ReadWriteFile. |
| crates/file/src/lib.rs | Crate-level API surface + docs + re-exports. |
| crates/file/src/file_inner.rs | Shared file implementation: dispatching, locking, positional IO, buffer ops. |
| crates/file/src/dispatcher.rs | Adds small, auto-scaling worker pool for blocking FS calls. |
| crates/file/src/directory.rs | Implements capability-scoped directory operations and convenience read/write. |
| crates/file/src/dir_entry.rs | Adds capability-friendly DirEntry without revealing full paths. |
| crates/file/src/dir_builder.rs | Adds async DirBuilder capability-scoped directory creation. |
| crates/file/logo.png | Adds crate logo (Git LFS). |
| crates/file/favicon.ico | Adds crate favicon (Git LFS). |
| crates/file/examples/streaming_io.rs | Adds example for chunked streaming read/write. |
| crates/file/examples/positional_io.rs | Adds example for positional read/write APIs. |
| crates/file/examples/open_options.rs | Adds example for OpenOptions usage. |
| crates/file/examples/file_types.rs | Adds example for typed file handles and narrowing. |
| crates/file/examples/directory_ops.rs | Adds example for directory operations and iteration. |
| crates/file/examples/basic_read_write.rs | Adds basic bind/read/write example. |
| crates/file/benches/fs_comparison.rs | Adds Criterion benchmarks comparing against other crates. |
| crates/file/TODO.md | Adds design TODOs/questions for the new crate. |
| crates/file/README.md | Adds crate README (cargo-doc2readme generated). |
| crates/file/ECOSYSTEM-ANALYSIS.md | Adds long-form ecosystem comparison doc. |
| crates/file/Cargo.toml | Adds crate manifest (features, deps, examples, benches). |
| crates/file/CHANGELOG.md | Adds crate changelog stub. |
| crates/anyspawn/src/spawner.rs | Doc comment whitespace tweak. |
| README.md | Lists new file crate in workspace README. |
| Cargo.toml | Registers file crate + adds shared deps used by it. |
| CHANGELOG.md | Adds file crate to changelog index. |
| .spelling | Adds new allowed technical terms used in docs. |
Comments suppressed due to low confidence (2)
crates/file/tests/integration.rs:1
- This test hard-codes a Unix-specific
/tmp/...path and will fail (or behave unexpectedly) on Windows. Consider generating a guaranteed-nonexistent path from aTempDir(e.g.,tmp.path().join(\"definitely_not_here\")) or using platform-appropriate temp directory APIs to keep the test cross-platform.
crates/file/tests/integration.rs:1 - This test accepts both success and failure as valid outcomes, which makes it non-assertive and can hide regressions. It’d be better to pick and enforce one behavior (ideally: succeed, since lexical normalization keeps the path within the capability), or split into two explicit tests depending on the intended contract of
safe_join/path handling.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
crates/file/src/directory.rs
Outdated
| let mut file = File::open(&full_path)?; | ||
| let len = usize::try_from(file.metadata()?.len()).unwrap_or(usize::MAX); | ||
| let mut buf = memory.reserve(len); | ||
| let mut total = 0; | ||
| while total < len { | ||
| let n = read_into_buf(&mut file, &mut buf, len - total)?; | ||
| if n == 0 { | ||
| break; | ||
| } | ||
| total += n; | ||
| } | ||
| Ok(buf.consume_all()) |
There was a problem hiding this comment.
If metadata().len() doesn’t fit in usize (notably on 32-bit targets, or very large files), this falls back to usize::MAX and then tries to reserve that much memory, which can lead to immediate OOM/panic. Prefer either returning an explicit error when the file is too large to buffer into memory, or switching to a chunked growth strategy (reserve a reasonable initial size, then grow as reads succeed) without attempting usize::MAX upfront.
a6f2b67 to
9e77769
Compare
| // WriteOnlyFile — can write, cannot read. | ||
| let mut wf = WriteOnlyFile::create(&dir, "data.txt").await?; | ||
| let mut buf = wf.reserve(64); | ||
| buf.put_slice(*b"written via WriteOnlyFile"); |
There was a problem hiding this comment.
Can be shortened slightly as BytesView::copied_from_slice(b"blah", &wf)
| let mut buf = wf.reserve(64); | ||
| buf.put_slice(*b"written via WriteOnlyFile"); | ||
| wf.write(buf.consume_all()).await?; | ||
| wf.flush().await?; |
There was a problem hiding this comment.
What are flush() semantics here? Is it just a pass-through to OS "flush" APIs? Or does it imply that the file types have some inherent internal buffers in the Rust universe? I assume the former but we should be careful not to give the wrong impression here.
We should also try support generic buffering layers built on Read and Write traits using something like BufRead, BufWrite and that we already have in the private repo, as well as via ConcurrentRead and ConcurrentWrite (ref ConcurrentBufRead in private repo) perhaps along the lines of #292 (comments welcome).
| let dir = Root::bind(tmp.path()).await?; | ||
|
|
||
| // Create a new file for reading and writing. | ||
| let mut rw = OpenOptions::new() |
There was a problem hiding this comment.
File sharing options would also be useful to have and demonstrate (are concurrent readers/writers allowed).
| let dir = Root::bind(tmp.path()).await?; | ||
|
|
||
| // WriteOnlyPositionalFile — write-only access at explicit offsets. | ||
| let wf = WriteOnlyPositionalFile::create(&dir, "pos.txt").await?; |
There was a problem hiding this comment.
We should try ensure that this still remains compatible with Read, Write, ConcurrentRead, ConcurrentWrite traits. I suppose that could be layered on as an "operation" layer?
Something like fn write_from(&self, offset) -> WriteHead<'a> which implements Write and ConcurrentWrite for example, incrementing the offset internally as writes are accumulated?
This might also be a simple way to structure the forward-only file types internally, as limiting layers over the positional ones? If the wiring hooks up right.
| let mut rf = ReadOnlyFile::open(&dir, "stream.bin").await?; | ||
| let mut total = 0usize; | ||
| loop { | ||
| let chunk = rf.read_max(16).await?; |
There was a problem hiding this comment.
Not entirely sure what semantics of read_max are based on the example but is this not just reinventing stuff from ReadExt or Read traits? It is not clear to me why this is not just using the traits from bytesbuf_io for I/O functions.
46e5da2 to
7757211
Compare
No description provided.