#![forbid(unsafe_code)]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
use std::sync::Mutex;
#[macro_use]
extern crate lazy_static;
lazy_static! {
static ref TEXT: Mutex<String> = Mutex::new(String::new());
}
#[derive(Debug)]
pub struct Tqdm;
impl Tqdm {
#[allow(clippy::new_ret_no_self)]
pub fn new<I: Iterator>(iter: I) -> TqdmAuto<I> {
let total = iter.size_hint().0;
TqdmAuto {
iter,
current: 0,
total,
}
}
pub fn manual(total: usize) -> TqdmManual {
TqdmManual { current: 0, total }
}
}
pub fn write(text: &str) {
let mut msg = TEXT.lock().unwrap();
*msg = String::from(text);
}
fn clear_previous_line() {
print!("\x1b[1A");
print!("\r");
let size = terminal_size::terminal_size()
.unwrap_or((terminal_size::Width(120), terminal_size::Height(120)));
let width = size.0 .0 as usize;
print!("{}", " ".repeat(width));
print!("\r");
}
trait WriteCon {
fn get_current_amount(&self) -> usize {
0
}
fn get_total_amount(&self) -> usize {
0
}
fn get_percentage(&self) -> usize {
let fraction = self.get_current_amount() as f32 / self.get_total_amount() as f32;
(fraction * 100.0).round() as usize
}
fn create_bar(&self) -> String {
let percents = self.get_percentage();
let current = self.get_current_amount();
let total = self.get_total_amount();
let length = total.to_string().len();
let mut bar = String::new();
bar += "[";
for x in 1..=20 {
if x * 5 <= percents {
bar += "#"
} else {
bar += " "
}
}
bar += "]";
format!(
"{:>3}% {} {:>length$}/{}",
percents,
bar,
current,
total,
length = length
)
}
fn display(&self) {
let bar = self.create_bar();
let mut text = TEXT.lock().unwrap();
if self.get_current_amount() == 0 {
return;
}
let lines = text.matches('\n').count();
if self.get_current_amount() == 1 && lines > 0 {
for _ in 0..=lines + 1 {
println!();
}
}
for _ in 0..lines {
clear_previous_line();
}
if lines > 0 {
clear_previous_line();
clear_previous_line();
}
if !text.is_empty() {
println!("{}", text);
*text = String::new();
}
println!("{}", bar);
}
}
#[derive(Debug)]
pub struct TqdmAuto<I: Iterator> {
iter: I,
current: usize,
total: usize,
}
impl<I: Iterator> Iterator for TqdmAuto<I> {
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
let next = self.iter.next();
#[allow(clippy::branches_sharing_code)]
if next.is_some() {
self.display();
self.current += 1;
next
} else {
self.display();
None
}
}
}
impl<I: Iterator> WriteCon for TqdmAuto<I> {
fn get_current_amount(&self) -> usize {
self.current
}
fn get_total_amount(&self) -> usize {
self.total
}
}
#[derive(Debug, Copy, Clone)]
pub struct TqdmManual {
current: usize,
total: usize,
}
impl TqdmManual {
pub fn update(mut self, num: usize) {
self.current = std::cmp::min(self.total, self.current + num);
self.display();
}
}
impl WriteCon for TqdmManual {
fn get_current_amount(&self) -> usize {
self.current
}
fn get_total_amount(&self) -> usize {
self.total
}
}