Skip to content

Commit 2f68c4c

Browse files
committed
Add API documentation
1 parent 94d61bc commit 2f68c4c

File tree

1 file changed

+256
-17
lines changed

1 file changed

+256
-17
lines changed

src/lib.rs

Lines changed: 256 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,40 @@ use likely_stable::unlikely;
1212
const MAX_CAPACITY: u16 = u16::MAX - 1;
1313

1414
/// Intrusive node stored in the TinyVec/heap storage.
15+
///
16+
/// Contains the key-value pair and doubly-linked list pointers for LRU ordering.
1517
#[derive(Default, Clone)]
1618
pub struct Entry<K, V>
1719
where
1820
K: Default + Clone,
1921
V: Default,
2022
{
23+
/// The cache key
2124
pub key: K,
25+
/// The cached value
2226
pub val: V,
27+
/// Next entry index in LRU order (u16::MAX if tail)
2328
pub next: u16,
29+
/// Previous entry index in LRU order (u16::MAX if head)
2430
pub prev: u16,
2531
}
2632

2733
/// LRU cache with inline-then-spill storage.
34+
///
35+
/// For small working sets (≤ N), entries are stored inline on the stack for maximum performance.
36+
/// Once capacity exceeds N, it transparently spills to heap-backed storage with O(1) operations.
37+
///
38+
/// # Example
39+
/// ```
40+
/// use tiny_lru::TinyLru;
41+
///
42+
/// let mut cache = TinyLru::<i32, &str, 4>::new();
43+
/// cache.push(1, "value");
44+
/// cache.push(2, "another");
45+
///
46+
/// assert_eq!(cache.get(&1), Some(&"value"));
47+
/// assert_eq!(cache.len(), 2);
48+
/// ```
2849
#[derive(Clone)]
2950
pub struct TinyLru<K, V, const N: usize>
3051
where
@@ -60,7 +81,15 @@ where
6081
K: Eq + Hash + Default + Clone,
6182
V: Default,
6283
{
63-
/// Create with capacity = N.
84+
/// Create a new cache with capacity = N.
85+
///
86+
/// # Example
87+
/// ```
88+
/// use tiny_lru::TinyLru;
89+
///
90+
/// let cache = TinyLru::<i32, &str, 8>::new();
91+
/// assert_eq!(cache.capacity(), 8);
92+
/// ```
6493
#[inline]
6594
pub fn new() -> Self {
6695
assert_capacity_limit::<N>();
@@ -74,7 +103,18 @@ where
74103
}
75104
}
76105

77-
/// Create with specified capacity (must be >= N).
106+
/// Create a new cache with specified capacity (must be >= N).
107+
///
108+
/// # Panics
109+
/// Panics if `cap < N`.
110+
///
111+
/// # Example
112+
/// ```
113+
/// use tiny_lru::TinyLru;
114+
///
115+
/// let cache = TinyLru::<i32, &str, 4>::with_capacity(16);
116+
/// assert_eq!(cache.capacity(), 16);
117+
/// ```
78118
#[inline]
79119
pub fn with_capacity(cap: u16) -> Self {
80120
assert_capacity_limit::<N>();
@@ -91,7 +131,22 @@ where
91131
}
92132
}
93133

94-
/// Insert or update; promotes on hit.
134+
/// Insert or update a key-value pair, promoting to MRU on hit.
135+
///
136+
/// If the key already exists, updates the value and promotes to most recently used.
137+
/// If the cache is at capacity, removes the least recently used entry first.
138+
///
139+
/// # Example
140+
/// ```
141+
/// use tiny_lru::TinyLru;
142+
///
143+
/// let mut cache = TinyLru::<i32, String, 2>::new();
144+
/// cache.push(1, "first".to_string());
145+
/// cache.push(2, "second".to_string());
146+
/// cache.push(1, "updated".to_string()); // Updates existing key
147+
///
148+
/// assert_eq!(cache.get(&1), Some(&"updated".to_string()));
149+
/// ```
95150
#[inline]
96151
pub fn push(&mut self, key: K, value: V) {
97152
// If key exists: update value and promote to MRU
@@ -113,7 +168,22 @@ where
113168
self.insert(key, value);
114169
}
115170

