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 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 pub fn total_elements(&self) -> usize {
70 self.count + self.data.len()
71 }
72
73 pub fn elements_left(&self) -> usize {
75 self.data.len()
76 }
77
78 pub fn progress(&self) -> f64 {
80 self.count as f64 / self.total_elements() as f64
81 }
82}
83
84pub trait Loader {
86 type Data;
88
89 type ProgressUpdate;
92
93 type Output;
95
96 type Context;
98
99 fn operate(&mut self, data: Self::Data, ctx: &Self::Context) -> Self::ProgressUpdate;
101
102 fn finish(self, ctx: &Self::Context) -> Self::Output;
104}
105
106#[derive(Debug)]
108pub enum LoadResult<L: Loader> {
109 Loading(L::ProgressUpdate),
111 Done(L::Output),
113}