1use std::io::{Stdout, stdout, Write};
2use std::time::SystemTime;
3
4pub struct Progress<T> {
5 current_index: usize,
6 start_time: SystemTime,
7 iter_size: usize,
8 inner: Box<dyn Iterator<Item=T>>,
9 progbar: Vec<u8>,
10 progbar_size: usize,
11 output: Stdout
12}
13
14
15impl<T> Progress<T> {
16 fn size_hint(mut self, size:usize) -> Progress<T> {
17 self.iter_size = size;
18
19 let prog_size = if size > 60 { 60 } else {size};
20
21 if self.progbar_size != prog_size {
22 self.progbar_size = prog_size;
23 self.progbar = vec![0x20; prog_size];
24 }
25 self
26 }
27}
28
29
30pub fn progress<T>(boxed: Box<dyn Iterator<Item=T>>) -> Progress<T> {
31
32 let p = Progress{
33 current_index:0,
34 start_time: SystemTime::now(),
35 iter_size: 0,
36 inner: boxed,
37 progbar: vec![],
38 progbar_size: 0,
39 output: stdout(),
40 };
41 let size = p.inner.size_hint().0;
42 p.size_hint(size)
43}
44
45
46pub trait Progressable<T> : Iterator<Item=T> where Self: Sized, Self: 'static {
47 #[inline]
48 fn prog(self) -> Progress<T> {
49 let b = Box::new(self);
50 progress(b)
51 }
52}
53
54impl<T, V> Progressable<V> for T where T : Iterator<Item=V>, T: 'static {}
55
56impl<T> Iterator for Progress<T> {
57 type Item = T;
58 fn next(&mut self) -> Option<T> {
59 let n = self.inner.next();
60
61 if n.is_some() {
62 let i = self.current_index * self.progbar_size / self.iter_size;
63 let j = ((self.current_index as i128 - 1) & (1 as i128).rotate_right(1)) as usize * self.progbar_size / self.iter_size;
64
65 if i != j || i == 0 {
66 self.progbar[i] = 0x23; }
68
69 let iter_rate = match self.start_time.elapsed() {
70 Ok(elapsed) => match elapsed.as_secs() {
71 e if e > 0 => self.current_index as f32 / (e) as f32,
72 _ => -1.0
73 },
74 Err(_) => -1.0
75 };
76
77 if iter_rate == -1.0 {
78
79 print!("\r[{bar}] {cur}/{max} [? it/sec] ",
80 bar=String::from_utf8(self.progbar.clone()).unwrap(),
81 cur=self.current_index,
82 max=self.iter_size
83 );
84 }
85 else {
86
87 print!("\r[{bar}] {cur}/{max} [{rate:.3} it/sec] ",
88 bar=String::from_utf8(self.progbar.clone()).unwrap(),
89 cur=self.current_index,
90 max=self.iter_size,
91 rate=iter_rate
92 );
93 }
94 self.output.flush().unwrap();
95
96 }
97 else if self.current_index == self.iter_size {
98 println!("")
99 }
100
101 self.current_index += 1;
102 n
103 }
104}
105
106
107#[cfg(test)]
108mod tests {
109
110 use super::*;
111 use std::array::IntoIter;
112
113 fn test_call() {
114 let arr = [1,2,3,4,5,6,7,8,9];
115 let sum = IntoIter::new(arr).prog().reduce(|a,b| {a+b}).unwrap();
116
117 assert_eq!(45, sum);
118
119 let range = 1..10;
120 let double_sum = range.into_iter().map(|e| {e*2}).reduce(|a,b| {a+b}).unwrap();
121
122 assert_eq!(90, double_sum);
123
124
125 let s = "qwerty";
126 let mut count = 0;
127 for c in s.chars().prog() {
128 count+=1;
129 }
130
131 assert_eq!(6, count);
132 }
133}