Loading pageâŚ
Rust walkthroughs
Loading pageâŚ
lru::LruCache::put handle existing entries compared to promote for cache policy enforcement?put performs a full insert-or-update operation that places the entry at the most-recently-used position and may evict the least-recently-used entry if the cache is at capacity, while promote only moves an existing entry to the most-recently-used position without modifying its value or triggering evictionâthe entry must already exist, and promote is purely an LRU order manipulation. The key distinction is that put is a write operation that can change cache contents and size, whereas promote is a read-positioning operation that only affects LRU ordering for an existing entry. Both operations update the cache's LRU state, but only put has side effects on the cache's contents and potential evictions.
use lru::LruCache;
fn basic_operations() {
let mut cache: LruCache<String, i32> = LruCache::new(NonZeroUsize::new(3).unwrap());
// put inserts new entries at most-recently-used position
cache.put("a".to_string(), 1);
cache.put("b".to_string(), 2);
cache.put("c".to_string(), 3);
// Order (MRU to LRU): c, b, a
// promote moves existing entry to MRU position
cache.promote(&"a".to_string());
// Order (MRU to LRU): a, c, b
// put with existing key updates value AND moves to MRU
cache.put("b".to_string(), 20);
// Order (MRU to LRU): b, a, c
// "b" now has value 20
}Both operations affect LRU ordering, but put also affects cache contents.
use lru::LruCache;
use std::num::NonZeroUsize;
fn put_new_entry() {
let mut cache: LruCache<i32, String> = LruCache::new(NonZeroUsize::new(2).unwrap());
// Insert first entry
cache.put(1, "one".to_string());
assert_eq!(cache.len(), 1);
assert_eq!(cache.get(&1), Some(&"one".to_string()));
// Insert second entry
cache.put(2, "two".to_string());
assert_eq!(cache.len(), 2);
// Cache is now at capacity
}put adds entries, potentially filling the cache to capacity.
use lru::LruCache;
use std::num::NonZeroUsize;
fn put_with_eviction() {
let mut cache: LruCache<i32, String> = LruCache::new(NonZeroUsize::new(2).unwrap());
cache.put(1, "one".to_string());
cache.put(2, "two".to_string());
// Cache is full
// Adding third entry evicts LRU (key 1)
let evicted = cache.put(3, "three".to_string());
// put returns the evicted entry (if any)
assert_eq!(evicted, Some((1, "one".to_string())));
assert_eq!(cache.get(&1), None); // Evicted
assert_eq!(cache.get(&2), Some(&"two".to_string()));
assert_eq!(cache.get(&3), Some(&"three".to_string()));
}put returns the evicted entry when it triggers eviction.
use lru::LruCache;
use std::num::NonZeroUsize;
fn promote_order_only() {
let mut cache: LruCache<i32, String> = LruCache::new(NonZeroUsize::new(3).unwrap());
cache.put(1, "one".to_string());
cache.put(2, "two".to_string());
cache.put(3, "three".to_string());
// Order: 3 (MRU), 2, 1 (LRU)
// promote moves 1 to MRU position
cache.promote(&1);
// Order: 1 (MRU), 3, 2 (LRU)
// Value is unchanged
assert_eq!(cache.get(&1), Some(&"one".to_string()));
// promote does NOT return anything
// It just reorders
}promote reorders without changing values or triggering eviction.
use lru::LruCache;
use std::num::NonZeroUsize;
fn promote_existing_only() {
let mut cache: LruCache<i32, String> = LruCache::new(NonZeroUsize::new(3).unwrap());
cache.put(1, "one".to_string());
// promote on existing entry: works
cache.promote(&1); // No-op, already MRU
// promote on non-existing entry: does nothing
cache.promote(&99); // No error, no effect
// No eviction, no insertion
assert_eq!(cache.len(), 1);
assert_eq!(cache.get(&99), None);
}promote silently ignores non-existent keysâit cannot insert or evict.
use lru::LruCache;
use std::num::NonZeroUsize;
fn put_updates_value() {
let mut cache: LruCache<i32, String> = LruCache::new(NonZeroUsize::new(3).unwrap());
cache.put(1, "one".to_string());
// put with same key updates value
let evicted = cache.put(1, "ONE".to_string());
// No eviction (key already exists, just updated)
assert_eq!(evicted, None);
// Value is updated
assert_eq!(cache.get(&1), Some(&"ONE".to_string()));
// Key is now MRU
}Updating an existing entry with put changes the value and moves to MRU.
// put:
// - Inserts new entries
// - Updates existing entries
// - Moves entry to MRU position
// - May evict LRU entry if at capacity
// - Returns evicted entry (if any)
// - Can change cache size (for new entries)
// - Always affects cache state
// promote:
// - Only works on existing entries
// - Does NOT modify values
// - Moves entry to MRU position
// - Does NOT trigger eviction
// - Returns nothing
// - Does NOT change cache size
// - Only affects LRU orderingThe two operations serve different purposes in LRU management.
use lru::LruCache;
use std::num::NonZeroUsize;
fn get_vs_promote() {
let mut cache: LruCache<i32, String> = LruCache::new(NonZeroUsize::new(3).unwrap());
cache.put(1, "one".to_string());
cache.put(2, "two".to_string());
cache.put(3, "three".to_string());
// Order: 3, 2, 1
// get AND promote (moves to MRU)
let value = cache.get(&1);
// Order: 1, 3, 2 (1 moved to MRU)
// peek AND NOT promote (keeps position)
let value = cache.peek(&2);
// Order: still 1, 3, 2
// promote explicitly (moves to MRU)
cache.promote(&2);
// Order: 2, 1, 3
}get is a read that promotes; promote is just promotion without reading.
use lru::LruCache;
use std::num::NonZeroUsize;
fn use_cases() {
let mut cache: LruCache<String, Data> = LruCache::new(NonZeroUsize::new(100).unwrap());
// Use put when:
// 1. Adding new entries
cache.put("key1".to_string(), Data::new());
// 2. Updating existing entries
cache.put("key1".to_string(), Data::updated());
// 3. Want eviction behavior
let evicted = cache.put("new_key".to_string(), Data::new());
if let Some((key, value)) = evicted {
// Handle evicted entry
}
// Use promote when:
// 1. Refreshing entry position without reading
cache.promote(&"key1".to_string());
// 2. Manual LRU management after peek
if let Some(data) = cache.peek(&"key1".to_string()) {
// Inspect without promoting
if data.is_important() {
// Now promote
cache.promote(&"key1".to_string());
}
}
// 3. Bulk reorder after loading cache
for key in &priority_keys {
cache.promote(key);
}
}Use put for write operations, promote for manual LRU manipulation.
use lru::LruCache;
use std::num::NonZeroUsize;
fn eviction_differences() {
let mut cache: LruCache<i32, String> = LruCache::new(NonZeroUsize::new(2).unwrap());
cache.put(1, "one".to_string());
cache.put(2, "two".to_string());
// put triggers eviction when full
let evicted = cache.put(3, "three".to_string());
assert!(evicted.is_some()); // Key 1 was evicted
// promote does NOT trigger eviction
cache.put(4, "four".to_string()); // First evict key 2
cache.put(5, "five".to_string()); // Then evict key 3
// Cache now: 5, 4
cache.promote(&4); // Just reorders
// Cache now: 4, 5
// No eviction occurred
}Only put can cause eviction; promote never does.
use lru::LruCache;
use std::num::NonZeroUsize;
fn manual_lru() {
let mut cache: LruCache<String, i32> = LruCache::new(NonZeroUsize::new(5).unwrap());
// Load initial entries
for i in 0..5 {
cache.put(format
!("key{}", i), i);
}
// Order (MRU to LRU): key4, key3, key2, key1, key0
// Promote specific entries based on external priority
// Without reading or modifying values
cache.promote(&"key0".to_string());
cache.promote(&"key1".to_string());
// Order: key1, key0, key4, key3, key2
// Now key2 and key3 are at LRU positions
// Next put will evict key2
}promote allows manual LRU manipulation for custom policies.
use lru::LruCache;
use std::num::NonZeroUsize;
fn return_values() {
let mut cache: LruCache<i32, String> = LruCache::new(NonZeroUsize::new(2).unwrap());
// put returns Option<(K, V)> - the evicted entry
let result1 = cache.put(1, "one".to_string());
assert_eq!(result1, None); // No eviction
let result2 = cache.put(2, "two".to_string());
assert_eq!(result2, None); // No eviction
let result3 = cache.put(3, "three".to_string());
assert_eq!(result3, Some((1, "one".to_string()))); // Evicted!
// promote returns () - nothing
cache.promote(&2); // Returns nothing, just reorders
}put returns the evicted entry; promote returns nothing.
use lru::LruCache;
use std::num::NonZeroUsize;
fn reference_handling() {
let mut cache: LruCache<String, i32> = LruCache::new(NonZeroUsize::new(3).unwrap());
cache.put("key".to_string(), 1);
// put takes ownership of key and value
cache.put("key".to_string(), 2);
// promote takes reference to key
cache.promote(&"key".to_string());
// This allows promote without consuming the key
let key = String::from("key");
cache.promote(&key); // key still usable
println!("Key: {}", key); // key still valid
}promote borrows the key; put takes ownership (for new keys).
use lru::LruCache;
use std::num::NonZeroUsize;
fn contains_and_promote() {
let mut cache: LruCache<i32, String> = LruCache::new(NonZeroUsize::new(3).unwrap());
cache.put(1, "one".to_string());
// Check if key exists before promote
if cache.contains_key(&1) {
cache.promote(&1);
}
// contains_key does NOT promote
// Order remains: 1 (MRU)
// peek_mut allows modification without promotion
if let Some(value) = cache.peek_mut(&1) {
value.push_str("_modified");
}
// Entry still at same position in LRU
}contains_key and peek don't promote; use promote explicitly when needed.
use lru::LruCache;
use std::num::NonZeroUsize;
fn conditional_promotion() {
let mut cache: LruCache<String, Data> = LruCache::new(NonZeroUsize::new(100).unwrap());
// Load cache
for i in 0..100 {
cache.put(format
!("item{}", i), Data::new(i));
}
// Process items, conditionally promote
let important_keys = vec
!["item0", "item50", "item99"];
for key in &important_keys {
// Only promote if exists and meets criteria
if let Some(data) = cache.peek(key) {
if data.is_important() {
cache.promote(key);
}
}
}
// Important items now at MRU positions
// Less likely to be evicted
}
struct Data {
id: i32,
}
impl Data {
fn new(id: i32) -> Self { Data { id } }
fn is_important(&self) -> bool { self.id % 50 == 0 }
}Combine peek and promote for conditional LRU updates.
use lru::LruCache;
use std::num::NonZeroUsize;
fn refresh_pattern() {
let mut cache: LruCache<String, String> = LruCache::new(NonZeroUsize::new(3).unwrap());
cache.put("a".to_string(), "data_a".to_string());
cache.put("b".to_string(), "data_b".to_string());
cache.put("c".to_string(), "data_c".to_string());
// Order: c, b, a
// External signal: "a" is still relevant, don't evict
cache.promote(&"a".to_string());
// Order: a, c, b
// Next eviction will remove "b" instead of "a"
cache.put("d".to_string(), "data_d".to_string());
// "b" is evicted, not "a"
assert!(cache.contains_key(&"a"));
assert!(!cache.contains_key(&"b"));
}Use promote to keep entries alive without modifying them.
use lru::LruCache;
use std::num::NonZeroUsize;
fn iteration_order() {
let mut cache: LruCache<i32, i32> = LruCache::new(NonZeroUsize::new(3).unwrap());
cache.put(1, 1);
cache.put(2, 2);
cache.put(3, 3);
// Order: 3, 2, 1
// Iteration is from MRU to LRU
let keys: Vec<_> = cache.iter().map(|(&k, _)| k).collect();
assert_eq!(keys, vec
![3, 2, 1]);
// After promote
cache.promote(&1);
// Order: 1, 3, 2
let keys: Vec<_> = cache.iter().map(|(&k, _)| k).collect();
assert_eq!(keys, vec
![1, 3, 2]);
}Iteration order reflects LRU order; promote changes this order.
Key differences:
// put:
// - Can insert new entries
// - Can update existing entries
// - Can trigger eviction
// - Returns evicted entry
// - Takes ownership of key and value
// - Full write operation
// promote:
// - Cannot insert new entries
// - Cannot update values
// - Cannot trigger eviction
// - Returns nothing
// - Takes reference to key
// - Pure ordering operationWhen to use each:
// Use put when:
// - Adding new data to cache
// - Updating cached values
// - Managing cache lifecycle (handle evictions)
// - Standard cache access pattern
// Use promote when:
// - Refreshing entry position without reading
// - Conditional promotion based on peek inspection
// - Batch reordering after bulk operations
// - Custom LRU policy implementationCommon patterns:
// Standard cache access:
// get() promotes automatically
// peek() doesn't promote
// put() inserts/updates and promotes
// Manual promotion:
// 1. peek() to inspect
// 2. Decide if important
// 3. promote() if needed
// Eviction handling:
// put() returns evicted entry
// promote() never causes evictionKey insight: put is a complete cache write operation that can insert, update, and evict, while promote is a focused LRU order manipulation that only moves existing entries to the most-recently-used position. put affects cache contents, size, and ordering, returning any evicted entry; promote affects only ordering, silently ignoring non-existent keys. Use put for normal cache writes and updates, and promote for manual LRU management when you want to refresh an entry's position without reading it (which would promote anyway) or when implementing custom cache policies that need fine-grained control over which entries stay and which get evicted.