summaryrefslogtreecommitdiffstats
path: root/vendor/env_logger/src/fmt
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/env_logger/src/fmt')
-rw-r--r--vendor/env_logger/src/fmt/humantime/extern_impl.rs118
-rw-r--r--vendor/env_logger/src/fmt/humantime/mod.rs11
-rw-r--r--vendor/env_logger/src/fmt/humantime/shim_impl.rs5
-rw-r--r--vendor/env_logger/src/fmt/mod.rs652
-rw-r--r--vendor/env_logger/src/fmt/writer/atty.rs33
-rw-r--r--vendor/env_logger/src/fmt/writer/mod.rs253
-rw-r--r--vendor/env_logger/src/fmt/writer/termcolor/extern_impl.rs532
-rw-r--r--vendor/env_logger/src/fmt/writer/termcolor/mod.rs12
-rw-r--r--vendor/env_logger/src/fmt/writer/termcolor/shim_impl.rs72
9 files changed, 1688 insertions, 0 deletions
diff --git a/vendor/env_logger/src/fmt/humantime/extern_impl.rs b/vendor/env_logger/src/fmt/humantime/extern_impl.rs
new file mode 100644
index 000000000..bdf165c4e
--- /dev/null
+++ b/vendor/env_logger/src/fmt/humantime/extern_impl.rs
@@ -0,0 +1,118 @@
+use std::fmt;
+use std::time::SystemTime;
+
+use humantime::{
+ format_rfc3339_micros, format_rfc3339_millis, format_rfc3339_nanos, format_rfc3339_seconds,
+};
+
+use crate::fmt::{Formatter, TimestampPrecision};
+
+pub(in crate::fmt) mod glob {
+ pub use super::*;
+}
+
+impl Formatter {
+ /// Get a [`Timestamp`] for the current date and time in UTC.
+ ///
+ /// # Examples
+ ///
+ /// Include the current timestamp with the log record:
+ ///
+ /// ```
+ /// use std::io::Write;
+ ///
+ /// let mut builder = env_logger::Builder::new();
+ ///
+ /// builder.format(|buf, record| {
+ /// let ts = buf.timestamp();
+ ///
+ /// writeln!(buf, "{}: {}: {}", ts, record.level(), record.args())
+ /// });
+ /// ```
+ ///
+ /// [`Timestamp`]: struct.Timestamp.html
+ pub fn timestamp(&self) -> Timestamp {
+ Timestamp {
+ time: SystemTime::now(),
+ precision: TimestampPrecision::Seconds,
+ }
+ }
+
+ /// Get a [`Timestamp`] for the current date and time in UTC with full
+ /// second precision.
+ pub fn timestamp_seconds(&self) -> Timestamp {
+ Timestamp {
+ time: SystemTime::now(),
+ precision: TimestampPrecision::Seconds,
+ }
+ }
+
+ /// Get a [`Timestamp`] for the current date and time in UTC with
+ /// millisecond precision.
+ pub fn timestamp_millis(&self) -> Timestamp {
+ Timestamp {
+ time: SystemTime::now(),
+ precision: TimestampPrecision::Millis,
+ }
+ }
+
+ /// Get a [`Timestamp`] for the current date and time in UTC with
+ /// microsecond precision.
+ pub fn timestamp_micros(&self) -> Timestamp {
+ Timestamp {
+ time: SystemTime::now(),
+ precision: TimestampPrecision::Micros,
+ }
+ }
+
+ /// Get a [`Timestamp`] for the current date and time in UTC with
+ /// nanosecond precision.
+ pub fn timestamp_nanos(&self) -> Timestamp {
+ Timestamp {
+ time: SystemTime::now(),
+ precision: TimestampPrecision::Nanos,
+ }
+ }
+}
+
+/// An [RFC3339] formatted timestamp.
+///
+/// The timestamp implements [`Display`] and can be written to a [`Formatter`].
+///
+/// [RFC3339]: https://www.ietf.org/rfc/rfc3339.txt
+/// [`Display`]: https://doc.rust-lang.org/stable/std/fmt/trait.Display.html
+/// [`Formatter`]: struct.Formatter.html
+pub struct Timestamp {
+ time: SystemTime,
+ precision: TimestampPrecision,
+}
+
+impl fmt::Debug for Timestamp {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ /// A `Debug` wrapper for `Timestamp` that uses the `Display` implementation.
+ struct TimestampValue<'a>(&'a Timestamp);
+
+ impl<'a> fmt::Debug for TimestampValue<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.0, f)
+ }
+ }
+
+ f.debug_tuple("Timestamp")
+ .field(&TimestampValue(self))
+ .finish()
+ }
+}
+
+impl fmt::Display for Timestamp {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let formatter = match self.precision {
+ TimestampPrecision::Seconds => format_rfc3339_seconds,
+ TimestampPrecision::Millis => format_rfc3339_millis,
+ TimestampPrecision::Micros => format_rfc3339_micros,
+ TimestampPrecision::Nanos => format_rfc3339_nanos,
+ };
+
+ formatter(self.time).fmt(f)
+ }
+}
diff --git a/vendor/env_logger/src/fmt/humantime/mod.rs b/vendor/env_logger/src/fmt/humantime/mod.rs
new file mode 100644
index 000000000..ac23ae249
--- /dev/null
+++ b/vendor/env_logger/src/fmt/humantime/mod.rs
@@ -0,0 +1,11 @@
+/*
+This internal module contains the timestamp implementation.
+
+Its public API is available when the `humantime` crate is available.
+*/
+
+#[cfg_attr(feature = "humantime", path = "extern_impl.rs")]
+#[cfg_attr(not(feature = "humantime"), path = "shim_impl.rs")]
+mod imp;
+
+pub(in crate::fmt) use self::imp::*;
diff --git a/vendor/env_logger/src/fmt/humantime/shim_impl.rs b/vendor/env_logger/src/fmt/humantime/shim_impl.rs
new file mode 100644
index 000000000..906bf9e4c
--- /dev/null
+++ b/vendor/env_logger/src/fmt/humantime/shim_impl.rs
@@ -0,0 +1,5 @@
+/*
+Timestamps aren't available when we don't have a `humantime` dependency.
+*/
+
+pub(in crate::fmt) mod glob {}
diff --git a/vendor/env_logger/src/fmt/mod.rs b/vendor/env_logger/src/fmt/mod.rs
new file mode 100644
index 000000000..86c093f0e
--- /dev/null
+++ b/vendor/env_logger/src/fmt/mod.rs
@@ -0,0 +1,652 @@
+//! Formatting for log records.
+//!
+//! This module contains a [`Formatter`] that can be used to format log records
+//! into without needing temporary allocations. Usually you won't need to worry
+//! about the contents of this module and can use the `Formatter` like an ordinary
+//! [`Write`].
+//!
+//! # Formatting log records
+//!
+//! The format used to print log records can be customised using the [`Builder::format`]
+//! method.
+//! Custom formats can apply different color and weight to printed values using
+//! [`Style`] builders.
+//!
+//! ```
+//! use std::io::Write;
+//!
+//! let mut builder = env_logger::Builder::new();
+//!
+//! builder.format(|buf, record| {
+//! writeln!(buf, "{}: {}",
+//! record.level(),
+//! record.args())
+//! });
+//! ```
+//!
+//! [`Formatter`]: struct.Formatter.html
+//! [`Style`]: struct.Style.html
+//! [`Builder::format`]: ../struct.Builder.html#method.format
+//! [`Write`]: https://doc.rust-lang.org/stable/std/io/trait.Write.html
+
+use std::cell::RefCell;
+use std::fmt::Display;
+use std::io::prelude::*;
+use std::rc::Rc;
+use std::{fmt, io, mem};
+
+use log::Record;
+
+mod humantime;
+pub(crate) mod writer;
+
+pub use self::humantime::glob::*;
+pub use self::writer::glob::*;
+
+use self::writer::{Buffer, Writer};
+
+pub(crate) mod glob {
+ pub use super::{Target, TimestampPrecision, WriteStyle};
+}
+
+/// Formatting precision of timestamps.
+///
+/// Seconds give precision of full seconds, milliseconds give thousands of a
+/// second (3 decimal digits), microseconds are millionth of a second (6 decimal
+/// digits) and nanoseconds are billionth of a second (9 decimal digits).
+#[derive(Copy, Clone, Debug)]
+pub enum TimestampPrecision {
+ /// Full second precision (0 decimal digits)
+ Seconds,
+ /// Millisecond precision (3 decimal digits)
+ Millis,
+ /// Microsecond precision (6 decimal digits)
+ Micros,
+ /// Nanosecond precision (9 decimal digits)
+ Nanos,
+}
+
+/// The default timestamp precision is seconds.
+impl Default for TimestampPrecision {
+ fn default() -> Self {
+ TimestampPrecision::Seconds
+ }
+}
+
+/// A formatter to write logs into.
+///
+/// `Formatter` implements the standard [`Write`] trait for writing log records.
+/// It also supports terminal colors, through the [`style`] method.
+///
+/// # Examples
+///
+/// Use the [`writeln`] macro to format a log record.
+/// An instance of a `Formatter` is passed to an `env_logger` format as `buf`:
+///
+/// ```
+/// use std::io::Write;
+///
+/// let mut builder = env_logger::Builder::new();
+///
+/// builder.format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args()));
+/// ```
+///
+/// [`Write`]: https://doc.rust-lang.org/stable/std/io/trait.Write.html
+/// [`writeln`]: https://doc.rust-lang.org/stable/std/macro.writeln.html
+/// [`style`]: #method.style
+pub struct Formatter {
+ buf: Rc<RefCell<Buffer>>,
+ write_style: WriteStyle,
+}
+
+impl Formatter {
+ pub(crate) fn new(writer: &Writer) -> Self {
+ Formatter {
+ buf: Rc::new(RefCell::new(writer.buffer())),
+ write_style: writer.write_style(),
+ }
+ }
+
+ pub(crate) fn write_style(&self) -> WriteStyle {
+ self.write_style
+ }
+
+ pub(crate) fn print(&self, writer: &Writer) -> io::Result<()> {
+ writer.print(&self.buf.borrow())
+ }
+
+ pub(crate) fn clear(&mut self) {
+ self.buf.borrow_mut().clear()
+ }
+}
+
+impl Write for Formatter {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.buf.borrow_mut().write(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ self.buf.borrow_mut().flush()
+ }
+}
+
+impl fmt::Debug for Formatter {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("Formatter").finish()
+ }
+}
+
+pub(crate) type FormatFn = Box<dyn Fn(&mut Formatter, &Record) -> io::Result<()> + Sync + Send>;
+
+pub(crate) struct Builder {
+ pub format_timestamp: Option<TimestampPrecision>,
+ pub format_module_path: bool,
+ pub format_target: bool,
+ pub format_level: bool,
+ pub format_indent: Option<usize>,
+ pub custom_format: Option<FormatFn>,
+ pub format_suffix: &'static str,
+ built: bool,
+}
+
+impl Default for Builder {
+ fn default() -> Self {
+ Builder {
+ format_timestamp: Some(Default::default()),
+ format_module_path: false,
+ format_target: true,
+ format_level: true,
+ format_indent: Some(4),
+ custom_format: None,
+ format_suffix: "\n",
+ built: false,
+ }
+ }
+}
+
+impl Builder {
+ /// Convert the format into a callable function.
+ ///
+ /// If the `custom_format` is `Some`, then any `default_format` switches are ignored.
+ /// If the `custom_format` is `None`, then a default format is returned.
+ /// Any `default_format` switches set to `false` won't be written by the format.
+ pub fn build(&mut self) -> FormatFn {
+ assert!(!self.built, "attempt to re-use consumed builder");
+
+ let built = mem::replace(
+ self,
+ Builder {
+ built: true,
+ ..Default::default()
+ },
+ );
+
+ if let Some(fmt) = built.custom_format {
+ fmt
+ } else {
+ Box::new(move |buf, record| {
+ let fmt = DefaultFormat {
+ timestamp: built.format_timestamp,
+ module_path: built.format_module_path,
+ target: built.format_target,
+ level: built.format_level,
+ written_header_value: false,
+ indent: built.format_indent,
+ suffix: built.format_suffix,
+ buf,
+ };
+
+ fmt.write(record)
+ })
+ }
+ }
+}
+
+#[cfg(feature = "color")]
+type SubtleStyle = StyledValue<'static, &'static str>;
+#[cfg(not(feature = "color"))]
+type SubtleStyle = &'static str;
+
+/// The default format.
+///
+/// This format needs to work with any combination of crate features.
+struct DefaultFormat<'a> {
+ timestamp: Option<TimestampPrecision>,
+ module_path: bool,
+ target: bool,
+ level: bool,
+ written_header_value: bool,
+ indent: Option<usize>,
+ buf: &'a mut Formatter,
+ suffix: &'a str,
+}
+
+impl<'a> DefaultFormat<'a> {
+ fn write(mut self, record: &Record) -> io::Result<()> {
+ self.write_timestamp()?;
+ self.write_level(record)?;
+ self.write_module_path(record)?;
+ self.write_target(record)?;
+ self.finish_header()?;
+
+ self.write_args(record)
+ }
+
+ fn subtle_style(&self, text: &'static str) -> SubtleStyle {
+ #[cfg(feature = "color")]
+ {
+ self.buf
+ .style()
+ .set_color(Color::Black)
+ .set_intense(true)
+ .clone()
+ .into_value(text)
+ }
+ #[cfg(not(feature = "color"))]
+ {
+ text
+ }
+ }
+
+ fn write_header_value<T>(&mut self, value: T) -> io::Result<()>
+ where
+ T: Display,
+ {
+ if !self.written_header_value {
+ self.written_header_value = true;
+
+ let open_brace = self.subtle_style("[");
+ write!(self.buf, "{}{}", open_brace, value)
+ } else {
+ write!(self.buf, " {}", value)
+ }
+ }
+
+ fn write_level(&mut self, record: &Record) -> io::Result<()> {
+ if !self.level {
+ return Ok(());
+ }
+
+ let level = {
+ #[cfg(feature = "color")]
+ {
+ self.buf.default_styled_level(record.level())
+ }
+ #[cfg(not(feature = "color"))]
+ {
+ record.level()
+ }
+ };
+
+ self.write_header_value(format_args!("{:<5}", level))
+ }
+
+ fn write_timestamp(&mut self) -> io::Result<()> {
+ #[cfg(feature = "humantime")]
+ {
+ use self::TimestampPrecision::*;
+ let ts = match self.timestamp {
+ None => return Ok(()),
+ Some(Seconds) => self.buf.timestamp_seconds(),
+ Some(Millis) => self.buf.timestamp_millis(),
+ Some(Micros) => self.buf.timestamp_micros(),
+ Some(Nanos) => self.buf.timestamp_nanos(),
+ };
+
+ self.write_header_value(ts)
+ }
+ #[cfg(not(feature = "humantime"))]
+ {
+ // Trick the compiler to think we have used self.timestamp
+ // Workaround for "field is never used: `timestamp`" compiler nag.
+ let _ = self.timestamp;
+ Ok(())
+ }
+ }
+
+ fn write_module_path(&mut self, record: &Record) -> io::Result<()> {
+ if !self.module_path {
+ return Ok(());
+ }
+
+ if let Some(module_path) = record.module_path() {
+ self.write_header_value(module_path)
+ } else {
+ Ok(())
+ }
+ }
+
+ fn write_target(&mut self, record: &Record) -> io::Result<()> {
+ if !self.target {
+ return Ok(());
+ }
+
+ match record.target() {
+ "" => Ok(()),
+ target => self.write_header_value(target),
+ }
+ }
+
+ fn finish_header(&mut self) -> io::Result<()> {
+ if self.written_header_value {
+ let close_brace = self.subtle_style("]");
+ write!(self.buf, "{} ", close_brace)
+ } else {
+ Ok(())
+ }
+ }
+
+ fn write_args(&mut self, record: &Record) -> io::Result<()> {
+ match self.indent {
+ // Fast path for no indentation
+ None => write!(self.buf, "{}{}", record.args(), self.suffix),
+
+ Some(indent_count) => {
+ // Create a wrapper around the buffer only if we have to actually indent the message
+
+ struct IndentWrapper<'a, 'b: 'a> {
+ fmt: &'a mut DefaultFormat<'b>,
+ indent_count: usize,
+ }
+
+ impl<'a, 'b> Write for IndentWrapper<'a, 'b> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ let mut first = true;
+ for chunk in buf.split(|&x| x == b'\n') {
+ if !first {
+ write!(
+ self.fmt.buf,
+ "{}{:width$}",
+ self.fmt.suffix,
+ "",
+ width = self.indent_count
+ )?;
+ }
+ self.fmt.buf.write_all(chunk)?;
+ first = false;
+ }
+
+ Ok(buf.len())
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ self.fmt.buf.flush()
+ }
+ }
+
+ // The explicit scope here is just to make older versions of Rust happy
+ {
+ let mut wrapper = IndentWrapper {
+ fmt: self,
+ indent_count,
+ };
+ write!(wrapper, "{}", record.args())?;
+ }
+
+ write!(self.buf, "{}", self.suffix)?;
+
+ Ok(())
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use log::{Level, Record};
+
+ fn write_record(record: Record, fmt: DefaultFormat) -> String {
+ let buf = fmt.buf.buf.clone();
+
+ fmt.write(&record).expect("failed to write record");
+
+ let buf = buf.borrow();
+ String::from_utf8(buf.bytes().to_vec()).expect("failed to read record")
+ }
+
+ fn write_target(target: &str, fmt: DefaultFormat) -> String {
+ write_record(
+ Record::builder()
+ .args(format_args!("log\nmessage"))
+ .level(Level::Info)
+ .file(Some("test.rs"))
+ .line(Some(144))
+ .module_path(Some("test::path"))
+ .target(target)
+ .build(),
+ fmt,
+ )
+ }
+
+ fn write(fmt: DefaultFormat) -> String {
+ write_target("", fmt)
+ }
+
+ #[test]
+ fn format_with_header() {
+ let writer = writer::Builder::new()
+ .write_style(WriteStyle::Never)
+ .build();
+
+ let mut f = Formatter::new(&writer);
+
+ let written = write(DefaultFormat {
+ timestamp: None,
+ module_path: true,
+ target: false,
+ level: true,
+ written_header_value: false,
+ indent: None,
+ suffix: "\n",
+ buf: &mut f,
+ });
+
+ assert_eq!("[INFO test::path] log\nmessage\n", written);
+ }
+
+ #[test]
+ fn format_no_header() {
+ let writer = writer::Builder::new()
+ .write_style(WriteStyle::Never)
+ .build();
+
+ let mut f = Formatter::new(&writer);
+
+ let written = write(DefaultFormat {
+ timestamp: None,
+ module_path: false,
+ target: false,
+ level: false,
+ written_header_value: false,
+ indent: None,
+ suffix: "\n",
+ buf: &mut f,
+ });
+
+ assert_eq!("log\nmessage\n", written);
+ }
+
+ #[test]
+ fn format_indent_spaces() {
+ let writer = writer::Builder::new()
+ .write_style(WriteStyle::Never)
+ .build();
+
+ let mut f = Formatter::new(&writer);
+
+ let written = write(DefaultFormat {
+ timestamp: None,
+ module_path: true,
+ target: false,
+ level: true,
+ written_header_value: false,
+ indent: Some(4),
+ suffix: "\n",
+ buf: &mut f,
+ });
+
+ assert_eq!("[INFO test::path] log\n message\n", written);
+ }
+
+ #[test]
+ fn format_indent_zero_spaces() {
+ let writer = writer::Builder::new()
+ .write_style(WriteStyle::Never)
+ .build();
+
+ let mut f = Formatter::new(&writer);
+
+ let written = write(DefaultFormat {
+ timestamp: None,
+ module_path: true,
+ target: false,
+ level: true,
+ written_header_value: false,
+ indent: Some(0),
+ suffix: "\n",
+ buf: &mut f,
+ });
+
+ assert_eq!("[INFO test::path] log\nmessage\n", written);
+ }
+
+ #[test]
+ fn format_indent_spaces_no_header() {
+ let writer = writer::Builder::new()
+ .write_style(WriteStyle::Never)
+ .build();
+
+ let mut f = Formatter::new(&writer);
+
+ let written = write(DefaultFormat {
+ timestamp: None,
+ module_path: false,
+ target: false,
+ level: false,
+ written_header_value: false,
+ indent: Some(4),
+ suffix: "\n",
+ buf: &mut f,
+ });
+
+ assert_eq!("log\n message\n", written);
+ }
+
+ #[test]
+ fn format_suffix() {
+ let writer = writer::Builder::new()
+ .write_style(WriteStyle::Never)
+ .build();
+
+ let mut f = Formatter::new(&writer);
+
+ let written = write(DefaultFormat {
+ timestamp: None,
+ module_path: false,
+ target: false,
+ level: false,
+ written_header_value: false,
+ indent: None,
+ suffix: "\n\n",
+ buf: &mut f,
+ });
+
+ assert_eq!("log\nmessage\n\n", written);
+ }
+
+ #[test]
+ fn format_suffix_with_indent() {
+ let writer = writer::Builder::new()
+ .write_style(WriteStyle::Never)
+ .build();
+
+ let mut f = Formatter::new(&writer);
+
+ let written = write(DefaultFormat {
+ timestamp: None,
+ module_path: false,
+ target: false,
+ level: false,
+ written_header_value: false,
+ indent: Some(4),
+ suffix: "\n\n",
+ buf: &mut f,
+ });
+
+ assert_eq!("log\n\n message\n\n", written);
+ }
+
+ #[test]
+ fn format_target() {
+ let writer = writer::Builder::new()
+ .write_style(WriteStyle::Never)
+ .build();
+
+ let mut f = Formatter::new(&writer);
+
+ let written = write_target(
+ "target",
+ DefaultFormat {
+ timestamp: None,
+ module_path: true,
+ target: true,
+ level: true,
+ written_header_value: false,
+ indent: None,
+ suffix: "\n",
+ buf: &mut f,
+ },
+ );
+
+ assert_eq!("[INFO test::path target] log\nmessage\n", written);
+ }
+
+ #[test]
+ fn format_empty_target() {
+ let writer = writer::Builder::new()
+ .write_style(WriteStyle::Never)
+ .build();
+
+ let mut f = Formatter::new(&writer);
+
+ let written = write(DefaultFormat {
+ timestamp: None,
+ module_path: true,
+ target: true,
+ level: true,
+ written_header_value: false,
+ indent: None,
+ suffix: "\n",
+ buf: &mut f,
+ });
+
+ assert_eq!("[INFO test::path] log\nmessage\n", written);
+ }
+
+ #[test]
+ fn format_no_target() {
+ let writer = writer::Builder::new()
+ .write_style(WriteStyle::Never)
+ .build();
+
+ let mut f = Formatter::new(&writer);
+
+ let written = write_target(
+ "target",
+ DefaultFormat {
+ timestamp: None,
+ module_path: true,
+ target: false,
+ level: true,
+ written_header_value: false,
+ indent: None,
+ suffix: "\n",
+ buf: &mut f,
+ },
+ );
+
+ assert_eq!("[INFO test::path] log\nmessage\n", written);
+ }
+}
diff --git a/vendor/env_logger/src/fmt/writer/atty.rs b/vendor/env_logger/src/fmt/writer/atty.rs
new file mode 100644
index 000000000..1a133eeff
--- /dev/null
+++ b/vendor/env_logger/src/fmt/writer/atty.rs
@@ -0,0 +1,33 @@
+/*
+This internal module contains the terminal detection implementation.
+
+If the `auto-color` feature is enabled then we detect whether we're attached to a particular TTY.
+Otherwise, assume we're not attached to anything. This effectively prevents styles from being
+printed.
+*/
+
+#[cfg(feature = "auto-color")]
+mod imp {
+ use is_terminal::IsTerminal;
+
+ pub(in crate::fmt) fn is_stdout() -> bool {
+ std::io::stdout().is_terminal()
+ }
+
+ pub(in crate::fmt) fn is_stderr() -> bool {
+ std::io::stderr().is_terminal()
+ }
+}
+
+#[cfg(not(feature = "auto-color"))]
+mod imp {
+ pub(in crate::fmt) fn is_stdout() -> bool {
+ false
+ }
+
+ pub(in crate::fmt) fn is_stderr() -> bool {
+ false
+ }
+}
+
+pub(in crate::fmt) use self::imp::*;
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));
+ }
+ }
+}
diff --git a/vendor/env_logger/src/fmt/writer/termcolor/extern_impl.rs b/vendor/env_logger/src/fmt/writer/termcolor/extern_impl.rs
new file mode 100644
index 000000000..89c382239
--- /dev/null
+++ b/vendor/env_logger/src/fmt/writer/termcolor/extern_impl.rs
@@ -0,0 +1,532 @@
+use std::borrow::Cow;
+use std::cell::RefCell;
+use std::fmt;
+use std::io::{self, Write};
+use std::rc::Rc;
+use std::sync::Mutex;
+
+use log::Level;
+use termcolor::{self, ColorChoice, ColorSpec, WriteColor};
+
+use crate::fmt::{Formatter, WritableTarget, WriteStyle};
+
+pub(in crate::fmt::writer) mod glob {
+ pub use super::*;
+}
+
+impl Formatter {
+ /// Begin a new [`Style`].
+ ///
+ /// # Examples
+ ///
+ /// Create a bold, red colored style and use it to print the log level:
+ ///
+ /// ```
+ /// use std::io::Write;
+ /// use env_logger::fmt::Color;
+ ///
+ /// let mut builder = env_logger::Builder::new();
+ ///
+ /// builder.format(|buf, record| {
+ /// let mut level_style = buf.style();
+ ///
+ /// level_style.set_color(Color::Red).set_bold(true);
+ ///
+ /// writeln!(buf, "{}: {}",
+ /// level_style.value(record.level()),
+ /// record.args())
+ /// });
+ /// ```
+ ///
+ /// [`Style`]: struct.Style.html
+ pub fn style(&self) -> Style {
+ Style {
+ buf: self.buf.clone(),
+ spec: ColorSpec::new(),
+ }
+ }
+
+ /// Get the default [`Style`] for the given level.
+ ///
+ /// The style can be used to print other values besides the level.
+ pub fn default_level_style(&self, level: Level) -> Style {
+ let mut level_style = self.style();
+ match level {
+ Level::Trace => level_style.set_color(Color::Cyan),
+ Level::Debug => level_style.set_color(Color::Blue),
+ Level::Info => level_style.set_color(Color::Green),
+ Level::Warn => level_style.set_color(Color::Yellow),
+ Level::Error => level_style.set_color(Color::Red).set_bold(true),
+ };
+ level_style
+ }
+
+ /// Get a printable [`Style`] for the given level.
+ ///
+ /// The style can only be used to print the level.
+ pub fn default_styled_level(&self, level: Level) -> StyledValue<'static, Level> {
+ self.default_level_style(level).into_value(level)
+ }
+}
+
+pub(in crate::fmt::writer) struct BufferWriter {
+ inner: termcolor::BufferWriter,
+ uncolored_target: Option<WritableTarget>,
+}
+
+pub(in crate::fmt) struct Buffer {
+ inner: termcolor::Buffer,
+ has_uncolored_target: bool,
+}
+
+impl BufferWriter {
+ pub(in crate::fmt::writer) fn stderr(is_test: bool, write_style: WriteStyle) -> Self {
+ BufferWriter {
+ inner: termcolor::BufferWriter::stderr(write_style.into_color_choice()),
+ uncolored_target: if is_test {
+ Some(WritableTarget::Stderr)
+ } else {
+ None
+ },
+ }
+ }
+
+ pub(in crate::fmt::writer) fn stdout(is_test: bool, write_style: WriteStyle) -> Self {
+ BufferWriter {
+ inner: termcolor::BufferWriter::stdout(write_style.into_color_choice()),
+ uncolored_target: if is_test {
+ Some(WritableTarget::Stdout)
+ } else {
+ None
+ },
+ }
+ }
+
+ pub(in crate::fmt::writer) fn pipe(
+ write_style: WriteStyle,
+ pipe: Box<Mutex<dyn io::Write + Send + 'static>>,
+ ) -> Self {
+ BufferWriter {
+ // The inner Buffer is never printed from, but it is still needed to handle coloring and other formatting
+ inner: termcolor::BufferWriter::stderr(write_style.into_color_choice()),
+ uncolored_target: Some(WritableTarget::Pipe(pipe)),
+ }
+ }
+
+ pub(in crate::fmt::writer) fn buffer(&self) -> Buffer {
+ Buffer {
+ inner: self.inner.buffer(),
+ has_uncolored_target: self.uncolored_target.is_some(),
+ }
+ }
+
+ pub(in crate::fmt::writer) fn print(&self, buf: &Buffer) -> io::Result<()> {
+ if let Some(target) = &self.uncolored_target {
+ // This impl uses the `eprint` and `print` macros
+ // instead of `termcolor`'s buffer.
+ // This is so their output can be captured by `cargo test`
+ let log = String::from_utf8_lossy(buf.bytes());
+
+ match target {
+ WritableTarget::Stderr => eprint!("{}", log),
+ WritableTarget::Stdout => print!("{}", log),
+ WritableTarget::Pipe(pipe) => write!(pipe.lock().unwrap(), "{}", log)?,
+ }
+
+ Ok(())
+ } else {
+ self.inner.print(&buf.inner)
+ }
+ }
+}
+
+impl Buffer {
+ pub(in crate::fmt) fn clear(&mut self) {
+ self.inner.clear()
+ }
+
+ pub(in crate::fmt) fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.inner.write(buf)
+ }
+
+ pub(in crate::fmt) fn flush(&mut self) -> io::Result<()> {
+ self.inner.flush()
+ }
+
+ pub(in crate::fmt) fn bytes(&self) -> &[u8] {
+ self.inner.as_slice()
+ }
+
+ fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
+ // Ignore styles for test captured logs because they can't be printed
+ if !self.has_uncolored_target {
+ self.inner.set_color(spec)
+ } else {
+ Ok(())
+ }
+ }
+
+ fn reset(&mut self) -> io::Result<()> {
+ // Ignore styles for test captured logs because they can't be printed
+ if !self.has_uncolored_target {
+ self.inner.reset()
+ } else {
+ Ok(())
+ }
+ }
+}
+
+impl WriteStyle {
+ fn into_color_choice(self) -> ColorChoice {
+ match self {
+ WriteStyle::Always => ColorChoice::Always,
+ WriteStyle::Auto => ColorChoice::Auto,
+ WriteStyle::Never => ColorChoice::Never,
+ }
+ }
+}
+
+/// A set of styles to apply to the terminal output.
+///
+/// Call [`Formatter::style`] to get a `Style` and use the builder methods to
+/// set styling properties, like [color] and [weight].
+/// To print a value using the style, wrap it in a call to [`value`] when the log
+/// record is formatted.
+///
+/// # Examples
+///
+/// Create a bold, red colored style and use it to print the log level:
+///
+/// ```
+/// use std::io::Write;
+/// use env_logger::fmt::Color;
+///
+/// let mut builder = env_logger::Builder::new();
+///
+/// builder.format(|buf, record| {
+/// let mut level_style = buf.style();
+///
+/// level_style.set_color(Color::Red).set_bold(true);
+///
+/// writeln!(buf, "{}: {}",
+/// level_style.value(record.level()),
+/// record.args())
+/// });
+/// ```
+///
+/// Styles can be re-used to output multiple values:
+///
+/// ```
+/// use std::io::Write;
+/// use env_logger::fmt::Color;
+///
+/// let mut builder = env_logger::Builder::new();
+///
+/// builder.format(|buf, record| {
+/// let mut bold = buf.style();
+///
+/// bold.set_bold(true);
+///
+/// writeln!(buf, "{}: {} {}",
+/// bold.value(record.level()),
+/// bold.value("some bold text"),
+/// record.args())
+/// });
+/// ```
+///
+/// [`Formatter::style`]: struct.Formatter.html#method.style
+/// [color]: #method.set_color
+/// [weight]: #method.set_bold
+/// [`value`]: #method.value
+#[derive(Clone)]
+pub struct Style {
+ buf: Rc<RefCell<Buffer>>,
+ spec: ColorSpec,
+}
+
+/// A value that can be printed using the given styles.
+///
+/// It is the result of calling [`Style::value`].
+///
+/// [`Style::value`]: struct.Style.html#method.value
+pub struct StyledValue<'a, T> {
+ style: Cow<'a, Style>,
+ value: T,
+}
+
+impl Style {
+ /// Set the text color.
+ ///
+ /// # Examples
+ ///
+ /// Create a style with red text:
+ ///
+ /// ```
+ /// use std::io::Write;
+ /// use env_logger::fmt::Color;
+ ///
+ /// let mut builder = env_logger::Builder::new();
+ ///
+ /// builder.format(|buf, record| {
+ /// let mut style = buf.style();
+ ///
+ /// style.set_color(Color::Red);
+ ///
+ /// writeln!(buf, "{}", style.value(record.args()))
+ /// });
+ /// ```
+ pub fn set_color(&mut self, color: Color) -> &mut Style {
+ self.spec.set_fg(Some(color.into_termcolor()));
+ self
+ }
+
+ /// Set the text weight.
+ ///
+ /// If `yes` is true then text will be written in bold.
+ /// If `yes` is false then text will be written in the default weight.
+ ///
+ /// # Examples
+ ///
+ /// Create a style with bold text:
+ ///
+ /// ```
+ /// use std::io::Write;
+ ///
+ /// let mut builder = env_logger::Builder::new();
+ ///
+ /// builder.format(|buf, record| {
+ /// let mut style = buf.style();
+ ///
+ /// style.set_bold(true);
+ ///
+ /// writeln!(buf, "{}", style.value(record.args()))
+ /// });
+ /// ```
+ pub fn set_bold(&mut self, yes: bool) -> &mut Style {
+ self.spec.set_bold(yes);
+ self
+ }
+
+ /// Set the text intensity.
+ ///
+ /// If `yes` is true then text will be written in a brighter color.
+ /// If `yes` is false then text will be written in the default color.
+ ///
+ /// # Examples
+ ///
+ /// Create a style with intense text:
+ ///
+ /// ```
+ /// use std::io::Write;
+ ///
+ /// let mut builder = env_logger::Builder::new();
+ ///
+ /// builder.format(|buf, record| {
+ /// let mut style = buf.style();
+ ///
+ /// style.set_intense(true);
+ ///
+ /// writeln!(buf, "{}", style.value(record.args()))
+ /// });
+ /// ```
+ pub fn set_intense(&mut self, yes: bool) -> &mut Style {
+ self.spec.set_intense(yes);
+ self
+ }
+
+ /// Set whether the text is dimmed.
+ ///
+ /// If `yes` is true then text will be written in a dimmer color.
+ /// If `yes` is false then text will be written in the default color.
+ ///
+ /// # Examples
+ ///
+ /// Create a style with dimmed text:
+ ///
+ /// ```
+ /// use std::io::Write;
+ ///
+ /// let mut builder = env_logger::Builder::new();
+ ///
+ /// builder.format(|buf, record| {
+ /// let mut style = buf.style();
+ ///
+ /// style.set_dimmed(true);
+ ///
+ /// writeln!(buf, "{}", style.value(record.args()))
+ /// });
+ /// ```
+ pub fn set_dimmed(&mut self, yes: bool) -> &mut Style {
+ self.spec.set_dimmed(yes);
+ self
+ }
+
+ /// Set the background color.
+ ///
+ /// # Examples
+ ///
+ /// Create a style with a yellow background:
+ ///
+ /// ```
+ /// use std::io::Write;
+ /// use env_logger::fmt::Color;
+ ///
+ /// let mut builder = env_logger::Builder::new();
+ ///
+ /// builder.format(|buf, record| {
+ /// let mut style = buf.style();
+ ///
+ /// style.set_bg(Color::Yellow);
+ ///
+ /// writeln!(buf, "{}", style.value(record.args()))
+ /// });
+ /// ```
+ pub fn set_bg(&mut self, color: Color) -> &mut Style {
+ self.spec.set_bg(Some(color.into_termcolor()));
+ self
+ }
+
+ /// Wrap a value in the style.
+ ///
+ /// The same `Style` can be used to print multiple different values.
+ ///
+ /// # Examples
+ ///
+ /// Create a bold, red colored style and use it to print the log level:
+ ///
+ /// ```
+ /// use std::io::Write;
+ /// use env_logger::fmt::Color;
+ ///
+ /// let mut builder = env_logger::Builder::new();
+ ///
+ /// builder.format(|buf, record| {
+ /// let mut style = buf.style();
+ ///
+ /// style.set_color(Color::Red).set_bold(true);
+ ///
+ /// writeln!(buf, "{}: {}",
+ /// style.value(record.level()),
+ /// record.args())
+ /// });
+ /// ```
+ pub fn value<T>(&self, value: T) -> StyledValue<T> {
+ StyledValue {
+ style: Cow::Borrowed(self),
+ value,
+ }
+ }
+
+ /// Wrap a value in the style by taking ownership of it.
+ pub(crate) fn into_value<T>(self, value: T) -> StyledValue<'static, T> {
+ StyledValue {
+ style: Cow::Owned(self),
+ value,
+ }
+ }
+}
+
+impl<'a, T> StyledValue<'a, T> {
+ fn write_fmt<F>(&self, f: F) -> fmt::Result
+ where
+ F: FnOnce() -> fmt::Result,
+ {
+ self.style
+ .buf
+ .borrow_mut()
+ .set_color(&self.style.spec)
+ .map_err(|_| fmt::Error)?;
+
+ // Always try to reset the terminal style, even if writing failed
+ let write = f();
+ let reset = self.style.buf.borrow_mut().reset().map_err(|_| fmt::Error);
+
+ write.and(reset)
+ }
+}
+
+impl fmt::Debug for Style {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("Style").field("spec", &self.spec).finish()
+ }
+}
+
+macro_rules! impl_styled_value_fmt {
+ ($($fmt_trait:path),*) => {
+ $(
+ impl<'a, T: $fmt_trait> $fmt_trait for StyledValue<'a, T> {
+ fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result {
+ self.write_fmt(|| T::fmt(&self.value, f))
+ }
+ }
+ )*
+ };
+}
+
+impl_styled_value_fmt!(
+ fmt::Debug,
+ fmt::Display,
+ fmt::Pointer,
+ fmt::Octal,
+ fmt::Binary,
+ fmt::UpperHex,
+ fmt::LowerHex,
+ fmt::UpperExp,
+ fmt::LowerExp
+);
+
+// The `Color` type is copied from https://github.com/BurntSushi/termcolor
+
+/// The set of available colors for the terminal foreground/background.
+///
+/// The `Ansi256` and `Rgb` colors will only output the correct codes when
+/// paired with the `Ansi` `WriteColor` implementation.
+///
+/// The `Ansi256` and `Rgb` color types are not supported when writing colors
+/// on Windows using the console. If they are used on Windows, then they are
+/// silently ignored and no colors will be emitted.
+///
+/// This set may expand over time.
+///
+/// This type has a `FromStr` impl that can parse colors from their human
+/// readable form. The format is as follows:
+///
+/// 1. Any of the explicitly listed colors in English. They are matched
+/// case insensitively.
+/// 2. A single 8-bit integer, in either decimal or hexadecimal format.
+/// 3. A triple of 8-bit integers separated by a comma, where each integer is
+/// in decimal or hexadecimal format.
+///
+/// Hexadecimal numbers are written with a `0x` prefix.
+#[allow(missing_docs)]
+#[non_exhaustive]
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum Color {
+ Black,
+ Blue,
+ Green,
+ Red,
+ Cyan,
+ Magenta,
+ Yellow,
+ White,
+ Ansi256(u8),
+ Rgb(u8, u8, u8),
+}
+
+impl Color {
+ fn into_termcolor(self) -> termcolor::Color {
+ match self {
+ Color::Black => termcolor::Color::Black,
+ Color::Blue => termcolor::Color::Blue,
+ Color::Green => termcolor::Color::Green,
+ Color::Red => termcolor::Color::Red,
+ Color::Cyan => termcolor::Color::Cyan,
+ Color::Magenta => termcolor::Color::Magenta,
+ Color::Yellow => termcolor::Color::Yellow,
+ Color::White => termcolor::Color::White,
+ Color::Ansi256(value) => termcolor::Color::Ansi256(value),
+ Color::Rgb(r, g, b) => termcolor::Color::Rgb(r, g, b),
+ }
+ }
+}
diff --git a/vendor/env_logger/src/fmt/writer/termcolor/mod.rs b/vendor/env_logger/src/fmt/writer/termcolor/mod.rs
new file mode 100644
index 000000000..20f01979e
--- /dev/null
+++ b/vendor/env_logger/src/fmt/writer/termcolor/mod.rs
@@ -0,0 +1,12 @@
+/*
+This internal module contains the style and terminal writing implementation.
+
+Its public API is available when the `termcolor` crate is available.
+The terminal printing is shimmed when the `termcolor` crate is not available.
+*/
+
+#[cfg_attr(feature = "color", path = "extern_impl.rs")]
+#[cfg_attr(not(feature = "color"), path = "shim_impl.rs")]
+mod imp;
+
+pub(in crate::fmt) use self::imp::*;
diff --git a/vendor/env_logger/src/fmt/writer/termcolor/shim_impl.rs b/vendor/env_logger/src/fmt/writer/termcolor/shim_impl.rs
new file mode 100644
index 000000000..0705770c9
--- /dev/null
+++ b/vendor/env_logger/src/fmt/writer/termcolor/shim_impl.rs
@@ -0,0 +1,72 @@
+use std::{io, sync::Mutex};
+
+use crate::fmt::{WritableTarget, WriteStyle};
+
+pub(in crate::fmt::writer) mod glob {}
+
+pub(in crate::fmt::writer) struct BufferWriter {
+ target: WritableTarget,
+}
+
+pub(in crate::fmt) struct Buffer(Vec<u8>);
+
+impl BufferWriter {
+ pub(in crate::fmt::writer) fn stderr(_is_test: bool, _write_style: WriteStyle) -> Self {
+ BufferWriter {
+ target: WritableTarget::Stderr,
+ }
+ }
+
+ pub(in crate::fmt::writer) fn stdout(_is_test: bool, _write_style: WriteStyle) -> Self {
+ BufferWriter {
+ target: WritableTarget::Stdout,
+ }
+ }
+
+ pub(in crate::fmt::writer) fn pipe(
+ _write_style: WriteStyle,
+ pipe: Box<Mutex<dyn io::Write + Send + 'static>>,
+ ) -> Self {
+ BufferWriter {
+ target: WritableTarget::Pipe(pipe),
+ }
+ }
+
+ pub(in crate::fmt::writer) fn buffer(&self) -> Buffer {
+ Buffer(Vec::new())
+ }
+
+ pub(in crate::fmt::writer) fn print(&self, buf: &Buffer) -> io::Result<()> {
+ // This impl uses the `eprint` and `print` macros
+ // instead of using the streams directly.
+ // This is so their output can be captured by `cargo test`.
+ match &self.target {
+ // Safety: If the target type is `Pipe`, `target_pipe` will always be non-empty.
+ WritableTarget::Pipe(pipe) => pipe.lock().unwrap().write_all(&buf.0)?,
+ WritableTarget::Stdout => print!("{}", String::from_utf8_lossy(&buf.0)),
+ WritableTarget::Stderr => eprint!("{}", String::from_utf8_lossy(&buf.0)),
+ }
+
+ Ok(())
+ }
+}
+
+impl Buffer {
+ pub(in crate::fmt) fn clear(&mut self) {
+ self.0.clear();
+ }
+
+ pub(in crate::fmt) fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.0.extend(buf);
+ Ok(buf.len())
+ }
+
+ pub(in crate::fmt) fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+
+ #[cfg(test)]
+ pub(in crate::fmt) fn bytes(&self) -> &[u8] {
+ &self.0
+ }
+}