diff options
Diffstat (limited to 'vendor/prodash/src/unit/display.rs')
-rw-r--r-- | vendor/prodash/src/unit/display.rs | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/vendor/prodash/src/unit/display.rs b/vendor/prodash/src/unit/display.rs new file mode 100644 index 000000000..592692ff5 --- /dev/null +++ b/vendor/prodash/src/unit/display.rs @@ -0,0 +1,188 @@ +use std::fmt::{self, Write}; + +use crate::{ + progress::Step, + unit::{DisplayValue, Unit}, +}; + +/// The location at which [`Throughput`] or [`UnitDisplays`][UnitDisplay] should be placed. +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)] +#[allow(missing_docs)] +pub enum Location { + BeforeValue, + AfterUnit, +} + +/// A structure able to display throughput, a value change within a given duration. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +pub struct Throughput { + /// The change of value between the current value and the previous one. + pub value_change_in_timespan: Step, + /// The amount of time passed between the previous and the current value. + pub timespan: std::time::Duration, +} + +impl Throughput { + /// A convenience method to create a new ThroughPut from `value_change_in_timespan` and `timespan`. + pub fn new(value_change_in_timespan: Step, timespan: std::time::Duration) -> Self { + Throughput { + value_change_in_timespan, + timespan, + } + } +} + +/// A way to display a [Unit]. +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)] +pub struct Mode { + location: Location, + percent: bool, + throughput: bool, +} + +impl Mode { + fn percent_location(&self) -> Option<Location> { + if self.percent { + Some(self.location) + } else { + None + } + } + + fn throughput_location(&self) -> Option<Location> { + if self.throughput { + Some(self.location) + } else { + None + } + } +} + +/// initialization and modification +impl Mode { + /// Create a mode instance with percentage only. + pub fn with_percentage() -> Self { + Mode { + percent: true, + throughput: false, + location: Location::AfterUnit, + } + } + /// Create a mode instance with throughput only. + pub fn with_throughput() -> Self { + Mode { + percent: false, + throughput: true, + location: Location::AfterUnit, + } + } + /// Turn on percentage display on the current instance. + pub fn and_percentage(mut self) -> Self { + self.percent = true; + self + } + /// Turn on throughput display on the current instance. + pub fn and_throughput(mut self) -> Self { + self.throughput = true; + self + } + /// Change the display location to show up in front of the value. + pub fn show_before_value(mut self) -> Self { + self.location = Location::BeforeValue; + self + } +} + +/// A utility to implement [Display][std::fmt::Display]. +pub struct UnitDisplay<'a> { + pub(crate) current_value: Step, + pub(crate) upper_bound: Option<Step>, + pub(crate) throughput: Option<Throughput>, + pub(crate) parent: &'a Unit, + pub(crate) display: What, +} + +pub(crate) enum What { + ValuesAndUnit, + Unit, + Values, +} + +impl What { + fn values(&self) -> bool { + matches!(self, What::Values | What::ValuesAndUnit) + } + fn unit(&self) -> bool { + matches!(self, What::Unit | What::ValuesAndUnit) + } +} + +impl<'a> UnitDisplay<'a> { + /// Display everything, values and the unit. + pub fn all(&mut self) -> &Self { + self.display = What::ValuesAndUnit; + self + } + /// Display only values. + pub fn values(&mut self) -> &Self { + self.display = What::Values; + self + } + /// Display only units. + pub fn unit(&mut self) -> &Self { + self.display = What::Unit; + self + } +} + +impl<'a> fmt::Display for UnitDisplay<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let unit: &dyn DisplayValue = self.parent.as_display_value(); + let mode = self.parent.mode; + + let percent_location_and_fraction = self.upper_bound.and_then(|upper| { + mode.and_then(|m| m.percent_location()) + .map(|location| (location, ((self.current_value as f64 / upper as f64) * 100.0).floor())) + }); + let throughput_and_location = self.throughput.as_ref().and_then(|throughput| { + mode.and_then(|m| m.throughput_location()) + .map(|location| (location, throughput)) + }); + if self.display.values() { + if let Some((Location::BeforeValue, fraction)) = percent_location_and_fraction { + unit.display_percentage(f, fraction)?; + f.write_char(' ')?; + } + if let Some((Location::BeforeValue, throughput)) = throughput_and_location { + unit.display_throughput(f, throughput)?; + f.write_char(' ')?; + } + unit.display_current_value(f, self.current_value, self.upper_bound)?; + if let Some(upper) = self.upper_bound { + unit.separator(f, self.current_value, self.upper_bound)?; + unit.display_upper_bound(f, upper, self.current_value)?; + } + } + if self.display.unit() { + let mut buf = String::with_capacity(10); + if self.display.values() { + buf.write_char(' ')?; + } + unit.display_unit(&mut buf, self.current_value)?; + if buf.len() > 1 { + // did they actually write a unit? + f.write_str(&buf)?; + } + + if let Some((Location::AfterUnit, fraction)) = percent_location_and_fraction { + f.write_char(' ')?; + unit.display_percentage(f, fraction)?; + } + if let Some((Location::AfterUnit, throughput)) = throughput_and_location { + f.write_char(' ')?; + unit.display_throughput(f, throughput)?; + } + } + Ok(()) + } +} |