From 8d826ac3adcb77a50471459e83fa984cc66065ec Mon Sep 17 00:00:00 2001 From: Avril Date: Mon, 10 Aug 2020 22:03:33 +0100 Subject: [PATCH] added MaybeSilent, improved trait impls --- Cargo.toml | 7 +- build.rs | 24 +++++ src/inter.rs | 144 ++++++++++++++++++++++++++ src/lib.rs | 2 + src/silent.rs | 277 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 452 insertions(+), 2 deletions(-) create mode 100644 build.rs diff --git a/Cargo.toml b/Cargo.toml index 2000153..24cba95 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "termprogress" description = "A terminal progress bar renderer with status and spinners" license = "GPL-3.0-or-later" -version = "0.2.4" +version = "0.3.4" authors = ["Avril "] edition = "2018" @@ -14,4 +14,7 @@ default = ["size"] size = ["terminal_size"] [dependencies] -terminal_size = {version = "0.1", optional = true} \ No newline at end of file +terminal_size = {version = "0.1", optional = true} +[build-dependencies] +rustc_version = "0.2" + diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..6399463 --- /dev/null +++ b/build.rs @@ -0,0 +1,24 @@ + +extern crate rustc_version; +use rustc_version::{version, version_meta, Channel}; + +fn main() { + // Assert we haven't travelled back in time + assert!(version().unwrap().major >= 1); + + // Set cfg flags depending on release channel + match version_meta().unwrap().channel { + Channel::Stable => { + println!("cargo:rustc-cfg=stable"); + } + Channel::Beta => { + println!("cargo:rustc-cfg=beta"); + } + Channel::Nightly => { + println!("cargo:rustc-cfg=nightly"); + } + Channel::Dev => { + println!("cargo:rustc-cfg=dev"); + } + } +} diff --git a/src/inter.rs b/src/inter.rs index 895df7b..1498e52 100644 --- a/src/inter.rs +++ b/src/inter.rs @@ -51,3 +51,147 @@ pub trait WithTitle: Sized + Display fn complete(self); } +impl WithTitle for Box +where T: WithTitle + ?Sized +{ + fn with_title(len: usize, string: impl AsRef) -> Self + { + Box::new(T::with_title(len, string)) + } + fn update(&mut self) + { + self.as_mut().update() + } + fn complete(self) + { + (*self).complete() + } +} + +impl Display for Box +where T: Display + ?Sized +{ + #[inline] fn refresh(&self) + { + self.as_ref().refresh(); + } + #[inline] fn blank(&self) + { + self.as_ref().blank(); + } + #[inline] fn println(&self, string: &str) + { + self.as_ref().println(string); + } + #[inline] fn eprintln(&self, string: &str) + { + self.as_ref().eprintln(string); + } + #[inline] fn get_title(&self) -> &str + { + self.as_ref().get_title() + } + #[inline] fn set_title(&mut self, from: &str) + { + self.as_mut().set_title(from); + } + #[inline] fn update_dimensions(&mut self, to: usize) + { + self.as_mut().update_dimensions(to); + } +} + + +impl ProgressBar for Box +where T: ProgressBar + ?Sized +{ + #[inline] fn set_progress(&mut self, value: f64) + { + self.as_mut().set_progress(value) + } + #[inline] fn get_progress(&self) -> f64 + { + self.as_ref().get_progress() + } +} + +impl Spinner for Box +where T: Spinner + ?Sized +{ + #[inline] fn bump(&mut self) + { + self.as_mut().bump() + } +} + +#[cfg(nightly)] mod never +{ + use super::*; + + impl Display for ! + { + #[inline] fn refresh(&self) + { + + } + #[inline] fn blank(&self) + { + + } + #[inline] fn println(&self, _: &str) + { + + } + #[inline] fn eprintln(&self, _: &str) + { + + } + #[inline] fn get_title(&self) -> &str + { + *self + } + #[inline] fn set_title(&mut self, _: &str) + { + } + + #[inline] fn update_dimensions(&mut self, _: usize) + { + + } + } + + impl ProgressBar for ! + { + + #[inline] fn set_progress(&mut self, _: f64) + { + + } + #[inline] fn get_progress(&self) -> f64 + { + *self + } + } + + impl Spinner for ! + { + #[inline] fn bump(&mut self){} + } + + impl WithTitle for ! + { + #[inline] fn with_title(_: usize, _: impl AsRef) -> Self + { + unreachable!() + } + #[inline] fn update(&mut self) + { + + } + #[inline] fn complete(self) + { + + } + } +} +#[cfg(nightly)] pub use never::*; diff --git a/src/lib.rs b/src/lib.rs index 362b79f..b712bb5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![cfg_attr(nightly, feature(never_type))] + #![allow(dead_code)] macro_rules! flush { diff --git a/src/silent.rs b/src/silent.rs index 41092fc..9c4cace 100644 --- a/src/silent.rs +++ b/src/silent.rs @@ -40,3 +40,280 @@ impl WithTitle for Silent #[inline] fn complete(self) {} } +/// An enum wrapper for a progress bar or spinner that might be silent. +#[derive(Debug)] +pub enum MaybeSilent +{ + /// There is no progress + Silent, + /// There is progress + Loud(T), +} + +impl Display for MaybeSilent +where T: Display +{ + + fn refresh(&self) + { + if let Self::Loud(this) = self { + this.refresh(); + } + } + fn blank(&self) + { + + if let Self::Loud(this) = self { + this.blank(); + } + } + fn println(&self, string: &str) + { + if let Self::Loud(this) = self { + this.println(string); + } + } + fn eprintln(&self, string: &str) + { + if let Self::Loud(this) = self { + this.eprintln(string) + } + } + + fn get_title(&self) -> &str + { + if let Self::Loud(this) = self { + this.get_title() + } else { + "" + } + } + fn set_title(&mut self, from: &str) + { + if let Self::Loud(this) = self { + this.set_title(from); + } + } + + fn update_dimensions(&mut self, to: usize) + { + if let Self::Loud(this) = self { + this.update_dimensions(to) + } + } +} + + +impl ProgressBar for MaybeSilent + where T: ProgressBar +{ + fn set_progress(&mut self, value: f64) + { + if let Self::Loud(this) = self { + this.set_progress(value) + } + } + fn get_progress(&self) -> f64 + { + if let Self::Loud(this) = self { + this.get_progress() + } else { + 0.0 + } + } +} + +impl Spinner for MaybeSilent + where T: Spinner +{ + fn bump(&mut self) + { + if let Self::Loud(this) = self { + this.bump() + } + } +} + +/// A trait for creating a progress bar or spinner with a title. +impl WithTitle for MaybeSilent + where T: WithTitle +{ + fn with_title(len: usize, string: impl AsRef) -> Self + { + Self::Loud(T::with_title(len, string)) + } + fn update(&mut self) + { + if let Self::Loud(this) = self { + this.update() + } + } + fn complete(self) + { + if let Self::Loud(this) = self { + this.complete() + } + } +} + +impl From> for MaybeSilent +{ + #[inline] fn from(from: Option) -> Self + { + match from { + Some(from) => Self::Loud(from), + None => Self::Silent, + } + } +} + +impl From> for Option +{ + fn from(from: MaybeSilent) -> Self + { + match from { + MaybeSilent::Loud(loud) => Some(loud), + _ => None, + } + } +} + +/// Return a `MaybeSilent` that is always silent +#[cfg(nightly)] +pub const fn always() -> MaybeSilent +{ + MaybeSilent::Silent +} + +/// Return a `MaybeSilent` that is always silent +#[cfg(not(nightly))] +pub const fn always() -> MaybeSilent +{ + MaybeSilent::Silent +} + +impl MaybeSilent +{ + /// Is this the not silent variant? + #[inline] pub fn is_loud(&self) -> bool + { + !self.is_silent() + } + /// Is this the silent variant? + #[inline] pub fn is_silent(&self) -> bool + { + if let Self::Silent = self { + true + } else { + false + } + } + /// Create a new `MaybeSilent` with a value. + pub const fn new_some(value: T) -> Self + { + Self::Loud(value) + } + + /// Create a new `MaybeSilent` with a potential value + #[inline] pub fn new(from: U) -> Self + where U: Into> + { + match from.into() { + Some(x) => Self::Loud(x), + _ => Self::Silent, + } + } + + /// Get a reference to the inner type if possible + pub fn as_ref(&self) -> Option<&T> + { + match self { + Self::Loud(loud) => Some(loud), + _ => None + } + } + /// Get a mutable reference to the inner type if possible + pub fn as_mut(&mut self) -> Option<&mut T> + { + match self { + Self::Loud(loud) => Some(loud), + _ => None + } + } + + + /// Get a dynamic mutable reference to the internal value if it is `Display`. + pub fn as_display_mut(&mut self) -> Option<&mut (dyn Display + 'static)> + where T: Display + 'static + { + match self { + Self::Loud(loud) => Some(loud), + _ => None + } + } + + /// Consume this instance and return the inner value if possible + #[inline] pub fn into_inner(self) -> Option + { + self.into() + } + + /// Consume this instance and return silent if it had no value + #[inline] pub fn into_silent(self) -> Option + { + match self { + Self::Silent => Some(Silent), + _ => None + } + } + + /// Get a dynamic mutable reference to the internal value if it is `ProgressBar` + pub fn as_bar_mut(&mut self) -> Option<&mut (dyn ProgressBar + 'static)> + where T: ProgressBar + 'static + { + match self { + Self::Loud(loud) => Some(loud), + _ => None + } + } + + /// Get a dynamic mutable reference to the internal value if it is `Spinner`. + pub fn as_spinner_mut(&mut self) -> Option<&mut (dyn Spinner + 'static)> + where T: Spinner + 'static + { + match self { + Self::Loud(loud) => Some(loud), + _ => None + } + } + + /// Get a dynamic reference to the internal value if it is `Display`. + pub fn as_display(&self) -> Option<&(dyn Display + 'static)> + where T: Display + 'static + { + match self { + Self::Loud(loud) => Some(loud), + _ => None + } + } + + /// Get a dynamic reference to the internal value if it is `ProgressBar` + pub fn as_bar(&self) -> Option<&(dyn ProgressBar + 'static)> + where T: ProgressBar + 'static + { + match self { + Self::Loud(loud) => Some(loud), + _ => None + } + } + + /// Get a dynamic reference to the internal value if it is `Spinner`. + pub fn as_spinner(&self) -> Option<&(dyn Spinner + 'static)> + where T: Spinner + 'static + { + match self { + Self::Loud(loud) => Some(loud), + _ => None + } + } +}