use crate::LoadlessIteratorExt;
use colored::Color;
use std::io::{stdout, Write};
const MOVE_BEGINNING_LINE: &str = "\x1b[1F";
const CLEAR_LINE: &str = "\x1b[2K";
pub struct LoadlessIterator<'a, Iterator> {
iter: Iterator,
idx: usize,
size: usize,
prog_len: usize,
prog_ch: char,
prog_color: Option<Color>,
wrap_ch: [char; 2],
wrap_color: Option<Color>,
target: WriteTarget<'a>,
}
enum WriteTarget<'a> {
Stdout,
Custom(&'a mut dyn Write),
}
impl<'a, Iter: Iterator> LoadlessIteratorExt<'a> for Iter {
fn loadless(self) -> LoadlessIterator<'a, Self> {
return LoadlessIterator::default(self);
}
}
impl<'a, Iter: Iterator> LoadlessIterator<'a, Iter> {
pub fn default(iter: Iter) -> Self {
let size;
match iter.size_hint().1 {
Some(s) => size = s,
None => size = iter.size_hint().0,
}
let mut prog_len: usize = size;
if size > 10 {
prog_len = 10;
}
return LoadlessIterator {
iter,
idx: 0,
size,
prog_len,
prog_ch: '▓',
prog_color: None,
wrap_ch: ['[', ']'],
wrap_color: None,
target: WriteTarget::Stdout,
};
}
pub fn write_target(mut self, target: &'a mut dyn Write) -> Self {
self.target = WriteTarget::Custom(target);
return self;
}
fn write_ln(&mut self) -> Result<(), std::io::Error> {
let wrap_color: String;
let prog_color;
match self.wrap_color {
Some(color) => wrap_color = color.to_fg_str().into(),
None => wrap_color = "".to_string(),
}
match self.prog_color {
Some(color) => prog_color = color.to_fg_str().into(),
None => prog_color = "".to_string(),
}
let space_count = self
.prog_len
.checked_sub(self.idx / (self.size / self.prog_len));
let output = format!(
"{}{}{}{}{}{}{}{}",
if self.idx != 0 {
format!("{MOVE_BEGINNING_LINE}{CLEAR_LINE}")
} else {
"".to_string()
},
&wrap_color,
self.wrap_ch[0],
&prog_color,
self.prog_ch
.to_string()
.repeat(self.idx / (self.size / self.prog_len)),
" ".to_string()
.repeat(if let Some(space_count) = space_count {
space_count as usize
} else {
0 as usize
}),
&wrap_color,
self.wrap_ch[1],
);
match &mut self.target {
WriteTarget::Stdout => {
writeln!(stdout(), "{output}")?;
}
WriteTarget::Custom(wt) => {
writeln!(wt, "{output}")?;
}
}
self.idx += 1;
return Ok(());
}
}
impl<'a, Iter: Iterator> Iterator for LoadlessIterator<'a, Iter> {
type Item = Iter::Item;
fn next(&mut self) -> Option<Self::Item> {
let _ = self.write_ln();
return self.iter.next();
}
}