caj2pdf_core/operations/
observe.rs1use super::{Detection, InputFormat, detect_source};
7use crate::{Cancellation, ErrorKind, Limits, NeverCancel, RangedSource, Result};
8use std::cell::RefCell;
9
10pub trait Progress {
14 fn format(&mut self, _format: Option<InputFormat>) {}
18
19 fn input_read(&mut self, _done: u64, _total: u64) {}
23
24 fn is_cancelled(&self) -> bool {
28 false
29 }
30}
31
32impl Progress for NeverCancel {}
34
35pub(super) fn refused() -> crate::Error {
39 ErrorKind::UnsupportedFormat.into()
40}
41
42pub(super) struct Observer<'p> {
44 progress: RefCell<&'p mut dyn Progress>,
45}
46
47impl<'p> Observer<'p> {
48 pub(super) fn new(progress: &'p mut dyn Progress) -> Self {
49 Self {
50 progress: RefCell::new(progress),
51 }
52 }
53
54 pub(super) fn track<'a, S: RangedSource>(&'a self, source: &'a mut S) -> Tracked<'a, 'p, S> {
56 Tracked {
57 source,
58 observer: self,
59 furthest: 0,
60 }
61 }
62
63 pub(super) fn resolve<S: RangedSource>(
67 &self,
68 source: &mut S,
69 format: Option<InputFormat>,
70 limits: &Limits,
71 ) -> Result<Detection> {
72 let detection = match format {
73 Some(format) => Some(Detection {
74 format,
75 header_offset: 0,
76 bytes_read: 0,
77 }),
78 None => detect_source(source, limits, self)?,
79 };
80 self.progress
81 .borrow_mut()
82 .format(detection.map(|detection| detection.format));
83 detection.ok_or_else(refused)
84 }
85}
86
87impl Cancellation for Observer<'_> {
88 fn is_cancelled(&self) -> bool {
89 self.progress.borrow().is_cancelled()
90 }
91}
92
93pub(super) struct Tracked<'a, 'p, S> {
95 source: &'a mut S,
96 observer: &'a Observer<'p>,
97 furthest: u64,
98}
99
100impl<S: RangedSource> RangedSource for Tracked<'_, '_, S> {
101 fn size(&self) -> u64 {
102 self.source.size()
103 }
104
105 fn read_at(&mut self, offset: u64, destination: &mut [u8]) -> Result<usize> {
106 let count = self.source.read_at(offset, destination)?;
107 let end = offset.saturating_add(count as u64);
108 if end > self.furthest {
109 self.furthest = end;
110 let total = self.source.size();
111 self.observer.progress.borrow_mut().input_read(end, total);
112 }
113 Ok(count)
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120
121 #[derive(Default)]
122 struct Recorded {
123 formats: Vec<Option<InputFormat>>,
124 reads: Vec<(u64, u64)>,
125 }
126
127 impl Progress for Recorded {
128 fn format(&mut self, format: Option<InputFormat>) {
129 self.formats.push(format);
130 }
131
132 fn input_read(&mut self, done: u64, total: u64) {
133 self.reads.push((done, total));
134 }
135 }
136
137 #[test]
138 fn the_furthest_byte_read_is_reported_once_per_advance() {
139 let mut recorded = Recorded::default();
140 {
141 let observer = Observer::new(&mut recorded);
142 let bytes = [7; 200];
143 let mut slice = &bytes[..];
144 let mut source = observer.track(&mut slice);
145 let mut buffer = [0; 100];
146 assert_eq!(source.read_at(0, &mut buffer).unwrap(), 100);
147 source.read_at(0, &mut buffer[..10]).unwrap();
148 source.read_at(100, &mut buffer[..1]).unwrap();
149 source.read_at(150, &mut buffer).unwrap();
150 assert!(source.read_at(201, &mut buffer).is_err());
151 assert_eq!(source.size(), 200);
152 assert!(!observer.is_cancelled());
153 }
154 assert_eq!(recorded.reads, [(100, 200), (101, 200), (200, 200)]);
155 }
156
157 #[test]
158 fn the_format_is_reported_before_an_unrecognized_input_is_refused() {
159 let mut recorded = Recorded::default();
160 {
161 let observer = Observer::new(&mut recorded);
162 let limits = Limits::default();
163 let error = observer
164 .resolve(&mut &b"unknown"[..], None, &limits)
165 .unwrap_err();
166 assert!(matches!(error.kind, ErrorKind::UnsupportedFormat));
167 assert_eq!(error.to_string(), "unsupported input format");
168 let explicit = observer
169 .resolve(&mut &b""[..], Some(InputFormat::Teb), &limits)
170 .unwrap();
171 assert_eq!(
172 (explicit.format, explicit.bytes_read),
173 (InputFormat::Teb, 0)
174 );
175 }
176 assert_eq!(recorded.formats, [None, Some(InputFormat::Teb)]);
177 }
178}