Preloader
A high-performance asynchronous data preloader library for Rust that provides efficient caching and concurrent access patterns.
Features
- 🚀 Asynchronous Loading: Load data asynchronously using Rust's
Futuretrait - 💾 Smart Caching: Once loaded, data is cached in memory for instant access
- 🔒 Thread Safe: Safe concurrent access across multiple threads
- 📊 State Management: Clear state-based behavior (Idle, Start, Loading, Loaded)
- ⚡ Non-blocking: Optional non-blocking data retrieval with
try_get() - 🔄 Idempotent: Multiple load calls are safely ignored after the first one
- 🛡️ Memory Safe: Uses Rust's type system for compile-time safety
- ⚡ Performance: Unsafe unchecked methods for zero-cost abstractions
Quick Start
Add this to your Cargo.toml:
[]
= "0.1.0"
= { = "1.0", = ["full"] }
= "1.0"
Basic Usage
use Preloader;
use tokio;
async
Advanced Usage
use Preloader;
use Arc;
use tokio;
async
API Reference
Preloader<T>
The main preloader struct that handles asynchronous data loading and caching.
Methods
new() -> Preloader<T>- Create a new preloader instanceload(future: impl Future<Output = T> + Send + 'static) -> ()- Start loading data asynchronouslyget() -> Result<&T, PreloaderError>- Get data (blocks until ready)try_get() -> Result<&T, PreloaderError>- Try to get data (non-blocking)get_unchecked() -> &T- Get data without checks (unsafe, panics if not ready)try_get_unchecked() -> &T- Try to get data without checks (unsafe, panics if not ready)
Error Types
Type Aliases
type Result<T> = Result;
Performance Characteristics
- Memory Overhead: Minimal - only stores the loaded data and state
- Concurrency: Excellent - supports unlimited concurrent readers
- Latency: Near-zero for cached data access
- Thread Safety: Full
Send + Syncimplementation - Atomic Operations: Uses atomic state transitions for optimal performance
- Zero-Cost Abstractions: Unsafe unchecked methods for maximum performance
Use Cases
- Configuration Loading: Load app configuration once, access everywhere
- Database Connections: Preload connection pools
- File Caching: Cache frequently accessed files
- API Response Caching: Cache external API responses
- Resource Initialization: Initialize heavy resources on startup
- Lazy Loading: Load expensive resources only when first accessed
- High-Performance Systems: Use unchecked methods in performance-critical paths
Examples
Configuration Loading
use Preloader;
use ;
async
Database Connection Pool
use Preloader;
use PgPool;
async
High-Performance Access Pattern
use Preloader;
use Arc;
Lazy Resource Loading
use Preloader;
use Arc;
State Transitions
The preloader follows a clear state machine:
- Idle → Start: When
load()is first called - Start → Loading: When the future is spawned
- Loading → Loaded: When the future completes successfully
- Idle/Start → Idle: When
load()is called again (ignored)
Thread Safety
The Preloader is designed for concurrent access:
- Multiple Readers: Unlimited concurrent
get()andtry_get()calls - Single Writer: Only one
load()call is processed - Atomic State: State transitions are atomic and lock-free
- Memory Ordering: Uses appropriate memory ordering for performance
Safety Considerations
Safe Methods
get()- Always safe, blocks until data is readytry_get()- Always safe, returns error if not ready
Unsafe Methods
get_unchecked()- Unsafe: Panics if data is not loadedtry_get_unchecked()- Unsafe: Panics if data is not loaded
Use unsafe methods only when you are absolutely certain the data is loaded and ready.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
Development Setup
Running Tests
# Run all tests
# Run tests with output
# Run specific test
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
- Built with Tokio for async runtime
- Uses atomic-enum for atomic state management
- Uses thiserror for error handling
- Inspired by modern caching patterns and concurrent programming best practices
Made with ❤️ in Rust