oxidize_pdf/memory/
mod.rs1use std::sync::{Arc, RwLock};
41
42pub mod cache;
43pub mod lazy_loader;
44pub mod memory_mapped;
45pub mod stream_processor;
46
47pub use cache::{LruCache, ObjectCache};
49pub use lazy_loader::{LazyDocument, LazyObject};
50pub use memory_mapped::{MappedReader, MemoryMappedFile};
51pub use stream_processor::{ProcessingAction, ProcessingEvent, StreamProcessor, StreamingOptions};
52
53#[derive(Debug, Clone)]
55pub struct MemoryOptions {
56 pub lazy_loading: bool,
58 pub memory_mapping: bool,
60 pub cache_size: usize,
62 pub streaming: bool,
64 pub buffer_size: usize,
66 pub mmap_threshold: usize,
68}
69
70impl Default for MemoryOptions {
71 fn default() -> Self {
72 Self {
73 lazy_loading: true,
74 memory_mapping: true,
75 cache_size: 1000,
76 streaming: true,
77 buffer_size: 64 * 1024, mmap_threshold: 10 * 1024 * 1024, }
80 }
81}
82
83impl MemoryOptions {
84 pub fn small_file() -> Self {
86 Self {
87 lazy_loading: false,
88 memory_mapping: false,
89 cache_size: 0,
90 streaming: false,
91 buffer_size: 16 * 1024,
92 mmap_threshold: usize::MAX,
93 }
94 }
95
96 pub fn large_file() -> Self {
98 Self {
99 lazy_loading: true,
100 memory_mapping: true,
101 cache_size: 5000,
102 streaming: true,
103 buffer_size: 256 * 1024,
104 mmap_threshold: 1024 * 1024, }
106 }
107
108 pub fn with_lazy_loading(mut self, enabled: bool) -> Self {
110 self.lazy_loading = enabled;
111 self
112 }
113
114 pub fn with_memory_mapping(mut self, enabled: bool) -> Self {
116 self.memory_mapping = enabled;
117 self
118 }
119
120 pub fn with_cache_size(mut self, size: usize) -> Self {
122 self.cache_size = size;
123 self
124 }
125
126 pub fn with_streaming(mut self, enabled: bool) -> Self {
128 self.streaming = enabled;
129 self
130 }
131}
132
133#[derive(Debug, Clone, Default)]
135pub struct MemoryStats {
136 pub allocated_bytes: usize,
138 pub cached_objects: usize,
140 pub cache_hits: usize,
142 pub cache_misses: usize,
144 pub lazy_loads: usize,
146 pub mapped_regions: usize,
148}
149
150pub struct MemoryManager {
152 #[allow(dead_code)]
153 options: MemoryOptions,
154 stats: Arc<RwLock<MemoryStats>>,
155 cache: Option<ObjectCache>,
156}
157
158impl MemoryManager {
159 pub fn new(options: MemoryOptions) -> Self {
161 let cache = if options.cache_size > 0 {
162 Some(ObjectCache::new(options.cache_size))
163 } else {
164 None
165 };
166
167 Self {
168 options,
169 stats: Arc::new(RwLock::new(MemoryStats::default())),
170 cache,
171 }
172 }
173
174 pub fn stats(&self) -> MemoryStats {
176 self.stats.read().unwrap().clone()
177 }
178
179 pub fn record_allocation(&self, bytes: usize) {
181 if let Ok(mut stats) = self.stats.write() {
182 stats.allocated_bytes += bytes;
183 }
184 }
185
186 pub fn record_cache_hit(&self) {
188 if let Ok(mut stats) = self.stats.write() {
189 stats.cache_hits += 1;
190 }
191 }
192
193 pub fn record_cache_miss(&self) {
195 if let Ok(mut stats) = self.stats.write() {
196 stats.cache_misses += 1;
197 }
198 }
199
200 pub fn cache(&self) -> Option<&ObjectCache> {
202 self.cache.as_ref()
203 }
204}
205
206#[cfg(test)]
207mod tests {
208 use super::*;
209
210 #[test]
211 fn test_memory_options_default() {
212 let options = MemoryOptions::default();
213 assert!(options.lazy_loading);
214 assert!(options.memory_mapping);
215 assert_eq!(options.cache_size, 1000);
216 assert!(options.streaming);
217 assert_eq!(options.buffer_size, 64 * 1024);
218 }
219
220 #[test]
221 fn test_memory_options_small_file() {
222 let options = MemoryOptions::small_file();
223 assert!(!options.lazy_loading);
224 assert!(!options.memory_mapping);
225 assert_eq!(options.cache_size, 0);
226 assert!(!options.streaming);
227 }
228
229 #[test]
230 fn test_memory_options_large_file() {
231 let options = MemoryOptions::large_file();
232 assert!(options.lazy_loading);
233 assert!(options.memory_mapping);
234 assert_eq!(options.cache_size, 5000);
235 assert!(options.streaming);
236 assert_eq!(options.buffer_size, 256 * 1024);
237 }
238
239 #[test]
240 fn test_memory_options_builder() {
241 let options = MemoryOptions::default()
242 .with_lazy_loading(false)
243 .with_memory_mapping(false)
244 .with_cache_size(500)
245 .with_streaming(false);
246
247 assert!(!options.lazy_loading);
248 assert!(!options.memory_mapping);
249 assert_eq!(options.cache_size, 500);
250 assert!(!options.streaming);
251 }
252
253 #[test]
254 fn test_memory_stats() {
255 let stats = MemoryStats::default();
256 assert_eq!(stats.allocated_bytes, 0);
257 assert_eq!(stats.cached_objects, 0);
258 assert_eq!(stats.cache_hits, 0);
259 assert_eq!(stats.cache_misses, 0);
260 assert_eq!(stats.lazy_loads, 0);
261 assert_eq!(stats.mapped_regions, 0);
262 }
263
264 #[test]
265 fn test_memory_manager() {
266 let options = MemoryOptions::default();
267 let manager = MemoryManager::new(options);
268
269 manager.record_allocation(1024);
271 manager.record_cache_hit();
272 manager.record_cache_miss();
273
274 let stats = manager.stats();
275 assert_eq!(stats.allocated_bytes, 1024);
276 assert_eq!(stats.cache_hits, 1);
277 assert_eq!(stats.cache_misses, 1);
278
279 assert!(manager.cache().is_some());
281 }
282
283 #[test]
284 fn test_memory_manager_no_cache() {
285 let options = MemoryOptions::default().with_cache_size(0);
286 let manager = MemoryManager::new(options);
287
288 assert!(manager.cache().is_none());
290 }
291}