mmap-guard#
Safe, guarded memory-mapped file I/O for Rust. Wraps memmap2::Mmap::map() behind a safe API so downstream crates can use #![forbid(unsafe_code)] while still benefiting from zero-copy file access.
Why mmap-guard?#
Projects that enforce #![forbid(unsafe_code)] can't call memmap2::Mmap::map() directly, because it's unsafe. The usual fallback, std::fs::read(), copies the whole file onto the heap, which doesn't work for disk images or multi-gigabyte binaries.
mmap-guard puts that one unsafe call in a single crate, so the testing and fuzzing can concentrate on one place. Consumers get those protections without having to reason about mmap safety themselves.
Features#
- Safe mmap construction β wraps
memmap2::Mmap::map()with pre-flight checks (empty file detection, permission errors) - Advisory file locking β acquires a shared advisory lock (via
fs4) before mapping; returnsio::ErrorKind::WouldBlockon lock contention - Platform quirk mitigation β documents and (where possible) mitigates SIGBUS/access violations from file truncation
- Unified read API β returns
&[u8]whether backed by mmap or a heap buffer (for stdin/non-seekable inputs) - Zero unsafe for consumers β exactly one
unsafeblock, fully documented with a// SAFETY:comment - Minimal dependencies β
memmap2andfs4at runtime
Quick Start#
Installation#
Add to your Cargo.toml:
[dependencies]
mmap-guard = "0.1"
Usage#
use mmap_guard::map_file;
// Memory-map a file β returns FileData that derefs to &[u8]
let data = map_file("large-file.bin")?;
assert!(!data.is_empty());
// Use it like any byte slice
println!("first byte: {:#04x}", data[0]);
For CLI tools that accept both file paths and stdin:
use mmap_guard::load;
// load() handles both file paths and stdin ("-" with a 1 GiB default cap).
let data = load("input.txt")?;
// For a custom stdin byte limit, call load_stdin directly:
// use mmap_guard::load_stdin;
// let data = load_stdin(Some(10 * 1024 * 1024))?; // 10 MiB cap
// let data = load_stdin(None)?; // unlimited
Architecture#
| Module | Purpose |
|---|---|
src/lib.rs | Crate-level docs, re-exports public API |
src/map.rs | map_file() with pre-flight stat check; the single unsafe block |
src/load.rs | load() routes "-" to load_stdin(), others to map_file() |
src/file_data.rs | FileData enum (Mapped(Mmap, File) / Loaded), Deref, AsRef |
What It Does NOT Do#
- Provide mutable/writable mappings
- Abstract over async I/O
- Implement its own mmap syscalls (delegates entirely to
memmap2)
Safety#
This crate contains exactly one unsafe block β the call to memmap2::Mmap::map(). The safety contract is maintained through:
- File opened read-only (
File::open()) - Shared advisory lock acquired via
fs4before mapping β contention returnsio::ErrorKind::WouldBlock - File descriptor and lock held through ownership in
FileData::Mapped(Mmap, File)β released on drop - No mutable aliasing (read-only mappings only)
#![deny(clippy::undocumented_unsafe_blocks)]enforced
See the safety documentation for the full contract and known limitations (SIGBUS from concurrent file truncation).
Security#
- Strict linting β pedantic/nursery/cargo clippy groups,
unwrap_useddenied,panicdenied - Dependency auditing β
cargo auditandcargo denyin CI - Coverage threshold β 80%+ project coverage enforced
- Supply chain β OpenSSF Scorecard monitoring
Documentation#
- Developer Guide β mdBook documentation
- API Reference β docs.rs
- GitHub Issues
Contributing#
See CONTRIBUTING.md for development setup and guidelines.
License#
Licensed under either of Apache License 2.0 or MIT License, at your option.
Acknowledgments#
- memmap2 for the underlying memory-mapping implementation