116-
/// Pop and return the LRU entry.
171+
/// Remove and return the least recently used entry.
172+
///
173+
/// Returns `None` if the cache is empty.
174+
///
175+
/// # Example
176+
/// ```
177+
/// use tiny_lru::TinyLru;
178+
///
179+
/// let mut cache = TinyLru::<i32, String, 2>::new();
180+
/// cache.push(1, "first".to_string());
181+
/// cache.push(2, "second".to_string());
182+
///
183+
/// let (key, value) = cache.pop().unwrap();
184+
/// assert_eq!(key, 1); // LRU entry
185+
/// assert_eq!(value, "first");
186+
/// ```
117187
#[inline]
118188
pub fn pop(&mut self) -> Option<(K, V)> {
119189
if self.is_empty() {
@@ -167,7 +237,20 @@ where
167237
Some((key, value))
168238
}
169239

170-
/// Get by key, promoting to MRU on hit.
240+
/// Get a value by key, promoting to MRU on hit.
241+
///
242+
/// Returns `None` if the key is not found.
243+
///
244+
/// # Example
245+
/// ```
246+
/// use tiny_lru::TinyLru;
247+
///
248+
/// let mut cache = TinyLru::<i32, String, 2>::new();
249+
/// cache.push(1, "value".to_string());
250+
///
251+
/// assert_eq!(cache.get(&1), Some(&"value".to_string()));
252+
/// assert_eq!(cache.get(&2), None);
253+
/// ```
171254
#[inline]
172255
pub fn get(&mut self, key: &K) -> Option<&V> {
173256
if let Some(index) = self.find_key_index(key) {
@@ -178,7 +261,22 @@ where
178261
}
179262
}
180263

181-
/// Get mutable by key, promoting to MRU on hit.
264+
/// Get a mutable reference by key, promoting to MRU on hit.
265+
///
266+
/// Returns `None` if the key is not found.
267+
///
268+
/// # Example
269+
/// ```
270+
/// use tiny_lru::TinyLru;
271+
///
272+
/// let mut cache = TinyLru::<i32, String, 2>::new();
273+
/// cache.push(1, "value".to_string());
274+
///
275+
/// if let Some(val) = cache.get_mut(&1) {
276+
/// val.push_str(" updated");
277+
/// }
278+
/// assert_eq!(cache.get(&1), Some(&"value updated".to_string()));
279+
/// ```
182280
#[inline]
183281
pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
184282
if let Some(index) = self.find_key_index(key) {
@@ -189,13 +287,44 @@ where
189287
}
190288
}
191289

192-
/// Peek without promotion.
290+
/// Peek at a value by key without promoting to MRU.
291+
///
292+
/// Returns `None` if the key is not found. Unlike `get()`, this does not
293+
/// affect the LRU ordering.
294+
///
295+
/// # Example
296+
/// ```
297+
/// use tiny_lru::TinyLru;
298+
///
299+
/// let mut cache = TinyLru::<i32, String, 2>::new();
300+
/// cache.push(1, "first".to_string());
301+
/// cache.push(2, "second".to_string());
302+
///
303+
/// // Peek doesn't change LRU order
304+
/// assert_eq!(cache.peek(&1), Some(&"first".to_string()));
305+
/// cache.pop(); // Still removes key 1 (LRU)
306+
/// ```
193307
#[inline]
194308
pub fn peek(&self, key: &K) -> Option<&V> {
195309
self.find_key_index(key).map(|index| &self.store[index].val)
196310
}
197311

198-
/// Remove by key and return owned pair.
312+
/// Remove a key-value pair and return the owned values.
313+
///
314+
/// Returns `None` if the key is not found.
315+
///
316+
/// # Example
317+
/// ```
318+
/// use tiny_lru::TinyLru;
319+
///
320+
/// let mut cache = TinyLru::<i32, String, 2>::new();
321+
/// cache.push(1, "value".to_string());
322+
///
323+
/// let (key, value) = cache.remove(&1).unwrap();
324+
/// assert_eq!(key, 1);
325+
/// assert_eq!(value, "value");
326+
/// assert!(cache.is_empty());
327+
/// ```
199328
#[inline]
200329
pub fn remove(&mut self, key: &K) -> Option<(K, V)> {
201330
// Find the key index
@@ -250,7 +379,20 @@ where
250379
Some((key, value))
251380
}
252381

253-
/// Clear all entries.
382+
/// Clear all entries from the cache.
383+
///
384+
/// Resets the cache to its initial state, including returning to pre-spill
385+
/// mode if it was previously spilled to heap.
386+
///
387+
/// # Example
388+
/// ```
389+
/// use tiny_lru::TinyLru;
390+
///
391+
/// let mut cache = TinyLru::<i32, String, 2>::new();
392+
/// cache.push(1, "value".to_string());
393+
/// cache.clear();
394+
/// assert!(cache.is_empty());
395+
/// ```
254396
#[inline]
255397
pub fn clear(&mut self) {
256398
// Clear the store efficiently
@@ -264,7 +406,19 @@ where
264406
self.index = None;
265407
}
266408

267-
/// Adjust capacity. Requires new_cap > size and new_cap >= N.
409+
/// Adjust the cache capacity.
410+
///
411+
/// # Panics
412+
/// Panics if `new_cap <= current_size` or `new_cap < N`.
413+
///
414+
/// # Example
415+
/// ```
416+
/// use tiny_lru::TinyLru;
417+
///
418+
/// let mut cache = TinyLru::<i32, String, 4>::new();
419+
/// cache.set_capacity(16);
420+
/// assert_eq!(cache.capacity(), 16);
421+
/// ```
268422
#[inline]
269423
pub fn set_capacity(&mut self, new_cap: u16) {
270424
// Validate requirements
@@ -276,44 +430,129 @@ where
276430
self.capacity = new_cap;
277431
}
278432

