Expand description
Asynchronous file I/O operations with priority handling.
async_file
provides a simple yet powerful API for performing asynchronous file operations
in Rust. It closely follows the standard library’s file API design while adding async
support and priority-based scheduling.
§Features
- Async Operations: All file operations are asynchronous, allowing for non-blocking I/O
- Priority Scheduling: Every operation accepts a priority parameter for fine-grained control
- Memory Safety: Uses an opaque
Data
type to safely handle OS-managed memory allocations - Platform Agnostic: Backend-agnostic API with a default std implementation
§Quick Start
use async_file::{File, Priority};
// Open a file with unit test priority
let file = File::open("/dev/zero", Priority::unit_test()).await?;
// Read up to 1KB of data
let data = file.read(1024, Priority::unit_test()).await?;
println!("Read {} bytes", data.len());
§Architecture Overview
§Opaque Type Design
The library uses opaque wrapper types that hide platform-specific implementations:
File
: Wraps platform file handles behind a unified async interfaceData
: Encapsulates OS-managed memory buffers for safe async I/OMetadata
: Provides file information in a platform-agnostic wayError
: Wraps platform-specific error types
This design ensures API stability while allowing platform-specific optimizations.
§Single Operation Constraint
Important: Only one operation may be in-flight at a time per file handle.
This constraint:
- Prevents race conditions on file position
- Simplifies the implementation
- Avoids many classes of concurrency bugs
- Matches typical file I/O patterns
Attempting concurrent operations on the same file handle will result in undefined behavior.
§Memory Management Strategy
The library uses an opaque Data
type instead of user-provided buffers. This design:
- Prevents use-after-free bugs: If an async operation is cancelled (by dropping the future), the OS might still write to the buffer. OS-managed allocation prevents this.
- Enables platform optimizations: Different platforms can use their optimal memory allocation strategies.
- Simplifies the API: Users don’t need to manage buffer lifetimes across await points.
§Common Usage Patterns
§Reading a File Completely
use async_file::{File, Priority};
// For small files, use read_all()
let file = File::open("config.txt", Priority::highest_async()).await?;
let contents = file.read_all(Priority::highest_async()).await?;
// Convert to String if needed
let text = String::from_utf8(contents.into_boxed_slice().into_vec())
.expect("Invalid UTF-8");
§Sequential Reading with Seeking
use async_file::{File, Priority};
use std::io::SeekFrom;
let mut file = File::open("/dev/zero", Priority::unit_test()).await?;
// Read header (first 128 bytes)
let header = file.read(128, Priority::unit_test()).await?;
// Skip to data section at byte 1024
file.seek(SeekFrom::Start(1024), Priority::unit_test()).await?;
// Read data
let data = file.read(4096, Priority::unit_test()).await?;
§Checking File Existence Before Opening
use async_file::{exists, File, Priority};
let path = "important.dat";
if exists(path, Priority::unit_test()).await {
let file = File::open(path, Priority::highest_async()).await?;
// Process file...
} else {
eprintln!("File not found: {}", path);
}
§Priority-Based Operations
use async_file::{File, Priority};
// Critical system file - use highest priority
let system_file = File::open("/critical/system.conf",
Priority::highest_async()).await?;
// Background logging - use low priority
// For other priority levels, use Priority::new()
// Priority::new(0.2) for low priority tasks
// User-facing operation - use high priority
// Priority::new(0.8) for high priority tasks
// Unit tests - use dedicated test priority
let test_file = File::open("test_fixture.txt",
Priority::unit_test()).await?;
§Platform Support
- Unix/Linux/macOS: Uses
blocking
crate to runstd::fs
operations in a thread pool - WASM: Uses web fetch API for remote file access (requires
set_default_origin
) - Windows: Same as Unix implementation using
blocking
crate
§Design Philosophy
This library enforces that only one operation may be in-flight at a time per file handle. This constraint simplifies the implementation and prevents many classes of concurrency bugs.
The library uses opaque types (File
, Data
, Metadata
) that wrap platform-specific
implementations, providing a clean abstraction layer while maintaining efficiency.
Structs§
- Data
- An opaque buffer type that holds data read from files.
- Error
- An error that can occur during file operations.
- File
- A handle to an open file for asynchronous I/O operations.
- Metadata
- Metadata information about a file.
Functions§
- exists
- Tests if a file or directory exists at the given path.
- set_
default_ origin - Sets the default origin for WASM file operations.
Type Aliases§
- Priority
- A priority value for scheduling file operations.