indeedee/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use std::time::{Duration, Instant};
4
5pub struct ProgressiveWaiter<L, I>
6where
7    L: Loader,
8    I: Iterator<Item = L::Data>,
9{
10    data: I,
11    loader: Option<L>,
12    count: usize,
13}
14
15impl<L, I> ProgressiveWaiter<L, I>
16where
17    L: Loader,
18    I: Iterator<Item = L::Data>,
19{
20    pub fn new(loader: L, data: I) -> Self {
21        Self {
22            data,
23            loader: Some(loader),
24            count: 0,
25        }
26    }
27
28    pub fn query(&mut self, allowed_time: Duration, context: &L::Context) -> LoadResult<L> {
29        let loader = match self.loader {
30            Some(ref mut loader) => loader,
31            None => panic!("tried to query after the loader was done."),
32        };
33
34        let start_time = Instant::now();
35
36        while let Some(next) = self.data.next() {
37            self.count += 1;
38            let update = loader.operate(next, &context);
39
40            if start_time.elapsed() >= allowed_time {
41                return LoadResult::Loading(update);
42            }
43        }
44
45        let output = self.loader.take().unwrap().finish(&context);
46        LoadResult::Done(output)
47    }
48
49    /// How many elements we've processed.
50    pub fn finished_count(&self) -> usize {
51        self.count
52    }
53
54    pub fn loader(&self) -> &L {
55        self.loader.as_ref().unwrap()
56    }
57
58    pub fn loader_mut(&mut self) -> &mut L {
59        self.loader.as_mut().unwrap()
60    }
61}
62
63impl<L, I> ProgressiveWaiter<L, I>
64where
65    L: Loader,
66    I: ExactSizeIterator<Item = L::Data>,
67{
68    /// How many total elements there are to process (including ones we already did).
69    pub fn total_elements(&self) -> usize {
70        self.count + self.data.len()
71    }
72
73    /// How many elements there are left to process.
74    pub fn elements_left(&self) -> usize {
75        self.data.len()
76    }
77
78    /// How far we are through, as a proportion from 0 to 1.
79    pub fn progress(&self) -> f64 {
80        self.count as f64 / self.total_elements() as f64
81    }
82}
83
84/// Something that handles a stream of data that might take a long time.
85pub trait Loader {
86    /// Type this operates over.
87    type Data;
88
89    /// An update on what the loader is currently working. This is just for informative purposes, if you care about that kind of thing...
90    /// but you can also just use `()`.
91    type ProgressUpdate;
92
93    /// What this produces when it's done.
94    type Output;
95
96    /// Any context this might need to do its work.
97    type Context;
98
99    /// Perform an update on one piece of data.
100    fn operate(&mut self, data: Self::Data, ctx: &Self::Context) -> Self::ProgressUpdate;
101
102    /// Once this is all through, consume itself and return the thing it's been building towards.
103    fn finish(self, ctx: &Self::Context) -> Self::Output;
104}
105
106/// Whether we've finished with this loader.
107#[derive(Debug)]
108pub enum LoadResult<L: Loader> {
109    /// We have not finished loading, and here's a progress update
110    Loading(L::ProgressUpdate),
111    /// We're done, and here's the output!
112    Done(L::Output),
113}