diff options
Diffstat (limited to 'vendor/env_logger/src/fmt/writer/mod.rs')
-rw-r--r-- | vendor/env_logger/src/fmt/writer/mod.rs | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/vendor/env_logger/src/fmt/writer/mod.rs b/vendor/env_logger/src/fmt/writer/mod.rs new file mode 100644 index 000000000..7f4b6f949 --- /dev/null +++ b/vendor/env_logger/src/fmt/writer/mod.rs @@ -0,0 +1,253 @@ +mod atty; +mod termcolor; + +use self::atty::{is_stderr, is_stdout}; +use self::termcolor::BufferWriter; +use std::{fmt, io, mem, sync::Mutex}; + +pub(super) mod glob { + pub use super::termcolor::glob::*; + pub use super::*; +} + +pub(super) use self::termcolor::Buffer; + +/// Log target, either `stdout`, `stderr` or a custom pipe. +#[non_exhaustive] +pub enum Target { + /// Logs will be sent to standard output. + Stdout, + /// Logs will be sent to standard error. + Stderr, + /// Logs will be sent to a custom pipe. + Pipe(Box<dyn io::Write + Send + 'static>), +} + +impl Default for Target { + fn default() -> Self { + Target::Stderr + } +} + +impl fmt::Debug for Target { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match self { + Self::Stdout => "stdout", + Self::Stderr => "stderr", + Self::Pipe(_) => "pipe", + } + ) + } +} + +/// Log target, either `stdout`, `stderr` or a custom pipe. +/// +/// Same as `Target`, except the pipe is wrapped in a mutex for interior mutability. +pub(super) enum WritableTarget { + /// Logs will be sent to standard output. + Stdout, + /// Logs will be sent to standard error. + Stderr, + /// Logs will be sent to a custom pipe. + Pipe(Box<Mutex<dyn io::Write + Send + 'static>>), +} + +impl From<Target> for WritableTarget { + fn from(target: Target) -> Self { + match target { + Target::Stdout => Self::Stdout, + Target::Stderr => Self::Stderr, + Target::Pipe(pipe) => Self::Pipe(Box::new(Mutex::new(pipe))), + } + } +} + +impl Default for WritableTarget { + fn default() -> Self { + Self::from(Target::default()) + } +} + +impl fmt::Debug for WritableTarget { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match self { + Self::Stdout => "stdout", + Self::Stderr => "stderr", + Self::Pipe(_) => "pipe", + } + ) + } +} +/// Whether or not to print styles to the target. +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum WriteStyle { + /// Try to print styles, but don't force the issue. + Auto, + /// Try very hard to print styles. + Always, + /// Never print styles. + Never, +} + +impl Default for WriteStyle { + fn default() -> Self { + WriteStyle::Auto + } +} + +/// A terminal target with color awareness. +pub(crate) struct Writer { + inner: BufferWriter, + write_style: WriteStyle, +} + +impl Writer { + pub fn write_style(&self) -> WriteStyle { + self.write_style + } + + pub(super) fn buffer(&self) -> Buffer { + self.inner.buffer() + } + + pub(super) fn print(&self, buf: &Buffer) -> io::Result<()> { + self.inner.print(buf) + } +} + +/// A builder for a terminal writer. +/// +/// The target and style choice can be configured before building. +#[derive(Debug)] +pub(crate) struct Builder { + target: WritableTarget, + write_style: WriteStyle, + is_test: bool, + built: bool, +} + +impl Builder { + /// Initialize the writer builder with defaults. + pub(crate) fn new() -> Self { + Builder { + target: Default::default(), + write_style: Default::default(), + is_test: false, + built: false, + } + } + + /// Set the target to write to. + pub(crate) fn target(&mut self, target: Target) -> &mut Self { + self.target = target.into(); + self + } + + /// Parses a style choice string. + /// + /// See the [Disabling colors] section for more details. + /// + /// [Disabling colors]: ../index.html#disabling-colors + pub(crate) fn parse_write_style(&mut self, write_style: &str) -> &mut Self { + self.write_style(parse_write_style(write_style)) + } + + /// Whether or not to print style characters when writing. + pub(crate) fn write_style(&mut self, write_style: WriteStyle) -> &mut Self { + self.write_style = write_style; + self + } + + /// Whether or not to capture logs for `cargo test`. + #[allow(clippy::wrong_self_convention)] + pub(crate) fn is_test(&mut self, is_test: bool) -> &mut Self { + self.is_test = is_test; + self + } + + /// Build a terminal writer. + pub(crate) fn build(&mut self) -> Writer { + assert!(!self.built, "attempt to re-use consumed builder"); + self.built = true; + + let color_choice = match self.write_style { + WriteStyle::Auto => { + if match &self.target { + WritableTarget::Stderr => is_stderr(), + WritableTarget::Stdout => is_stdout(), + WritableTarget::Pipe(_) => false, + } { + WriteStyle::Auto + } else { + WriteStyle::Never + } + } + color_choice => color_choice, + }; + + let writer = match mem::take(&mut self.target) { + WritableTarget::Stderr => BufferWriter::stderr(self.is_test, color_choice), + WritableTarget::Stdout => BufferWriter::stdout(self.is_test, color_choice), + WritableTarget::Pipe(pipe) => BufferWriter::pipe(color_choice, pipe), + }; + + Writer { + inner: writer, + write_style: self.write_style, + } + } +} + +impl Default for Builder { + fn default() -> Self { + Builder::new() + } +} + +impl fmt::Debug for Writer { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Writer").finish() + } +} + +fn parse_write_style(spec: &str) -> WriteStyle { + match spec { + "auto" => WriteStyle::Auto, + "always" => WriteStyle::Always, + "never" => WriteStyle::Never, + _ => Default::default(), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_write_style_valid() { + let inputs = vec![ + ("auto", WriteStyle::Auto), + ("always", WriteStyle::Always), + ("never", WriteStyle::Never), + ]; + + for (input, expected) in inputs { + assert_eq!(expected, parse_write_style(input)); + } + } + + #[test] + fn parse_write_style_invalid() { + let inputs = vec!["", "true", "false", "NEVER!!"]; + + for input in inputs { + assert_eq!(WriteStyle::Auto, parse_write_style(input)); + } + } +} |