1use super::{entry::Entry, seek, Result};
2use chrono::prelude::*;
3use rand::distributions::{Distribution, Uniform};
4use std::convert::TryInto;
5use std::io::{BufRead, Read, Seek, SeekFrom};
6
7pub struct Entries<T: Seek + Read + BufRead> {
8 f: T,
9 buf: String,
10}
11
12impl<T: Seek + Read + BufRead> Entries<T> {
13 pub fn new(f: T) -> Self {
14 Entries {
15 f,
16 buf: String::with_capacity(4096),
17 }
18 }
19
20 pub fn len(&mut self) -> Result<u64> {
21 let prev = self.f.stream_position()?;
22 let len = self.f.seek(SeekFrom::End(0))?;
23 self.f.seek(SeekFrom::Start(prev))?;
24 Ok(len)
25 }
26
27 pub fn is_empty(&mut self) -> Result<bool> {
28 Ok(self.len()? == 0)
29 }
30
31 pub fn at(&mut self, pos: u64) -> Result<Option<Entry>> {
32 if pos > self.len()? {
33 return Ok(None);
34 }
35
36 self.f.seek(SeekFrom::Start(pos))?;
37 seek::start_of_current_line(&mut self.f)?;
38 self.next_entry()
39 }
40
41 pub fn seek_to_end(&mut self) -> Result<()> {
42 let len = self.len()?;
43 self.at(len)?;
44 Ok(())
45 }
46
47 pub fn seek_to_next(&mut self) -> Result<Option<u64>> {
48 seek::start_of_next_line(&mut self.f)
49 }
50
51 pub fn seek_to_prev(&mut self) -> Result<Option<u64>> {
52 seek::start_of_prev_line(&mut self.f)
53 }
54
55 pub fn next_entry(&mut self) -> Result<Option<Entry>> {
56 self.buf.clear();
57 self.f.read_line(&mut self.buf)?;
58
59 if self.buf.is_empty() {
66 self.f.seek(SeekFrom::End(1))?;
67 return Ok(None);
68 }
69
70 let row = quick_csv::Csv::from_reader(self.buf.as_bytes())
71 .next()
72 .unwrap()?;
73 Ok(Some(row.try_into()?))
74 }
75
76 pub fn rand_entry(&mut self) -> Result<Option<Entry>> {
77 let mut rng = rand::thread_rng();
78 let range = Uniform::new(0, self.len()?);
79 self.at(range.sample(&mut rng))
80 }
81
82 pub fn prev_entry(&mut self) -> Result<Option<Entry>> {
83 if self.f.stream_position()? <= self.len()? {
89 self.seek_to_prev()?;
90 }
91
92 if self.seek_to_prev()?.is_none() {
96 return Ok(None);
97 }
98
99 self.next_entry()
100 }
101
102 pub fn seek_to_first(&mut self, date: &chrono::DateTime<FixedOffset>) -> Result<()> {
103 let file_size = self.len()?;
104 let mut end = file_size;
105 let mut start = self.f.seek(SeekFrom::Start(0))?;
106
107 while start < end {
108 let cur = start + (end - start) / 2;
109
110 let entry = match self.at(cur)? {
111 Some(entry) => entry,
112 None => break,
118 };
119
120 if entry.datetime() >= date {
121 if cur == 0 {
122 break;
123 }
124 end = cur - 1;
125 } else {
126 if cur == file_size {
127 break;
128 }
129 start = cur + 1;
130 }
131 }
132
133 if end >= file_size {
148 return Ok(());
149 }
150
151 self.next_entry()?;
154
155 loop {
156 match self.prev_entry()? {
157 None => break,
158 Some(entry) => {
159 if entry.datetime() < date {
160 break;
161 }
162 }
163 }
164 }
165
166 Ok(())
167 }
168}
169
170impl<T: Seek + Read + BufRead> Iterator for Entries<T> {
171 type Item = Result<Entry>;
172
173 fn next(&mut self) -> Option<Self::Item> {
174 match self.next_entry() {
175 Ok(opt) => opt.map(Ok),
176 Err(e) => Some(Err(e)),
177 }
178 }
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184 use std::io::Cursor;
185 use test_case::test_case;
186
187 const TESTDATA: &str = "2020-01-01T00:01:00.899849209+00:00,\"\"\"1\"\"\"
1892020-02-12T23:08:40.987613062+00:00,\"\"\"2\"\"\"
1902020-03-12T00:00:00.000000000+00:00,\"\"\"3\"\"\"
1912020-04-12T23:28:45.726598931+00:00,\"\"\"4\"\"\"
1922020-05-12T23:28:48.495151445+00:00,\"\"\"5\"\"\"
1932020-06-13T10:12:53.353050231+00:00,\"\"\"6\"\"\"
194";
195
196 #[allow(clippy::identity_op, clippy::erasing_op)]
200 #[test_case(44 * 0 + 0 => Some("1".to_owned()))]
201 #[test_case(44 * 0 + 10 => Some("1".to_owned()))]
202 #[test_case(44 * 0 + 43 => Some("1".to_owned()))]
203 #[test_case(44 * 1 + 0 => Some("2".to_owned()))]
204 #[test_case(44 * 1 + 10 => Some("2".to_owned()))]
205 #[test_case(44 * 1 + 43 => Some("2".to_owned()))]
206 #[test_case(44 * 2 + 0 => Some("3".to_owned()))]
207 #[test_case(44 * 2 + 10 => Some("3".to_owned()))]
208 #[test_case(44 * 2 + 43 => Some("3".to_owned()))]
209 #[test_case(44 * 3 + 0 => Some("4".to_owned()))]
210 #[test_case(44 * 3 + 10 => Some("4".to_owned()))]
211 #[test_case(44 * 3 + 43 => Some("4".to_owned()))]
212 #[test_case(44 * 4 + 0 => Some("5".to_owned()))]
213 #[test_case(44 * 4 + 10 => Some("5".to_owned()))]
214 #[test_case(44 * 4 + 43 => Some("5".to_owned()))]
215 #[test_case(44 * 5 + 0 => Some("6".to_owned()))]
216 #[test_case(44 * 5 + 10 => Some("6".to_owned()))]
217 #[test_case(44 * 5 + 43 => Some("6".to_owned()))]
218 #[test_case(44 * 6 + 0 => None)]
219 #[test_case(44 * 7 + 0 => None)]
220 #[test_case(44 * 8 + 0 => None)]
221 fn test_entry_at(pos: u64) -> Option<String> {
222 let r = Cursor::new(Vec::from(TESTDATA.as_bytes()));
223 Entries::new(r)
224 .at(pos)
225 .unwrap()
226 .map(|e| e.message().to_owned())
227 }
228
229 #[test_case("2020-01-01T00:01:00.899849209+00:00" => Some("1".to_owned()))]
231 #[test_case("2020-02-12T23:08:40.987613062+00:00" => Some("2".to_owned()))]
232 #[test_case("2020-03-12T00:00:00.000000000+00:00" => Some("3".to_owned()))]
233 #[test_case("2020-04-12T23:28:45.726598931+00:00" => Some("4".to_owned()))]
234 #[test_case("2020-05-12T23:28:48.495151445+00:00" => Some("5".to_owned()))]
235 #[test_case("2020-06-13T10:12:53.353050231+00:00" => Some("6".to_owned()))]
236 #[test_case("2000-01-01T00:01:00.000000000+00:00" => Some("1".to_owned()))]
238 #[test_case("2021-01-01T00:00:00.000000000+00:00" => None)]
239 #[test_case("2020-02-12T23:08:00+00:00" => Some("2".to_owned()))]
242 #[test_case("2020-02-12T23:59:00+00:00" => Some("3".to_owned()))]
243 #[test_case("2020-04-12T23:27:00+00:00" => Some("4".to_owned()))]
244 #[test_case("2020-05-12T23:27:00+00:00" => Some("5".to_owned()))]
245 #[test_case("2020-06-13T10:00:00+00:00" => Some("6".to_owned()))]
246 fn test_seek_to_first(date_str: &str) -> Option<String> {
247 let date = DateTime::parse_from_rfc3339(date_str).unwrap();
248 let r = Cursor::new(Vec::from(TESTDATA.as_bytes()));
249 let mut entries = Entries::new(r);
250 entries.seek_to_first(&date).unwrap();
251 entries
252 .next_entry()
253 .unwrap()
254 .map(|e| e.message().to_owned())
255 }
256
257 #[test]
258 fn test_seek_to_first_single_entry() {
259 let date = DateTime::parse_from_rfc3339("2021-04-02T00:00:00Z").unwrap();
260 let r = Cursor::new(Vec::from(
261 "2021-04-02T20:05:39.428673666+00:00,\"\"\"Hello world\"\"\"\n".as_bytes(),
262 ));
263 let mut entries = Entries::new(r);
264 entries.seek_to_first(&date).unwrap();
265 let message = entries
266 .next_entry()
267 .unwrap()
268 .map(|e| e.message().to_owned());
269
270 assert_eq!(message, Some("Hello world".to_string()));
271 }
272
273 #[test]
274 fn test_navigating_entries() -> Result<()> {
275 let r = Cursor::new(Vec::from(TESTDATA.as_bytes()));
276 let mut entries = Entries::new(r);
277
278 assert_eq!(entries.next_entry()?.unwrap().message(), "1");
279 assert_eq!(entries.next_entry()?.unwrap().message(), "2");
280 assert_eq!(entries.next_entry()?.unwrap().message(), "3");
281 assert_eq!(entries.next_entry()?.unwrap().message(), "4");
282 assert_eq!(entries.next_entry()?.unwrap().message(), "5");
283 assert_eq!(entries.next_entry()?.unwrap().message(), "6");
284 assert!(entries.next_entry()?.is_none());
285 assert_eq!(entries.prev_entry()?.unwrap().message(), "6");
286 assert_eq!(entries.prev_entry()?.unwrap().message(), "5");
287 assert_eq!(entries.prev_entry()?.unwrap().message(), "4");
288 assert_eq!(entries.prev_entry()?.unwrap().message(), "3");
289 assert_eq!(entries.prev_entry()?.unwrap().message(), "2");
290 assert_eq!(entries.prev_entry()?.unwrap().message(), "1");
291 assert!(entries.prev_entry()?.is_none());
292 assert!(entries.prev_entry()?.is_none());
293 assert!(entries.prev_entry()?.is_none());
294 assert_eq!(entries.next_entry()?.unwrap().message(), "1");
295 assert_eq!(entries.next_entry()?.unwrap().message(), "2");
296 assert_eq!(entries.next_entry()?.unwrap().message(), "3");
297 assert_eq!(entries.next_entry()?.unwrap().message(), "4");
298 assert_eq!(entries.next_entry()?.unwrap().message(), "5");
299 assert_eq!(entries.next_entry()?.unwrap().message(), "6");
300 assert!(entries.next_entry()?.is_none());
301 Ok(())
302 }
303
304 #[test]
305 fn test_seek_to_end() -> Result<()> {
306 let r = Cursor::new(Vec::from(TESTDATA.as_bytes()));
307 let mut entries = Entries::new(r);
308
309 entries.seek_to_end()?;
310 assert_eq!(entries.prev_entry()?.unwrap().message(), "6");
311 Ok(())
312 }
313
314 #[test]
315 fn test_iterator() {
316 let r = Cursor::new(Vec::from(TESTDATA.as_bytes()));
317 let mut entries = Entries::new(r);
318
319 assert_eq!(entries.next().unwrap().unwrap().message(), "1");
320 assert_eq!(entries.next().unwrap().unwrap().message(), "2");
321 assert_eq!(entries.next().unwrap().unwrap().message(), "3");
322 assert_eq!(entries.next().unwrap().unwrap().message(), "4");
323 assert_eq!(entries.next().unwrap().unwrap().message(), "5");
324 assert_eq!(entries.next().unwrap().unwrap().message(), "6");
325 assert!(entries.next().is_none());
326 }
327}