1use crate::error::{PdfError, Result};
7use crate::memory::{MemoryManager, MemoryOptions};
8use crate::objects::ObjectId;
9use crate::parser::{ParsedPage, PdfObject, PdfReader};
10use std::collections::HashMap;
11use std::fs::File;
12use std::io::{Read, Seek};
13use std::sync::{Arc, RwLock};
14
15pub enum LazyObject {
17 NotLoaded { offset: u64 },
19 Loaded(Arc<PdfObject>),
21 Loading,
23}
24
25pub struct LazyDocument<R: Read + Seek> {
27 #[allow(dead_code)]
28 reader: Arc<RwLock<PdfReader<R>>>,
29 memory_manager: Arc<MemoryManager>,
30 object_map: Arc<RwLock<HashMap<ObjectId, LazyObject>>>,
31 page_count: u32,
32}
33
34impl LazyDocument<File> {
35 pub fn open<P: AsRef<std::path::Path>>(path: P, options: MemoryOptions) -> Result<Self> {
37 let reader = PdfReader::open(path).map_err(|e| PdfError::ParseError(e.to_string()))?;
38 Self::new(reader, options)
39 }
40}
41
42impl<R: Read + Seek> LazyDocument<R> {
43 pub fn new(reader: PdfReader<R>, options: MemoryOptions) -> Result<Self> {
45 let memory_manager = Arc::new(MemoryManager::new(options));
46
47 let page_count = 0;
50
51 let reader = Arc::new(RwLock::new(reader));
52 let object_map = Arc::new(RwLock::new(HashMap::new()));
53
54 Ok(Self {
55 reader,
56 memory_manager,
57 object_map,
58 page_count,
59 })
60 }
61
62 pub fn page_count(&self) -> u32 {
64 self.page_count
65 }
66
67 pub fn get_page(&self, index: u32) -> Result<ParsedPage> {
69 if index >= self.page_count {
70 return Err(PdfError::InvalidPageNumber(index));
71 }
72
73 self.memory_manager.record_cache_miss();
74
75 Err(PdfError::ParseError(
78 "Lazy loading not fully implemented".to_string(),
79 ))
80 }
81
82 pub fn get_object(&self, id: &ObjectId) -> Result<Arc<PdfObject>> {
84 if let Some(cache) = self.memory_manager.cache() {
86 if let Some(obj) = cache.get(id) {
87 self.memory_manager.record_cache_hit();
88 return Ok(obj);
89 }
90 }
91
92 self.memory_manager.record_cache_miss();
93
94 if let Ok(mut map) = self.object_map.write() {
96 match map.get_mut(id) {
97 Some(LazyObject::Loaded(obj)) => {
98 return Ok(obj.clone());
99 }
100 Some(LazyObject::Loading) => {
101 return Err(PdfError::ParseError(
102 "Circular reference detected".to_string(),
103 ));
104 }
105 Some(LazyObject::NotLoaded { offset }) => {
106 let offset = *offset;
107 map.insert(*id, LazyObject::Loading);
109
110 let obj = self.load_object_at_offset(offset)?;
112 let obj_arc = Arc::new(obj);
113
114 if let Some(cache) = self.memory_manager.cache() {
116 cache.put(*id, obj_arc.clone());
117 }
118
119 map.insert(*id, LazyObject::Loaded(obj_arc.clone()));
121
122 return Ok(obj_arc);
123 }
124 None => {
125 }
128 }
129 }
130
131 Err(PdfError::InvalidObjectReference(
132 id.number(),
133 id.generation(),
134 ))
135 }
136
137 pub fn preload_page(&self, index: u32) -> Result<()> {
139 let page = self.get_page(index)?;
140
141 if let Some(resources) = page.get_resources() {
143 if let Some(fonts) = resources.get("Font").and_then(|f| f.as_dict()) {
145 for font_ref in fonts.0.values() {
146 if let PdfObject::Reference(num, gen) = font_ref {
147 let id = ObjectId::new(*num, *gen);
148 let _ = self.get_object(&id);
149 }
150 }
151 }
152
153 if let Some(xobjects) = resources.get("XObject").and_then(|x| x.as_dict()) {
155 for xobj_ref in xobjects.0.values() {
156 if let PdfObject::Reference(num, gen) = xobj_ref {
157 let id = ObjectId::new(*num, *gen);
158 let _ = self.get_object(&id);
159 }
160 }
161 }
162 }
163
164 Ok(())
165 }
166
167 pub fn memory_stats(&self) -> crate::memory::MemoryStats {
169 self.memory_manager.stats()
170 }
171
172 pub fn clear_cache(&self) {
174 if let Some(cache) = self.memory_manager.cache() {
175 cache.clear();
176 }
177
178 if let Ok(mut map) = self.object_map.write() {
179 map.retain(|_, obj| matches!(obj, LazyObject::NotLoaded { .. }));
181 }
182 }
183
184 fn load_object_at_offset(&self, _offset: u64) -> Result<PdfObject> {
185 Ok(PdfObject::Null)
188 }
189}
190
191pub struct LazyPageIterator<R: Read + Seek> {
193 document: Arc<LazyDocument<R>>,
194 current: u32,
195 total: u32,
196}
197
198impl<R: Read + Seek> LazyPageIterator<R> {
199 pub fn new(document: Arc<LazyDocument<R>>) -> Self {
200 let total = document.page_count();
201 Self {
202 document,
203 current: 0,
204 total,
205 }
206 }
207}
208
209impl<R: Read + Seek> Iterator for LazyPageIterator<R> {
210 type Item = Result<ParsedPage>;
211
212 fn next(&mut self) -> Option<Self::Item> {
213 if self.current >= self.total {
214 return None;
215 }
216
217 let result = self.document.get_page(self.current);
218 self.current += 1;
219 Some(result)
220 }
221}
222
223#[cfg(test)]
224mod tests {
225 use super::*;
226 use crate::parser::test_helpers;
227 use std::io::Cursor;
228
229 #[test]
230 fn test_lazy_object_states() {
231 let not_loaded = LazyObject::NotLoaded { offset: 1234 };
232 match not_loaded {
233 LazyObject::NotLoaded { offset } => assert_eq!(offset, 1234),
234 _ => panic!("Wrong state"),
235 }
236
237 let loaded = LazyObject::Loaded(Arc::new(PdfObject::Integer(42)));
238 match loaded {
239 LazyObject::Loaded(obj) => {
240 assert_eq!(*obj, PdfObject::Integer(42));
241 }
242 _ => panic!("Wrong state"),
243 }
244
245 let loading = LazyObject::Loading;
246 match loading {
247 LazyObject::Loading => assert!(true),
248 _ => panic!("Wrong state"),
249 }
250 }
251
252 #[test]
253 fn test_lazy_document_creation() {
254 let pdf_data = test_helpers::create_minimal_pdf();
255 let cursor = Cursor::new(pdf_data);
256 let reader = PdfReader::new(cursor).unwrap();
257 let options = MemoryOptions::default();
258
259 let lazy_doc = LazyDocument::new(reader, options).unwrap();
260 assert_eq!(lazy_doc.page_count(), 0); }
262
263 #[test]
264 fn test_memory_stats() {
265 let pdf_data = test_helpers::create_minimal_pdf();
266 let cursor = Cursor::new(pdf_data);
267 let reader = PdfReader::new(cursor).unwrap();
268 let options = MemoryOptions::default();
269
270 let lazy_doc = LazyDocument::new(reader, options).unwrap();
271 let stats = lazy_doc.memory_stats();
272
273 assert_eq!(stats.cache_hits, 0);
274 assert_eq!(stats.cache_misses, 0);
275 }
276
277 #[test]
278 fn test_clear_cache() {
279 let pdf_data = test_helpers::create_minimal_pdf();
280 let cursor = Cursor::new(pdf_data);
281 let reader = PdfReader::new(cursor).unwrap();
282 let options = MemoryOptions::default().with_cache_size(10);
283
284 let lazy_doc = LazyDocument::new(reader, options).unwrap();
285
286 lazy_doc.clear_cache();
288 }
289
290 #[test]
291 fn test_page_iterator() {
292 let pdf_data = test_helpers::create_minimal_pdf();
293 let cursor = Cursor::new(pdf_data);
294 let reader = PdfReader::new(cursor).unwrap();
295 let options = MemoryOptions::default();
296
297 let lazy_doc = Arc::new(LazyDocument::new(reader, options).unwrap());
298 let mut iterator = LazyPageIterator::new(lazy_doc);
299
300 assert!(iterator.next().is_none());
302 }
303
304 #[test]
305 fn test_lazy_object_not_loaded() {
306 let obj = LazyObject::NotLoaded { offset: 42 };
307
308 match obj {
309 LazyObject::NotLoaded { offset } => {
310 assert_eq!(offset, 42);
311 }
312 _ => panic!("Expected NotLoaded variant"),
313 }
314 }
315
316 #[test]
317 fn test_lazy_object_loaded() {
318 let pdf_obj = Arc::new(PdfObject::Boolean(true));
319 let obj = LazyObject::Loaded(pdf_obj.clone());
320
321 match obj {
322 LazyObject::Loaded(arc_obj) => {
323 assert_eq!(*arc_obj, PdfObject::Boolean(true));
324 assert!(Arc::ptr_eq(&arc_obj, &pdf_obj));
325 }
326 _ => panic!("Expected Loaded variant"),
327 }
328 }
329
330 #[test]
331 fn test_lazy_object_loading() {
332 let obj = LazyObject::Loading;
333
334 match obj {
335 LazyObject::Loading => {
336 }
338 _ => panic!("Expected Loading variant"),
339 }
340 }
341
342 #[test]
343 fn test_lazy_document_page_count() {
344 let pdf_data = test_helpers::create_minimal_pdf();
345 let cursor = Cursor::new(pdf_data);
346 let reader = PdfReader::new(cursor).unwrap();
347 let options = MemoryOptions::default();
348
349 let lazy_doc = LazyDocument::new(reader, options).unwrap();
350
351 assert_eq!(lazy_doc.page_count(), 0);
352 }
353
354 #[test]
355 fn test_lazy_document_get_page_invalid_index() {
356 let pdf_data = test_helpers::create_minimal_pdf();
357 let cursor = Cursor::new(pdf_data);
358 let reader = PdfReader::new(cursor).unwrap();
359 let options = MemoryOptions::default();
360
361 let lazy_doc = LazyDocument::new(reader, options).unwrap();
362
363 let result = lazy_doc.get_page(0);
365 assert!(result.is_err());
366
367 match result {
368 Err(PdfError::InvalidPageNumber(num)) => {
369 assert_eq!(num, 0);
370 }
371 _ => panic!("Expected InvalidPageNumber error"),
372 }
373
374 let result = lazy_doc.get_page(5);
376 assert!(result.is_err());
377
378 match result {
379 Err(PdfError::InvalidPageNumber(num)) => {
380 assert_eq!(num, 5);
381 }
382 _ => panic!("Expected InvalidPageNumber error"),
383 }
384 }
385
386 #[test]
387 fn test_lazy_document_get_object_not_found() {
388 let pdf_data = test_helpers::create_minimal_pdf();
389 let cursor = Cursor::new(pdf_data);
390 let reader = PdfReader::new(cursor).unwrap();
391 let options = MemoryOptions::default();
392
393 let lazy_doc = LazyDocument::new(reader, options).unwrap();
394 let obj_id = ObjectId::new(999, 0);
395
396 let result = lazy_doc.get_object(&obj_id);
397 assert!(result.is_err());
398
399 match result {
400 Err(PdfError::InvalidObjectReference(num, gen)) => {
401 assert_eq!(num, 999);
402 assert_eq!(gen, 0);
403 }
404 _ => panic!("Expected InvalidObjectReference error"),
405 }
406 }
407
408 #[test]
409 fn test_lazy_document_get_object_circular_reference() {
410 let pdf_data = test_helpers::create_minimal_pdf();
411 let cursor = Cursor::new(pdf_data);
412 let reader = PdfReader::new(cursor).unwrap();
413 let options = MemoryOptions::default();
414
415 let lazy_doc = LazyDocument::new(reader, options).unwrap();
416 let obj_id = ObjectId::new(1, 0);
417
418 {
420 let mut map = lazy_doc.object_map.write().unwrap();
421 map.insert(obj_id, LazyObject::Loading);
422 }
423
424 let result = lazy_doc.get_object(&obj_id);
425 assert!(result.is_err());
426
427 match result {
428 Err(PdfError::ParseError(msg)) => {
429 assert!(msg.contains("Circular reference"));
430 }
431 _ => panic!("Expected ParseError for circular reference"),
432 }
433 }
434
435 #[test]
436 fn test_lazy_document_get_object_not_loaded_then_loaded() {
437 let pdf_data = test_helpers::create_minimal_pdf();
438 let cursor = Cursor::new(pdf_data);
439 let reader = PdfReader::new(cursor).unwrap();
440 let options = MemoryOptions::default();
441
442 let lazy_doc = LazyDocument::new(reader, options).unwrap();
443 let obj_id = ObjectId::new(1, 0);
444
445 {
447 let mut map = lazy_doc.object_map.write().unwrap();
448 map.insert(obj_id, LazyObject::NotLoaded { offset: 100 });
449 }
450
451 let result = lazy_doc.get_object(&obj_id);
452 assert!(result.is_ok());
453
454 let obj = result.unwrap();
455 assert_eq!(*obj, PdfObject::Null); {
459 let map = lazy_doc.object_map.read().unwrap();
460 match map.get(&obj_id) {
461 Some(LazyObject::Loaded(_)) => {}
462 _ => panic!("Expected object to be cached as Loaded"),
463 }
464 }
465 }
466
467 #[test]
468 fn test_lazy_document_get_object_already_loaded() {
469 let pdf_data = test_helpers::create_minimal_pdf();
470 let cursor = Cursor::new(pdf_data);
471 let reader = PdfReader::new(cursor).unwrap();
472 let options = MemoryOptions::default();
473
474 let lazy_doc = LazyDocument::new(reader, options).unwrap();
475 let obj_id = ObjectId::new(1, 0);
476 let test_obj = Arc::new(PdfObject::Boolean(true));
477
478 {
480 let mut map = lazy_doc.object_map.write().unwrap();
481 map.insert(obj_id, LazyObject::Loaded(test_obj.clone()));
482 }
483
484 let result = lazy_doc.get_object(&obj_id);
485 assert!(result.is_ok());
486
487 let obj = result.unwrap();
488 assert_eq!(*obj, PdfObject::Boolean(true));
489 assert!(Arc::ptr_eq(&obj, &test_obj));
490 }
491
492 #[test]
493 fn test_lazy_document_preload_page_invalid_index() {
494 let pdf_data = test_helpers::create_minimal_pdf();
495 let cursor = Cursor::new(pdf_data);
496 let reader = PdfReader::new(cursor).unwrap();
497 let options = MemoryOptions::default();
498
499 let lazy_doc = LazyDocument::new(reader, options).unwrap();
500
501 let result = lazy_doc.preload_page(0);
502 assert!(result.is_err());
503
504 match result {
505 Err(PdfError::InvalidPageNumber(num)) => {
506 assert_eq!(num, 0);
507 }
508 _ => panic!("Expected InvalidPageNumber error"),
509 }
510 }
511
512 #[test]
513 fn test_lazy_document_memory_stats_initial() {
514 let pdf_data = test_helpers::create_minimal_pdf();
515 let cursor = Cursor::new(pdf_data);
516 let reader = PdfReader::new(cursor).unwrap();
517 let options = MemoryOptions::default();
518
519 let lazy_doc = LazyDocument::new(reader, options).unwrap();
520 let stats = lazy_doc.memory_stats();
521
522 assert_eq!(stats.cache_hits, 0);
524 assert_eq!(stats.cache_misses, 0);
525 assert_eq!(stats.allocated_bytes, 0);
526 }
527
528 #[test]
529 fn test_lazy_document_memory_stats_after_operations() {
530 let pdf_data = test_helpers::create_minimal_pdf();
531 let cursor = Cursor::new(pdf_data);
532 let reader = PdfReader::new(cursor).unwrap();
533 let options = MemoryOptions::default().with_cache_size(10);
534
535 let lazy_doc = LazyDocument::new(reader, options).unwrap();
536 let obj_id = ObjectId::new(1, 0);
537
538 let _ = lazy_doc.get_object(&obj_id);
540
541 let stats = lazy_doc.memory_stats();
542 assert!(stats.cache_misses > 0);
543 }
544
545 #[test]
546 fn test_lazy_document_clear_cache_empty() {
547 let pdf_data = test_helpers::create_minimal_pdf();
548 let cursor = Cursor::new(pdf_data);
549 let reader = PdfReader::new(cursor).unwrap();
550 let options = MemoryOptions::default();
551
552 let lazy_doc = LazyDocument::new(reader, options).unwrap();
553
554 lazy_doc.clear_cache();
556
557 let map = lazy_doc.object_map.read().unwrap();
559 assert!(map.is_empty());
560 }
561
562 #[test]
563 fn test_lazy_document_clear_cache_with_objects() {
564 let pdf_data = test_helpers::create_minimal_pdf();
565 let cursor = Cursor::new(pdf_data);
566 let reader = PdfReader::new(cursor).unwrap();
567 let options = MemoryOptions::default().with_cache_size(10);
568
569 let lazy_doc = LazyDocument::new(reader, options).unwrap();
570 let obj_id1 = ObjectId::new(1, 0);
571 let obj_id2 = ObjectId::new(2, 0);
572 let obj_id3 = ObjectId::new(3, 0);
573
574 {
576 let mut map = lazy_doc.object_map.write().unwrap();
577 map.insert(obj_id1, LazyObject::NotLoaded { offset: 100 });
578 map.insert(
579 obj_id2,
580 LazyObject::Loaded(Arc::new(PdfObject::Integer(42))),
581 );
582 map.insert(obj_id3, LazyObject::Loading);
583 }
584
585 lazy_doc.clear_cache();
586
587 {
589 let map = lazy_doc.object_map.read().unwrap();
590 assert_eq!(map.len(), 1); assert!(matches!(
592 map.get(&obj_id1),
593 Some(LazyObject::NotLoaded { .. })
594 ));
595 assert!(!map.contains_key(&obj_id2));
596 assert!(!map.contains_key(&obj_id3));
597 }
598 }
599
600 #[test]
601 fn test_lazy_page_iterator_creation() {
602 let pdf_data = test_helpers::create_minimal_pdf();
603 let cursor = Cursor::new(pdf_data);
604 let reader = PdfReader::new(cursor).unwrap();
605 let options = MemoryOptions::default();
606
607 let lazy_doc = Arc::new(LazyDocument::new(reader, options).unwrap());
608 let iterator = LazyPageIterator::new(lazy_doc.clone());
609
610 assert_eq!(iterator.current, 0);
611 assert_eq!(iterator.total, 0); assert!(Arc::ptr_eq(&iterator.document, &lazy_doc));
613 }
614
615 #[test]
616 fn test_lazy_page_iterator_empty_document() {
617 let pdf_data = test_helpers::create_minimal_pdf();
618 let cursor = Cursor::new(pdf_data);
619 let reader = PdfReader::new(cursor).unwrap();
620 let options = MemoryOptions::default();
621
622 let lazy_doc = Arc::new(LazyDocument::new(reader, options).unwrap());
623 let mut iterator = LazyPageIterator::new(lazy_doc);
624
625 assert!(iterator.next().is_none());
627 assert!(iterator.next().is_none()); }
629
630 #[test]
631 fn test_lazy_page_iterator_multiple_calls() {
632 let pdf_data = test_helpers::create_minimal_pdf();
633 let cursor = Cursor::new(pdf_data);
634 let reader = PdfReader::new(cursor).unwrap();
635 let options = MemoryOptions::default();
636
637 let lazy_doc = Arc::new(LazyDocument::new(reader, options).unwrap());
638 let mut iterator = LazyPageIterator::new(lazy_doc);
639
640 for _ in 0..5 {
642 assert!(iterator.next().is_none());
643 }
644 }
645
646 #[test]
647 fn test_lazy_document_with_different_memory_options() {
648 let pdf_data = test_helpers::create_minimal_pdf();
649 let cursor = Cursor::new(pdf_data);
650 let reader = PdfReader::new(cursor).unwrap();
651
652 let options = MemoryOptions::default().with_cache_size(100);
654
655 let lazy_doc = LazyDocument::new(reader, options).unwrap();
656
657 assert_eq!(lazy_doc.page_count(), 0);
658
659 let stats = lazy_doc.memory_stats();
660 assert_eq!(stats.cache_hits, 0);
661 assert_eq!(stats.cache_misses, 0);
662 }
663
664 #[test]
665 fn test_lazy_document_load_object_at_offset() {
666 let pdf_data = test_helpers::create_minimal_pdf();
667 let cursor = Cursor::new(pdf_data);
668 let reader = PdfReader::new(cursor).unwrap();
669 let options = MemoryOptions::default();
670
671 let lazy_doc = LazyDocument::new(reader, options).unwrap();
672
673 let obj_id = ObjectId::new(1, 0);
675
676 {
678 let mut map = lazy_doc.object_map.write().unwrap();
679 map.insert(obj_id, LazyObject::NotLoaded { offset: 1234 });
680 }
681
682 let result = lazy_doc.get_object(&obj_id);
683 assert!(result.is_ok());
684
685 let obj = result.unwrap();
686 assert_eq!(*obj, PdfObject::Null); }
688
689 #[test]
690 fn test_lazy_document_cache_hit_path() {
691 let pdf_data = test_helpers::create_minimal_pdf();
692 let cursor = Cursor::new(pdf_data);
693 let reader = PdfReader::new(cursor).unwrap();
694 let options = MemoryOptions::default().with_cache_size(10);
695
696 let lazy_doc = LazyDocument::new(reader, options).unwrap();
697 let obj_id = ObjectId::new(1, 0);
698 let test_obj = Arc::new(PdfObject::Real(3.14));
699
700 if let Some(cache) = lazy_doc.memory_manager.cache() {
702 cache.put(obj_id, test_obj.clone());
703 }
704
705 let result = lazy_doc.get_object(&obj_id);
706 assert!(result.is_ok());
707
708 let obj = result.unwrap();
709 assert_eq!(*obj, PdfObject::Real(3.14));
710 assert!(Arc::ptr_eq(&obj, &test_obj));
711
712 let stats = lazy_doc.memory_stats();
714 assert!(stats.cache_hits > 0);
715 }
716
717 #[test]
718 fn test_lazy_document_object_map_locking() {
719 let pdf_data = test_helpers::create_minimal_pdf();
720 let cursor = Cursor::new(pdf_data);
721 let reader = PdfReader::new(cursor).unwrap();
722 let options = MemoryOptions::default();
723
724 let lazy_doc = LazyDocument::new(reader, options).unwrap();
725 let obj_id = ObjectId::new(1, 0);
726
727 {
729 let _read_lock = lazy_doc.object_map.read().unwrap();
730 }
731
732 {
733 let mut write_lock = lazy_doc.object_map.write().unwrap();
734 write_lock.insert(obj_id, LazyObject::NotLoaded { offset: 500 });
735 }
736
737 {
739 let read_lock = lazy_doc.object_map.read().unwrap();
740 assert!(read_lock.contains_key(&obj_id));
741 }
742 }
743
744 #[test]
745 fn test_lazy_document_open_nonexistent_file() {
746 let nonexistent_path = "/path/that/does/not/exist.pdf";
747 let options = MemoryOptions::default();
748
749 let result = LazyDocument::open(nonexistent_path, options);
750 assert!(result.is_err());
751
752 match result {
753 Err(PdfError::ParseError(_)) => {}
754 _ => panic!("Expected ParseError for nonexistent file"),
755 }
756 }
757
758 #[test]
759 fn test_lazy_object_enum_all_variants() {
760 let variants = vec![
762 LazyObject::NotLoaded { offset: 12345 },
763 LazyObject::Loaded(Arc::new(PdfObject::String(crate::parser::PdfString::new(
764 b"test".to_vec(),
765 )))),
766 LazyObject::Loading,
767 ];
768
769 for (i, variant) in variants.into_iter().enumerate() {
770 match variant {
771 LazyObject::NotLoaded { offset } if i == 0 => {
772 assert_eq!(offset, 12345);
773 }
774 LazyObject::Loaded(obj) if i == 1 => match &*obj {
775 PdfObject::String(_) => {}
776 _ => panic!("Expected String object"),
777 },
778 LazyObject::Loading if i == 2 => {
779 }
781 _ => panic!("Unexpected variant at index {i}"),
782 }
783 }
784 }
785
786 #[test]
787 fn test_lazy_page_iterator_with_document_reference() {
788 let pdf_data = test_helpers::create_minimal_pdf();
789 let cursor = Cursor::new(pdf_data);
790 let reader = PdfReader::new(cursor).unwrap();
791 let options = MemoryOptions::default();
792
793 let lazy_doc = Arc::new(LazyDocument::new(reader, options).unwrap());
794 let _iterator = LazyPageIterator::new(lazy_doc.clone());
795
796 assert_eq!(lazy_doc.page_count(), 0);
798 }
799
800 #[test]
801 fn test_lazy_document_concurrent_access_simulation() {
802 use std::sync::Arc;
803 use std::thread;
804
805 let pdf_data = test_helpers::create_minimal_pdf();
806 let cursor = Cursor::new(pdf_data);
807 let reader = PdfReader::new(cursor).unwrap();
808 let options = MemoryOptions::default().with_cache_size(10);
809
810 let lazy_doc = Arc::new(LazyDocument::new(reader, options).unwrap());
811 let mut handles = vec![];
812
813 for i in 0..3 {
815 let doc_clone = lazy_doc.clone();
816 let handle = thread::spawn(move || {
817 let obj_id = ObjectId::new(i + 1, 0);
818
819 let _result = doc_clone.get_object(&obj_id);
821
822 let _stats = doc_clone.memory_stats();
824
825 doc_clone.clear_cache();
827 });
828 handles.push(handle);
829 }
830
831 for handle in handles {
832 handle.join().unwrap();
833 }
834
835 assert_eq!(lazy_doc.page_count(), 0);
837 }
838}