1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
//! Configuration for the Greedy Dual-Size Frequency (GDSF) cache.
//!
//! This module provides configuration for GDSF caches. GDSF is particularly
//! well-suited for variable-sized objects as it considers object size in
//! eviction decisions.
//!
//! # Sizing Guidelines
//!
//! ## Understanding `max_size` and `capacity`
//!
//! - **`max_size`**: The maximum total size in bytes for cached *values*. This should reflect
//! your memory budget for the cache data itself.
//! - **`capacity`**: The maximum number of entries. Each entry has memory overhead beyond
//! the value size (approximately 64-128 bytes per entry for keys, pointers, and metadata).
//!
//! ## For In-Memory Caches
//!
//! Set `max_size` to the amount of memory you want to allocate for cached values:
//!
//! ```text
//! Total Memory ≈ max_size + (capacity × overhead_per_entry)
//! overhead_per_entry ≈ 64-128 bytes (keys, pointers, metadata)
//! ```
//!
//! **Example**: For a 100MB cache with ~10KB average values:
//! - `max_size = 100 * 1024 * 1024` (100MB for values)
//! - `capacity = 10_000` entries
//! - Overhead ≈ 10,000 × 100 bytes = ~1MB additional
//!
//! ## For Disk-Based or External Caches
//!
//! When caching references to external storage, size based on your target cache size:
//!
//! ```text
//! capacity = target_cache_size / average_object_size
//! ```
//!
//! **Example**: For a 1GB disk cache with 50KB average objects:
//! - `max_size = 1024 * 1024 * 1024` (1GB)
//! - `capacity = 1GB / 50KB ≈ 20,000` entries
//!
//! ## GDSF-Specific Considerations
//!
//! GDSF is ideal for **variable-sized objects** because it balances frequency
//! against size. For GDSF caches, `max_size` is especially important since the
//! algorithm optimizes for keeping many small popular items over few large ones.
//!
//! # Examples
//!
//! ```
//! use cache_rs::config::GdsfCacheConfig;
//! use cache_rs::GdsfCache;
//! use core::num::NonZeroUsize;
//!
//! // In-memory cache: 50MB budget for variable-sized objects
//! let config = GdsfCacheConfig {
//! capacity: NonZeroUsize::new(10_000).unwrap(),
//! initial_age: 0.0,
//! max_size: 50 * 1024 * 1024, // 50MB
//! };
//! let cache: GdsfCache<String, Vec<u8>> = GdsfCache::init(config, None);
//!
//! // Disk cache: 1GB for web assets (images, JS, CSS)
//! let config = GdsfCacheConfig {
//! capacity: NonZeroUsize::new(20_000).unwrap(), // ~50KB avg
//! initial_age: 0.0,
//! max_size: 1024 * 1024 * 1024, // 1GB
//! };
//! let cache: GdsfCache<String, Vec<u8>> = GdsfCache::init(config, None);
//! ```
use fmt;
use NonZeroUsize;
/// Configuration for a GDSF (Greedy Dual-Size Frequency) cache.
///
/// GDSF assigns a priority to each item based on the formula:
/// `Priority = (Frequency / Size) + Global_Age`
///
/// This makes it ideal for caching variable-sized objects where you want
/// to favor keeping many small popular items over few large items.
///
/// # Fields
///
/// - `capacity`: Maximum number of entries the cache can hold. Each entry has
/// memory overhead (~64-128 bytes) for keys, pointers, and metadata.
/// - `initial_age`: Initial global age value (default: 0.0)
/// - `max_size`: Maximum total size in bytes for cached values. **Essential for GDSF**
/// since the algorithm optimizes based on object sizes. See module docs for guidance.
///
/// # Sizing Recommendations
///
/// Always set meaningful values for both fields:
///
/// - **In-memory cache**: `max_size` = memory budget for values;
/// `capacity` = `max_size` / average_value_size
/// - **Disk-based cache**: `max_size` = disk space allocation;
/// `capacity` = `max_size` / average_object_size
///
/// # Examples
///
/// ```
/// use cache_rs::config::GdsfCacheConfig;
/// use cache_rs::GdsfCache;
/// use core::num::NonZeroUsize;
///
/// // 10MB cache for variable-sized web responses (~2KB avg)
/// let config = GdsfCacheConfig {
/// capacity: NonZeroUsize::new(5_000).unwrap(),
/// initial_age: 0.0,
/// max_size: 10 * 1024 * 1024, // 10MB
/// };
/// let cache: GdsfCache<String, Vec<u8>> = GdsfCache::init(config, None);
///
/// // 100MB image cache with ~20KB average size
/// let config = GdsfCacheConfig {
/// capacity: NonZeroUsize::new(5_000).unwrap(),
/// initial_age: 0.0,
/// max_size: 100 * 1024 * 1024, // 100MB
/// };
/// let cache: GdsfCache<String, Vec<u8>> = GdsfCache::init(config, None);
/// ```