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}