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,
}
impl Bar {
fn copy(self) -> Bar {
Bar {
..self
}
}
}
pub struct BarBuilder {
bar: Bar,
}
impl BarBuilder {
pub fn new() -> BarBuilder {
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.copy()
}
}
impl Bar {
pub fn default() -> Bar {
Bar {
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;
}
}
impl Bar {
pub fn to_string(&self) -> String {
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.clone());
} else {
progress_bar.push(self.empty_char.clone());
}
}
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());
}
progress_bar
}
}
impl Bar {
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
}
}
impl Bar {
fn calculate_percent(&self) -> f32 {
(self.current_partial as f32 / self.total as f32)
}
}
#[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(), "[█████████████████████████ ]")
}
}