279-
/// Current number of items.
433+
/// Returns the current number of items in the cache.
434+
///
435+
/// # Example
436+
/// ```
437+
/// use tiny_lru::TinyLru;
438+
///
439+
/// let mut cache = TinyLru::<i32, String, 4>::new();
440+
/// assert_eq!(cache.len(), 0);
441+
/// cache.push(1, "value".to_string());
442+
/// assert_eq!(cache.len(), 1);
443+
/// ```
280444
#[inline]
281445
pub fn len(&self) -> u16 {
282446
self.store.len() as u16
283447
}
284448

285-
/// Whether the cache is empty.
449+
/// Returns `true` if the cache contains no items.
450+
///
451+
/// # Example
452+
/// ```
453+
/// use tiny_lru::TinyLru;
454+
///
455+
/// let mut cache = TinyLru::<i32, String, 4>::new();
456+
/// assert!(cache.is_empty());
457+
/// cache.push(1, "value".to_string());
458+
/// assert!(!cache.is_empty());
459+
/// ```
286460
#[inline]
287461
pub fn is_empty(&self) -> bool {
288462
self.store.is_empty()
289463
}
290464

291-
/// Current capacity.
465+
/// Returns the current capacity of the cache.
466+
///
467+
/// # Example
468+
/// ```
469+
/// use tiny_lru::TinyLru;
470+
///
471+
/// let cache = TinyLru::<i32, String, 8>::new();
472+
/// assert_eq!(cache.capacity(), 8);
473+
/// ```
292474
#[inline]
293475
pub fn capacity(&self) -> u16 {
294476
self.capacity
295477
}
296478

297-
/// Contains key.
479+
/// Returns `true` if the cache contains the specified key.
480+
///
481+
/// # Example
482+
/// ```
483+
/// use tiny_lru::TinyLru;
484+
///
485+
/// let mut cache = TinyLru::<i32, String, 4>::new();
486+
/// cache.push(1, "value".to_string());
487+
///
488+
/// assert!(cache.contains_key(&1));
489+
/// assert!(!cache.contains_key(&2));
490+
/// ```
298491
#[inline]
299492
pub fn contains_key(&self, key: &K) -> bool {
300493
self.find_key_index(key).is_some()
301494
}
302495

303-
/// Check if the cache is currently spilled to heap.
496+
/// Returns `true` if the cache has spilled to heap-backed storage.
497+
///
498+
/// This happens when the cache size exceeds the inline capacity N.
499+
///
500+
/// # Example
501+
/// ```
502+
/// use tiny_lru::TinyLru;
503+
///
504+
/// let mut cache = TinyLru::<i32, String, 2>::with_capacity(4);
505+
/// assert!(!cache.is_spilled());
506+
///
507+
/// cache.push(1, "a".to_string());
508+
/// cache.push(2, "b".to_string());
509+
/// cache.push(3, "c".to_string()); // Triggers spill
510+
/// assert!(cache.is_spilled());
511+
/// ```
304512
#[inline]
305513
pub fn is_spilled(&self) -> bool {
306514
self.index.is_some()
307515
}
308516

309-
/// Check if unspill is currently possible.
517+
/// Returns `true` if the cache can be unspilled back to inline storage.
518+
///
519+
/// This is possible when the cache is spilled but the current size ≤ N.
520+
///
521+
/// # Example
522+
/// ```
523+
/// use tiny_lru::TinyLru;
524+
///
525+
/// let mut cache = TinyLru::<i32, String, 2>::with_capacity(4);
526+
/// cache.push(1, "a".to_string());
527+
/// cache.push(2, "b".to_string());
528+
/// cache.push(3, "c".to_string()); // Spills
529+
/// cache.pop(); // Size back to 2
530+
///
531+
/// assert!(cache.can_unspill());
532+
/// ```
310533
#[inline]
311534
pub fn can_unspill(&self) -> bool {
312535
self.is_spilled() && self.store.len() <= N
313536
}
314537

315538
/// Attempt to unspill from heap back to inline storage.
316-
/// Returns true if unspill was successful, false if not possible.
539+
///
540+
/// Returns `true` if unspill was successful, `false` if not possible.
541+
/// This can free heap memory when the cache size drops below N.
542+
///
543+
/// # Example
544+
/// ```
545+
/// use tiny_lru::TinyLru;
546+
///
547+
/// let mut cache = TinyLru::<i32, String, 2>::with_capacity(4);
548+
/// cache.push(1, "a".to_string());
549+
/// cache.push(2, "b".to_string());
550+
/// cache.push(3, "c".to_string()); // Spills
551+
/// cache.pop(); // Size back to 2
552+
///
553+
/// assert!(cache.unspill()); // Returns to inline storage
554+
/// assert!(!cache.is_spilled());
555+
/// ```
317556
#[inline]
318557
pub fn unspill(&mut self) -> bool {
319558
if !self.can_unspill() {

0 commit comments

Comments
 (0)