๐ Quickleaf Cache

Quickleaf Cache is a fast, lightweight, and feature-rich in-memory cache library for Rust. It combines the simplicity of a HashMap with advanced caching features like TTL (Time To Live), filtering, ordering, and event notifications.
โจ Features
- ๐ High Performance: O(1) access with ordered key iteration
- โฐ TTL Support: Automatic expiration with lazy cleanup
- ๐ Advanced Filtering: StartWith, EndWith, and complex pattern matching
- ๐ Flexible Ordering: Ascending/descending with pagination support
- ๐ Event Notifications: Real-time cache operation events
- ๐ฏ LRU Eviction: Automatic removal of least recently used items
- ๐ก๏ธ Type Safety: Full Rust type safety with generic value support
- ๐ฆ Lightweight: Minimal external dependencies
๐ฆ Installation
Add the following to your Cargo.toml
:
[dependencies]
quickleaf = "0.3"
๐ Quick Start
use quickleaf::{Quickleaf, Duration};
fn main() {
let mut cache = Quickleaf::new(1000);
cache.insert("user:123", "Alice");
cache.insert("user:456", "Bob");
println!("{:?}", cache.get("user:123"));
cache.insert_with_ttl("session:abc", "temp_data", Duration::from_secs(60));
}
๐ Usage Examples
Basic Operations
use quickleaf::Quickleaf;
fn main() {
let mut cache = Quickleaf::new(5);
cache.insert("apple", 100);
cache.insert("banana", 200);
cache.insert("cherry", 300);
println!("{:?}", cache.get("apple"));
assert!(cache.contains_key("banana"));
cache.remove("cherry").unwrap();
println!("Cache size: {}", cache.len());
println!("Is empty: {}", cache.is_empty());
}
๐ TTL (Time To Live) Features
Default TTL for All Items
use quickleaf::{Quickleaf, Duration};
fn main() {
let mut cache = Quickleaf::with_default_ttl(100, Duration::from_secs(300));
cache.insert("default_ttl", "expires in 5 min");
cache.insert_with_ttl("custom_ttl", "expires in 30 sec", Duration::from_secs(30));
println!("{:?}", cache.get("custom_ttl"));
}
Manual Cleanup
use quickleaf::{Quickleaf, Duration};
use std::thread;
fn main() {
let mut cache = Quickleaf::new(10);
cache.insert_with_ttl("temp1", "data1", Duration::from_millis(100));
cache.insert_with_ttl("temp2", "data2", Duration::from_millis(100));
cache.insert("permanent", "data3");
println!("Initial size: {}", cache.len());
thread::sleep(Duration::from_millis(150));
let removed_count = cache.cleanup_expired();
println!("Removed {} expired items", removed_count); println!("Final size: {}", cache.len()); }
๐ Advanced Filtering
Filter by Prefix
use quickleaf::{Quickleaf, ListProps, Order, Filter};
fn main() {
let mut cache = Quickleaf::new(10);
cache.insert("user:123", "Alice");
cache.insert("user:456", "Bob");
cache.insert("product:789", "Widget");
cache.insert("user:999", "Charlie");
let users = cache.list(
ListProps::default()
.filter(Filter::StartWith("user:".to_string()))
.order(Order::Asc)
).unwrap();
for (key, value) in users {
println!("{}: {}", key, value);
}
}
Filter by Suffix
use quickleaf::{Quickleaf, ListProps, Filter};
fn main() {
let mut cache = Quickleaf::new(10);
cache.insert("config.json", "{}");
cache.insert("data.json", "[]");
cache.insert("readme.txt", "docs");
cache.insert("settings.json", "{}");
let json_files = cache.list(
ListProps::default()
.filter(Filter::EndWith(".json".to_string()))
).unwrap();
println!("JSON files found: {}", json_files.len()); }
Complex Pattern Filtering
use quickleaf::{Quickleaf, ListProps, Filter, Order};
fn main() {
let mut cache = Quickleaf::new(10);
cache.insert("cache_user_data", "user1");
cache.insert("cache_product_info", "product1");
cache.insert("temp_user_session", "session1");
cache.insert("cache_user_preferences", "prefs1");
let cached_user_data = cache.list(
ListProps::default()
.filter(Filter::StartAndEndWith("cache_".to_string(), "_data".to_string()))
.order(Order::Desc)
).unwrap();
for (key, value) in cached_user_data {
println!("{}: {}", key, value);
}
}
๐ Pagination and Ordering
use quickleaf::{Quickleaf, ListProps, Order};
fn main() {
let mut cache = Quickleaf::new(100);
for i in 1..=20 {
cache.insert(format!("item_{:02}", i), i);
}
let page1 = cache.list(
ListProps::default()
.order(Order::Asc)
).unwrap();
println!("First 5 items:");
for (i, (key, value)) in page1.iter().take(5).enumerate() {
println!(" {}: {} = {}", i+1, key, value);
}
let desc_items = cache.list(
ListProps::default()
.order(Order::Desc)
).unwrap();
println!("Top 3 items (desc):");
for (key, value) in desc_items.iter().take(3) {
println!(" {}: {}", key, value);
}
}
๐ Event Notifications
use quickleaf::{Quickleaf, Event};
use std::sync::mpsc::channel;
use std::thread;
fn main() {
let (tx, rx) = channel();
let mut cache = Quickleaf::with_sender(10, tx);
let event_handler = thread::spawn(move || {
for event in rx {
match event {
Event::Insert(data) => {
println!("โ Inserted: {} = {}", data.key, data.value);
}
Event::Remove(data) => {
println!("โ Removed: {} = {}", data.key, data.value);
}
Event::Clear => {
println!("๐๏ธ Cache cleared");
}
}
}
});
cache.insert("user:1", "Alice");
cache.insert("user:2", "Bob");
cache.remove("user:1").unwrap();
cache.clear();
drop(cache);
event_handler.join().unwrap();
}
๐ Combined Features Example
use quickleaf::{Quickleaf, Duration, ListProps, Filter, Order};
use std::thread;
fn main() {
let (tx, _rx) = std::sync::mpsc::channel();
let mut cache = Quickleaf::with_sender_and_ttl(50, tx, Duration::from_secs(300));
cache.insert_with_ttl("session:guest", "temporary", Duration::from_secs(30));
cache.insert_with_ttl("session:user123", "authenticated", Duration::from_secs(3600));
cache.insert("config:theme", "dark"); cache.insert("config:lang", "en");
let sessions = cache.list(
ListProps::default()
.filter(Filter::StartWith("session:".to_string()))
.order(Order::Asc)
).unwrap();
println!("Active sessions: {}", sessions.len());
thread::sleep(Duration::from_secs(35));
println!("Guest session: {:?}", cache.get("session:guest")); println!("User session: {:?}", cache.get("session:user123"));
let expired_count = cache.cleanup_expired();
println!("Cleaned up {} expired items", expired_count);
}
๐๏ธ Architecture
Cache Structure
Quickleaf uses a dual-structure approach for optimal performance:
- HashMap: O(1) key-value access
- Vec: Maintains sorted key order for efficient iteration
- Lazy Cleanup: TTL items are removed when accessed, not proactively
TTL Strategy
- Lazy Cleanup: Expired items are removed during access operations (
get
, contains_key
, list
)
- Manual Cleanup: Use
cleanup_expired()
for proactive cleaning
- No Background Threads: Zero overhead until items are accessed
๐ง API Reference
Cache Creation
let cache = Quickleaf::new(capacity);
let cache = Quickleaf::with_default_ttl(capacity, ttl);
let cache = Quickleaf::with_sender(capacity, sender);
let cache = Quickleaf::with_sender_and_ttl(capacity, sender, ttl);
Core Operations
cache.insert(key, value);
cache.insert_with_ttl(key, value, ttl);
cache.get(key); cache.get_mut(key); cache.contains_key(key);
cache.remove(key); cache.clear();
cache.cleanup_expired(); cache.set_default_ttl(ttl);
cache.get_default_ttl();
Filtering and Listing
cache.list(props);
Filter::None
Filter::StartWith(prefix)
Filter::EndWith(suffix)
Filter::StartAndEndWith(prefix, suffix)
Order::Asc Order::Desc
๐งช Testing
Run the test suite:
cargo test
cargo test ttl
cargo test -- --nocapture
๐ Performance
Benchmarks
Operation |
Time Complexity |
Notes |
Insert |
O(log n) |
Due to ordered insertion |
Get |
O(1) |
HashMap lookup |
Remove |
O(n) |
Vec removal |
List |
O(n) |
Iteration with filtering |
TTL Check |
O(1) |
Simple time comparison |
Memory Usage
- Base overhead: ~48 bytes per cache instance
- Per item: ~(key_size + value_size + 56) bytes
- TTL overhead: +24 bytes per item with TTL
๐ Examples
Check out the examples/
directory for more comprehensive examples:
cargo run --example ttl_example
๐ค 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
git clone https://github.com/lowcarboncode/quickleaf.git
cd quickleaf
cargo test
cargo run --example ttl_example
cargo fmt --check
cargo clippy -- -D warnings
๐ License
This project is licensed under the Apache 2.0 License - see the LICENSE file for details.
๐ Links
Made with โค๏ธ by the LowCarbonCode team