pub struct Bar {
pub current_partial: usize,
pub total: usize,
width: usize,
empty_char: char,
full_char: char,
include_percent: bool,
include_numbers: bool,
previous_text_width: usize,
}
pub struct BarBuilder {
bar: Bar,
}
impl Default for BarBuilder {
fn default() -> Self {
BarBuilder::new()
}
}
impl BarBuilder {
pub fn new() -> Self {
BarBuilder {
bar: Bar::default(),
}
}
pub fn total(mut self, total: usize) -> BarBuilder {
self.bar.total = total;
self
}
pub fn width(mut self, width: usize) -> BarBuilder {
self.bar.width = width;
self
}
pub fn empty_char(mut self, character: char) -> BarBuilder {
self.bar.empty_char = character;
self
}
pub fn full_char(mut self, character: char) -> BarBuilder {
self.bar.full_char = character;
self
}
pub fn include_percent(mut self) -> BarBuilder {
self.bar.include_percent = true;
self
}
pub fn include_numbers(mut self) -> BarBuilder {
self.bar.include_numbers = true;
self
}
pub fn get_bar(self) -> Bar {
self.bar
}
}
impl Default for Bar {
fn default() -> Self {
Self {
current_partial: 0,
total: 100,
width: 50,
full_char: '█',
empty_char: ' ',
include_percent: false,
include_numbers: false,
previous_text_width: 0,
}
}
}
impl Bar {
pub fn update(&mut self, to_add: usize) {
self.previous_text_width = self.get_width();
self.current_partial += to_add;
}
pub fn replace(&mut self, new_progress: usize) {
self.previous_text_width = self.get_width();
self.current_partial = new_progress;
}
pub fn get_width(&self) -> usize {
let mut width: usize = 52;
if self.include_numbers {
let total_string = format!("{}", self.total);
let partial_string = format!("{}", self.current_partial);
width += total_string.len() + partial_string.len() + 2;
}
if self.include_percent {
let current_percent = self.calculate_percent();
if current_percent >= 0.95 {
width += 8;
} else if current_percent > 0.095 {
width += 7;
} else {
width += 6;
}
}
width
}
pub fn get_last_width(&self) -> usize {
self.previous_text_width
}
fn calculate_percent(&self) -> f32 {
self.current_partial as f32 / self.total as f32
}
}
impl std::fmt::Display for Bar {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let percent = self.calculate_percent();
let mut progress_bar = String::from("[");
for i in 0..self.width {
if (i as f32) < (self.width as f32 * percent) {
progress_bar.push(self.full_char);
} else {
progress_bar.push(self.empty_char);
}
}
progress_bar.push(']');
if self.include_percent {
progress_bar.push_str(format!(" {:.2}%", percent * 100.0).as_str());
}
if self.include_numbers {
progress_bar.push_str(format!(" {:?}/{:?}", self.current_partial, self.total).as_str());
}
write!(f, "{}", progress_bar)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn include_percent_test() {
let mut bar = BarBuilder::new().include_percent().get_bar();
assert_eq!(bar.get_width(), 58);
bar.update(50);
assert_eq!(bar.get_width(), 59);
bar.update(50);
assert_eq!(bar.get_width(), 60);
}
#[test]
fn include_numbers_test() {
let mut bar = BarBuilder::new().include_numbers().get_bar();
assert_eq!(bar.get_width(), 58);
bar.update(50);
assert_eq!(bar.get_width(), 59);
bar.update(50);
assert_eq!(bar.get_width(), 60);
}
#[test]
fn update_test() {
let mut bar = Bar::default();
bar.update(50);
}
#[test]
fn replace_test() {
let mut bar = Bar::default();
bar.replace(10);
}
#[test]
fn to_string_test() {
let mut bar = Bar::default();
assert_eq!(
bar.to_string(),
"[ ]"
);
bar.update(50);
assert_eq!(
bar.to_string(),
"[█████████████████████████ ]"
)
}
}