1use crate::error::ParseError;
4use crate::iterators::ConFrameIterator;
5use crate::types::ConFrame;
6use std::io::{self, Read};
7use std::path::Path;
8
9pub type StreamError = Box<dyn std::error::Error + Send + Sync>;
12
13pub const DEFAULT_READ_SIZE: usize = 1 << 20;
15
16pub struct ConFrameReader<R> {
36 src: R,
37 buf: Vec<u8>,
39 start: usize,
40 end: usize,
41 read_size: usize,
42 eof: bool,
43 failed: Option<io::Error>,
44 done: bool,
45}
46
47impl ConFrameReader<Box<dyn Read + Send>> {
48 pub fn open(path: &Path) -> Result<Self, Box<dyn std::error::Error>> {
51 Ok(Self::new(crate::compression::open_decoded(path)?))
52 }
53}
54
55impl<R: Read> ConFrameReader<R> {
56 pub fn new(src: R) -> Self {
58 Self::with_read_size(src, DEFAULT_READ_SIZE)
59 }
60
61 pub fn with_read_size(src: R, read_size: usize) -> Self {
64 Self {
65 src,
66 buf: Vec::new(),
67 start: 0,
68 end: 0,
69 read_size: read_size.max(1),
70 eof: false,
71 failed: None,
72 done: false,
73 }
74 }
75
76 pub fn forward(&mut self) -> Option<Result<(), StreamError>> {
79 self.step(|it| it.forward().map(|r| r.map(|()| ((), it.byte_pos()))))
80 }
81
82 fn step<T>(
92 &mut self,
93 mut op: impl FnMut(&mut ConFrameIterator<'_>) -> Option<Result<(T, usize), ParseError>>,
94 ) -> Option<Result<T, StreamError>> {
95 let mut cut = false;
96 while !self.done {
97 let ended = self.eof || self.failed.is_some();
98 let rest = &self.buf[self.start..self.end];
99 let text = if ended {
100 rest
101 } else {
102 memchr::memrchr(b'\n', rest).map_or(&rest[..0], |i| &rest[..=i])
103 };
104 if ended || !cut || {
108 let mut probe = ConFrameIterator::from_bytes(text);
109 probe.forward();
110 settled(text, probe.byte_pos())
111 } {
112 let mut it = ConFrameIterator::from_bytes(text);
113 let result = op(&mut it);
114 if ended || settled(text, it.byte_pos()) {
115 match result {
116 Some(Ok((value, used))) => {
117 self.start += used;
118 return Some(Ok(value));
119 }
120 other if self.failed.is_none() => {
121 self.done = true;
122 return other.map(|r| r.map(|(value, _)| value).map_err(Into::into));
123 }
124 _ => {}
125 }
126 }
127 }
128 cut = true;
129 if let Some(e) = self.failed.take() {
130 self.done = true;
131 return Some(Err(e.into()));
132 }
133 self.fill();
134 }
135 None
136 }
137
138 fn fill(&mut self) {
143 self.buf.copy_within(self.start..self.end, 0);
144 self.end -= self.start;
145 self.start = 0;
146 let target = self.end + self.read_size.max(self.end / 8);
147 if target > self.buf.len() {
148 self.buf.reserve_exact(target - self.buf.len());
149 self.buf.resize(target, 0);
150 }
151 while self.end < target {
152 match self.src.read(&mut self.buf[self.end..target]) {
153 Ok(0) => {
154 self.eof = true;
155 return;
156 }
157 Ok(n) => self.end += n,
158 Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
159 Err(e) => {
160 self.failed = Some(e);
161 return;
162 }
163 }
164 }
165 }
166}
167
168fn settled(text: &[u8], pos: usize) -> bool {
176 let mut lines = text[pos.min(text.len())..].split_inclusive(|&b| b == b'\n');
177 lines
178 .find(|line| !line.iter().all(u8::is_ascii_whitespace))
179 .is_some()
180 && lines.next().is_some()
181}
182
183impl<R: Read> Iterator for ConFrameReader<R> {
184 type Item = Result<ConFrame, StreamError>;
185
186 fn next(&mut self) -> Option<Self::Item> {
187 self.step(|it| it.next_with_end())
188 }
189}
190
191#[cfg(test)]
192mod tests {
193 use super::*;
194
195 fn zero_atom_frame(len: usize) -> Vec<u8> {
197 let tail = "\n{\"con_spec_version\":2}\n10.000000 10.000000 10.000000\n\
198 90.000000 90.000000 90.000000\n\n\n0\n\n\n";
199 let mut frame = vec![b'U'; len - tail.len()];
200 frame.extend_from_slice(tail.as_bytes());
201 frame
202 }
203
204 fn after_first(frame: &[u8], after: &[u8]) -> (usize, usize) {
206 let text = [frame, after].concat();
207 let mut reader = ConFrameReader::new(&text[..]);
208 let want = ConFrameIterator::from_bytes(frame).next().unwrap().unwrap();
209 assert_eq!(reader.next().unwrap().unwrap(), want);
210 assert_eq!(reader.start, frame.len());
211 (reader.buf.len(), reader.buf.capacity())
212 }
213
214 #[test]
215 fn a_frame_over_one_read_grows_the_buffer_to_about_one_frame_and_one_read() {
216 let small = zero_atom_frame(100).repeat(2);
217 for len in [(1 << 20) + 57, (1 << 21) + 57] {
218 let frame = zero_atom_frame(len);
219 for after in [&small[..], &[][..]] {
220 let (filled, capacity) = after_first(&frame, after);
221 assert!(filled <= capacity);
222 assert!(
223 capacity <= len + DEFAULT_READ_SIZE,
224 "frame {len}, {} bytes after it: capacity {capacity}",
225 after.len()
226 );
227 }
228 }
229 }
230
231 #[test]
232 fn a_frame_of_many_reads_grows_the_buffer_by_an_eighth_at_most() {
233 let read_size = 4096;
234 let len = 64 * read_size + 57;
235 let text = [zero_atom_frame(len), zero_atom_frame(100)]
236 .concat()
237 .repeat(2);
238 let mut reader = ConFrameReader::with_read_size(&text[..], read_size);
239 for _ in 0..4 {
240 assert!(reader.next().unwrap().is_ok());
241 assert!(reader.buf.capacity() <= len + len / 8 + read_size);
242 }
243 assert!(reader.next().is_none());
244 }
245}