diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 18:31:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 18:31:44 +0000 |
commit | c23a457e72abe608715ac76f076f47dc42af07a5 (patch) | |
tree | 2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /vendor/anstream | |
parent | Releasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip |
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/anstream')
-rw-r--r-- | vendor/anstream/.cargo-checksum.json | 2 | ||||
-rw-r--r-- | vendor/anstream/Cargo.toml | 18 | ||||
-rw-r--r-- | vendor/anstream/benches/stream.rs | 15 | ||||
-rw-r--r-- | vendor/anstream/benches/strip.rs | 2 | ||||
-rw-r--r-- | vendor/anstream/src/auto.rs | 100 | ||||
-rw-r--r-- | vendor/anstream/src/buffer.rs | 46 | ||||
-rw-r--r-- | vendor/anstream/src/fmt.rs | 54 | ||||
-rw-r--r-- | vendor/anstream/src/lib.rs | 8 | ||||
-rw-r--r-- | vendor/anstream/src/lockable.rs | 48 | ||||
-rw-r--r-- | vendor/anstream/src/macros.rs | 128 | ||||
-rw-r--r-- | vendor/anstream/src/raw.rs | 46 | ||||
-rw-r--r-- | vendor/anstream/src/stream.rs | 261 | ||||
-rw-r--r-- | vendor/anstream/src/strip.rs | 107 | ||||
-rw-r--r-- | vendor/anstream/src/wincon.rs | 162 |
14 files changed, 687 insertions, 310 deletions
diff --git a/vendor/anstream/.cargo-checksum.json b/vendor/anstream/.cargo-checksum.json index 3824cf9a4..a4d939b43 100644 --- a/vendor/anstream/.cargo-checksum.json +++ b/vendor/anstream/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"48f9c457447fc49837fbbb9e76351fb4c685654fff37fa48b04c93fdc10a02c3","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"6efb0476a1cc085077ed49357026d8c173bf33017278ef440f222fb9cbcb66e6","README.md":"b230c2257d0c7a49b9bd97f2fa73abedcdc055757b5cedd2b0eb1a7a448ff461","benches/stream.rs":"94226af8a048d5db3d6a2e756ed0a1e3ca44a4927a7648ac673d6c3c621cda35","benches/strip.rs":"0569a82722cec5f2bbbf027ab279b7d946f9be7f2a8e698eb992e01c3d33898a","benches/wincon.rs":"680e86933c008b242a3286c5149c33d3c086426eb99fe134b6e79f7578f96663","src/adapter/mod.rs":"baf4237ea0b18df63609e49d93572ca27c2202a4cbec0220adb5a7e815c7d8ed","src/adapter/strip.rs":"010972f96708c56da9bced98287f134ce43a4f6459c22c1697abdc4fd6f82d00","src/adapter/wincon.rs":"9869aa553c253c49bebc0830628225cd294df8e84837b3952529173b06b24b85","src/auto.rs":"18796e0449ca0dff4a535e580e7176abab78227c6a1cd63f2c83b8f4ceceaab9","src/buffer.rs":"89712eb5c75ccfd4d4d757be394f2631844d7f0227afe0af4f5c3ff1567b750e","src/lib.rs":"059cdc8f9759c33f483a7997b7bd8c74c74a83911f2a0a70fa9aa3deaca277d8","src/lockable.rs":"09ffb8a7362c0812da9960234be6cf8290814453be94f6476be64e3804d6ce47","src/macros.rs":"9b8e1c5b0639c019fa2a84cc825e52fcd0749af4876a9ecf3a750f68469986aa","src/raw.rs":"beb6038242ca46aa21f09a55d8956422cdf6f1596fa97bb3ddf79ab67ac0c8f2","src/strip.rs":"d8469758e9992109b70c8b21b44794eb7341d29034fb0a9bd746c1174e7484f9","src/wincon.rs":"d27007d3b3453dbe18b49cdc088e8aabec2203149cb1f3e7aa4fcee28071d58b"},"package":"0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"}
\ No newline at end of file +{"files":{"Cargo.toml":"5bd2428bd62a91e0f3be5e64d2df8facd8873ddad6ed3eb2335ec7292f09c7ae","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"6efb0476a1cc085077ed49357026d8c173bf33017278ef440f222fb9cbcb66e6","README.md":"b230c2257d0c7a49b9bd97f2fa73abedcdc055757b5cedd2b0eb1a7a448ff461","benches/stream.rs":"7e666c4f4b79ddb5237361ed25264a966ee241192fbb2c1baea3006e3e0326b4","benches/strip.rs":"9603bd5ca1ae4661c2ccab50315dbfdec0c661ac2624262172bbd8f5d0bd87c9","benches/wincon.rs":"680e86933c008b242a3286c5149c33d3c086426eb99fe134b6e79f7578f96663","src/adapter/mod.rs":"baf4237ea0b18df63609e49d93572ca27c2202a4cbec0220adb5a7e815c7d8ed","src/adapter/strip.rs":"010972f96708c56da9bced98287f134ce43a4f6459c22c1697abdc4fd6f82d00","src/adapter/wincon.rs":"9869aa553c253c49bebc0830628225cd294df8e84837b3952529173b06b24b85","src/auto.rs":"36dafc3aabaff080198f901268d2aa5453cc4b1cd7b93277edf90cad6354cb72","src/buffer.rs":"83e7088b50dd3e2941c06a417d9eef75fda45311a2912ba94f480ec98d6f0183","src/fmt.rs":"cc11b005c4559843bd908a57958a13c8d0922fae6aff5261f3583c90e60da73c","src/lib.rs":"649b86b187835e0e33baaaf2242c5f331b7dff133fae8fc419c52b7add797c57","src/macros.rs":"a26ababe32a39732d0aade9674f6e5e267bd26c6ea06603ff9e61e80681195e0","src/stream.rs":"cbe8f61fba4c3c60934339c8bda5d1ff43320f57cdc4ed409aa173945a941b3d","src/strip.rs":"56e6516283b6c0dfa72a8e0e6679da8424295f50a3e56c44281e76de6aa0344b","src/wincon.rs":"fe5aff7bfd80b14c9a6b07143079d59b81831293ad766b845e46fad2e1459c9a"},"package":"83d7b3983a025adeb201ef26a5564ebd1641ea9851f6282aee4940f745a3c07c"}
\ No newline at end of file diff --git a/vendor/anstream/Cargo.toml b/vendor/anstream/Cargo.toml index 75d78e26e..d60caca19 100644 --- a/vendor/anstream/Cargo.toml +++ b/vendor/anstream/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.64.0" +rust-version = "1.70.0" name = "anstream" -version = "0.3.2" +version = "0.6.3" include = [ "build.rs", "src/**/*", @@ -109,37 +109,33 @@ optional = true version = "1.0.0" optional = true -[dependencies.is-terminal] -version = "0.4.4" -optional = true - [dependencies.utf8parse] version = "0.2.1" [dev-dependencies.criterion] -version = "0.4.0" +version = "0.5.1" [dev-dependencies.owo-colors] version = "3.5.0" [dev-dependencies.proptest] -version = "1.1.0" +version = "1.2.0" [dev-dependencies.strip-ansi-escapes] -version = "0.1.1" +version = "0.2.0" [features] auto = [ "dep:anstyle-query", "dep:colorchoice", - "dep:is-terminal", ] default = [ "auto", "wincon", ] +test = [] wincon = ["dep:anstyle-wincon"] [target."cfg(windows)".dependencies.anstyle-wincon] -version = "1.0.1" +version = "3.0.1" optional = true diff --git a/vendor/anstream/benches/stream.rs b/vendor/anstream/benches/stream.rs index 55c20b896..f89aacf5f 100644 --- a/vendor/anstream/benches/stream.rs +++ b/vendor/anstream/benches/stream.rs @@ -15,7 +15,7 @@ fn stream(c: &mut Criterion) { let mut group = c.benchmark_group(name); group.bench_function("nop", |b| { b.iter(|| { - let buffer = anstream::Buffer::with_capacity(content.len()); + let buffer = Vec::with_capacity(content.len()); let mut stream = buffer; stream.write_all(content).unwrap(); @@ -25,7 +25,7 @@ fn stream(c: &mut Criterion) { }); group.bench_function("StripStream", |b| { b.iter(|| { - let buffer = anstream::Buffer::with_capacity(content.len()); + let buffer = Vec::with_capacity(content.len()); let mut stream = anstream::StripStream::new(buffer); stream.write_all(content).unwrap(); @@ -36,9 +36,8 @@ fn stream(c: &mut Criterion) { #[cfg(all(windows, feature = "wincon"))] group.bench_function("WinconStream", |b| { b.iter(|| { - let buffer = anstream::Buffer::with_capacity(content.len()); - let mut stream = - anstream::WinconStream::new(anstyle_wincon::Console::new(buffer).unwrap()); + let buffer = Vec::with_capacity(content.len()); + let mut stream = anstream::WinconStream::new(buffer); stream.write_all(content).unwrap(); @@ -47,7 +46,7 @@ fn stream(c: &mut Criterion) { }); group.bench_function("AutoStream::always_ansi", |b| { b.iter(|| { - let buffer = anstream::Buffer::with_capacity(content.len()); + let buffer = Vec::with_capacity(content.len()); let mut stream = anstream::AutoStream::always_ansi(buffer); stream.write_all(content).unwrap(); @@ -57,7 +56,7 @@ fn stream(c: &mut Criterion) { }); group.bench_function("AutoStream::always", |b| { b.iter(|| { - let buffer = anstream::Buffer::with_capacity(content.len()); + let buffer = Vec::with_capacity(content.len()); let mut stream = anstream::AutoStream::always(buffer); stream.write_all(content).unwrap(); @@ -67,7 +66,7 @@ fn stream(c: &mut Criterion) { }); group.bench_function("AutoStream::never", |b| { b.iter(|| { - let buffer = anstream::Buffer::with_capacity(content.len()); + let buffer = Vec::with_capacity(content.len()); let mut stream = anstream::AutoStream::never(buffer); stream.write_all(content).unwrap(); diff --git a/vendor/anstream/benches/strip.rs b/vendor/anstream/benches/strip.rs index af204bf96..9ed6178c4 100644 --- a/vendor/anstream/benches/strip.rs +++ b/vendor/anstream/benches/strip.rs @@ -63,7 +63,7 @@ fn strip(c: &mut Criterion) { }); group.bench_function("strip_ansi_escapes", |b| { b.iter(|| { - let stripped = strip_ansi_escapes::strip(content).unwrap(); + let stripped = strip_ansi_escapes::strip(content); black_box(stripped) }) diff --git a/vendor/anstream/src/auto.rs b/vendor/anstream/src/auto.rs index b252c05cb..2b9d361cd 100644 --- a/vendor/anstream/src/auto.rs +++ b/vendor/anstream/src/auto.rs @@ -1,7 +1,7 @@ +use crate::stream::AsLockedWrite; +use crate::stream::RawStream; #[cfg(feature = "auto")] use crate::ColorChoice; -use crate::Lockable; -use crate::RawStream; use crate::StripStream; #[cfg(all(windows, feature = "wincon"))] use crate::WinconStream; @@ -101,9 +101,8 @@ where fn wincon(raw: S) -> Result<Self, S> { #[cfg(all(windows, feature = "wincon"))] { - let console = anstyle_wincon::Console::new(raw)?; Ok(Self { - inner: StreamInner::Wincon(WinconStream::new(console)), + inner: StreamInner::Wincon(WinconStream::new(raw)), }) } #[cfg(not(all(windows, feature = "wincon")))] @@ -119,18 +118,30 @@ where StreamInner::PassThrough(w) => w, StreamInner::Strip(w) => w.into_inner(), #[cfg(all(windows, feature = "wincon"))] - StreamInner::Wincon(w) => w.into_inner().into_inner(), + StreamInner::Wincon(w) => w.into_inner(), } } #[inline] - #[cfg(feature = "auto")] pub fn is_terminal(&self) -> bool { match &self.inner { StreamInner::PassThrough(w) => w.is_terminal(), StreamInner::Strip(w) => w.is_terminal(), #[cfg(all(windows, feature = "wincon"))] - StreamInner::Wincon(w) => true, + StreamInner::Wincon(_) => true, // its only ever a terminal + } + } + + /// Prefer [`AutoStream::choice`] + /// + /// This doesn't report what is requested but what is currently active. + #[inline] + pub fn current_choice(&self) -> ColorChoice { + match &self.inner { + StreamInner::PassThrough(_) => ColorChoice::AlwaysAnsi, + StreamInner::Strip(_) => ColorChoice::Never, + #[cfg(all(windows, feature = "wincon"))] + StreamInner::Wincon(_) => ColorChoice::Always, } } } @@ -160,29 +171,32 @@ fn choice(raw: &dyn RawStream) -> ColorChoice { } } -#[cfg(feature = "auto")] -impl<S> is_terminal::IsTerminal for AutoStream<S> -where - S: RawStream, -{ +impl AutoStream<std::io::Stdout> { + /// Get exclusive access to the `AutoStream` + /// + /// Why? + /// - Faster performance when writing in a loop + /// - Avoid other threads interleaving output with the current thread #[inline] - fn is_terminal(&self) -> bool { - self.is_terminal() + pub fn lock(self) -> AutoStream<std::io::StdoutLock<'static>> { + let inner = match self.inner { + StreamInner::PassThrough(w) => StreamInner::PassThrough(w.lock()), + StreamInner::Strip(w) => StreamInner::Strip(w.lock()), + #[cfg(all(windows, feature = "wincon"))] + StreamInner::Wincon(w) => StreamInner::Wincon(w.lock()), + }; + AutoStream { inner } } } -impl<S> AutoStream<S> -where - S: Lockable + RawStream, - <S as Lockable>::Locked: RawStream, -{ +impl AutoStream<std::io::Stderr> { /// Get exclusive access to the `AutoStream` /// /// Why? /// - Faster performance when writing in a loop /// - Avoid other threads interleaving output with the current thread #[inline] - pub fn lock(self) -> <Self as Lockable>::Locked { + pub fn lock(self) -> AutoStream<std::io::StderrLock<'static>> { let inner = match self.inner { StreamInner::PassThrough(w) => StreamInner::PassThrough(w.lock()), StreamInner::Strip(w) => StreamInner::Strip(w.lock()), @@ -195,54 +209,54 @@ where impl<S> std::io::Write for AutoStream<S> where - S: RawStream, + S: RawStream + AsLockedWrite, { + // Must forward all calls to ensure locking happens appropriately #[inline] fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { match &mut self.inner { - StreamInner::PassThrough(w) => w.write(buf), + StreamInner::PassThrough(w) => w.as_locked_write().write(buf), StreamInner::Strip(w) => w.write(buf), #[cfg(all(windows, feature = "wincon"))] StreamInner::Wincon(w) => w.write(buf), } } - + #[inline] + fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result<usize> { + match &mut self.inner { + StreamInner::PassThrough(w) => w.as_locked_write().write_vectored(bufs), + StreamInner::Strip(w) => w.write_vectored(bufs), + #[cfg(all(windows, feature = "wincon"))] + StreamInner::Wincon(w) => w.write_vectored(bufs), + } + } + // is_write_vectored: nightly only #[inline] fn flush(&mut self) -> std::io::Result<()> { match &mut self.inner { - StreamInner::PassThrough(w) => w.flush(), + StreamInner::PassThrough(w) => w.as_locked_write().flush(), StreamInner::Strip(w) => w.flush(), #[cfg(all(windows, feature = "wincon"))] StreamInner::Wincon(w) => w.flush(), } } - - // Provide explicit implementations of trait methods - // - To reduce bookkeeping - // - Avoid acquiring / releasing locks in a loop - #[inline] fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> { match &mut self.inner { - StreamInner::PassThrough(w) => w.write_all(buf), + StreamInner::PassThrough(w) => w.as_locked_write().write_all(buf), StreamInner::Strip(w) => w.write_all(buf), #[cfg(all(windows, feature = "wincon"))] StreamInner::Wincon(w) => w.write_all(buf), } } - - // Not bothering with `write_fmt` as it just calls `write_all` -} - -impl<S> Lockable for AutoStream<S> -where - S: Lockable + RawStream, - <S as Lockable>::Locked: RawStream, -{ - type Locked = AutoStream<<S as Lockable>::Locked>; - + // write_all_vectored: nightly only #[inline] - fn lock(self) -> Self::Locked { - self.lock() + fn write_fmt(&mut self, args: std::fmt::Arguments<'_>) -> std::io::Result<()> { + match &mut self.inner { + StreamInner::PassThrough(w) => w.as_locked_write().write_fmt(args), + StreamInner::Strip(w) => w.write_fmt(args), + #[cfg(all(windows, feature = "wincon"))] + StreamInner::Wincon(w) => w.write_fmt(args), + } } } diff --git a/vendor/anstream/src/buffer.rs b/vendor/anstream/src/buffer.rs index 1ba0bffdb..9846bb7c8 100644 --- a/vendor/anstream/src/buffer.rs +++ b/vendor/anstream/src/buffer.rs @@ -1,5 +1,9 @@ -/// In-memory [`RawStream`][crate::RawStream] +#![allow(deprecated)] + +/// In-memory [`RawStream`][crate::stream::RawStream] #[derive(Clone, Default, Debug, PartialEq, Eq)] +#[deprecated(since = "0.6.2", note = "Use Vec")] +#[doc(hidden)] pub struct Buffer(Vec<u8>); impl Buffer { @@ -26,14 +30,6 @@ impl AsRef<[u8]> for Buffer { } } -#[cfg(feature = "auto")] -impl is_terminal::IsTerminal for Buffer { - #[inline] - fn is_terminal(&self) -> bool { - false - } -} - impl std::io::Write for Buffer { #[inline] fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { @@ -49,28 +45,24 @@ impl std::io::Write for Buffer { #[cfg(all(windows, feature = "wincon"))] impl anstyle_wincon::WinconStream for Buffer { - fn set_colors( + fn write_colored( &mut self, fg: Option<anstyle::AnsiColor>, bg: Option<anstyle::AnsiColor>, - ) -> std::io::Result<()> { - use std::io::Write as _; - - if let Some(fg) = fg { - write!(self, "{}", fg.render_fg())?; - } - if let Some(bg) = bg { - write!(self, "{}", bg.render_bg())?; - } - if fg.is_none() && bg.is_none() { - write!(self, "{}", anstyle::Reset.render())?; - } - Ok(()) + data: &[u8], + ) -> std::io::Result<usize> { + self.0.write_colored(fg, bg, data) } +} - fn get_colors( - &self, - ) -> std::io::Result<(Option<anstyle::AnsiColor>, Option<anstyle::AnsiColor>)> { - Ok((None, None)) +#[cfg(all(windows, feature = "wincon"))] +impl anstyle_wincon::WinconStream for &'_ mut Buffer { + fn write_colored( + &mut self, + fg: Option<anstyle::AnsiColor>, + bg: Option<anstyle::AnsiColor>, + data: &[u8], + ) -> std::io::Result<usize> { + (**self).write_colored(fg, bg, data) } } diff --git a/vendor/anstream/src/fmt.rs b/vendor/anstream/src/fmt.rs new file mode 100644 index 000000000..e673c26dd --- /dev/null +++ b/vendor/anstream/src/fmt.rs @@ -0,0 +1,54 @@ +/// A shim which allows a [`std::io::Write`] to be implemented in terms of a [`std::fmt::Write`] +/// +/// This saves off I/O errors. instead of discarding them +pub(crate) struct Adapter<W> +where + W: FnMut(&[u8]) -> std::io::Result<()>, +{ + writer: W, + error: std::io::Result<()>, +} + +impl<W> Adapter<W> +where + W: FnMut(&[u8]) -> std::io::Result<()>, +{ + pub(crate) fn new(writer: W) -> Self { + Adapter { + writer, + error: Ok(()), + } + } + + pub(crate) fn write_fmt(mut self, fmt: std::fmt::Arguments<'_>) -> std::io::Result<()> { + match std::fmt::write(&mut self, fmt) { + Ok(()) => Ok(()), + Err(..) => { + // check if the error came from the underlying `Write` or not + if self.error.is_err() { + self.error + } else { + Err(std::io::Error::new( + std::io::ErrorKind::Other, + "formatter error", + )) + } + } + } + } +} + +impl<W> std::fmt::Write for Adapter<W> +where + W: FnMut(&[u8]) -> std::io::Result<()>, +{ + fn write_str(&mut self, s: &str) -> std::fmt::Result { + match (self.writer)(s.as_bytes()) { + Ok(()) => Ok(()), + Err(e) => { + self.error = Err(e); + Err(std::fmt::Error) + } + } + } +} diff --git a/vendor/anstream/src/lib.rs b/vendor/anstream/src/lib.rs index 582fa5221..972113903 100644 --- a/vendor/anstream/src/lib.rs +++ b/vendor/anstream/src/lib.rs @@ -35,23 +35,23 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg))] pub mod adapter; +pub mod stream; + mod buffer; #[macro_use] mod macros; mod auto; -mod lockable; -mod raw; +mod fmt; mod strip; #[cfg(all(windows, feature = "wincon"))] mod wincon; pub use auto::AutoStream; -pub use lockable::Lockable; -pub use raw::RawStream; pub use strip::StripStream; #[cfg(all(windows, feature = "wincon"))] pub use wincon::WinconStream; +#[allow(deprecated)] pub use buffer::Buffer; /// Create an ANSI escape code compatible stdout diff --git a/vendor/anstream/src/lockable.rs b/vendor/anstream/src/lockable.rs deleted file mode 100644 index fcf20e317..000000000 --- a/vendor/anstream/src/lockable.rs +++ /dev/null @@ -1,48 +0,0 @@ -#[cfg(all(windows, feature = "wincon"))] -use crate::RawStream; - -/// Explicitly lock a [`std::io::Write`]able -pub trait Lockable { - type Locked; - - /// Get exclusive access to the `AutoStream` - /// - /// Why? - /// - Faster performance when writing in a loop - /// - Avoid other threads interleaving output with the current thread - fn lock(self) -> Self::Locked; -} - -impl Lockable for std::io::Stdout { - type Locked = std::io::StdoutLock<'static>; - - #[inline] - fn lock(self) -> Self::Locked { - #[allow(clippy::needless_borrow)] // Its needed to avoid recursion - (&self).lock() - } -} - -impl Lockable for std::io::Stderr { - type Locked = std::io::StderrLock<'static>; - - #[inline] - fn lock(self) -> Self::Locked { - #[allow(clippy::needless_borrow)] // Its needed to avoid recursion - (&self).lock() - } -} - -#[cfg(all(windows, feature = "wincon"))] -impl<S> Lockable for anstyle_wincon::Console<S> -where - S: RawStream + Lockable, - <S as Lockable>::Locked: RawStream, -{ - type Locked = anstyle_wincon::Console<<S as Lockable>::Locked>; - - #[inline] - fn lock(self) -> Self::Locked { - self.map(|s| s.lock()) - } -} diff --git a/vendor/anstream/src/macros.rs b/vendor/anstream/src/macros.rs index ea9095944..bd1accb06 100644 --- a/vendor/anstream/src/macros.rs +++ b/vendor/anstream/src/macros.rs @@ -22,6 +22,10 @@ /// Use `print!` only for the primary output of your program. Use /// [`eprint!`] instead to print error and progress messages. /// +/// **NOTE:** Not all `print!` calls will be captured in tests like [`std::print!`] +/// - Capturing will automatically be activated in test binaries +/// - Otherwise, only when the `test` feature is enabled +/// /// # Panics /// /// Panics if writing to `stdout` fails for any reason **except** broken pipe. @@ -56,14 +60,29 @@ #[macro_export] macro_rules! print { ($($arg:tt)*) => {{ - use std::io::Write as _; + if cfg!(any(feature = "test", test)) { + use std::io::Write as _; + + let stdio = std::io::stdout(); + let choice = $crate::AutoStream::choice(&stdio); + let buffer = Vec::new(); + let mut stream = $crate::AutoStream::new(buffer, choice); + // Ignore errors rather than panic + let _ = ::std::write!(&mut stream, $($arg)*); + let buffer = stream.into_inner(); + // Should be UTF-8 but not wanting to panic + let buffer = String::from_utf8_lossy(&buffer); + ::std::print!("{}", buffer) + } else { + use std::io::Write as _; - let mut stream = $crate::stdout(); - match ::std::write!(&mut stream, $($arg)*) { - Err(e) if e.kind() != ::std::io::ErrorKind::BrokenPipe => { - ::std::panic!("failed printing to stdout: {e}"); + let mut stream = $crate::stdout(); + match ::std::write!(&mut stream, $($arg)*) { + Err(e) if e.kind() != ::std::io::ErrorKind::BrokenPipe => { + ::std::panic!("failed printing to stdout: {e}"); + } + Err(_) | Ok(_) => {} } - Err(_) | Ok(_) => {} } }}; } @@ -91,6 +110,10 @@ macro_rules! print { /// Use `println!` only for the primary output of your program. Use /// [`eprintln!`] instead to print error and progress messages. /// +/// **NOTE:** Not all `println!` calls will be captured in tests like [`std::println!`] +/// - Capturing will automatically be activated in test binaries +/// - Otherwise, only when the `test` feature is enabled +/// /// # Panics /// /// Panics if writing to `stdout` fails for any reason **except** broken pipe. @@ -118,14 +141,29 @@ macro_rules! println { $crate::print!("\n") }; ($($arg:tt)*) => {{ - use std::io::Write as _; + if cfg!(any(feature = "test", test)) { + use std::io::Write as _; + + let stdio = std::io::stdout(); + let choice = $crate::AutoStream::choice(&stdio); + let buffer = Vec::new(); + let mut stream = $crate::AutoStream::new(buffer, choice); + // Ignore errors rather than panic + let _ = ::std::write!(&mut stream, $($arg)*); + let buffer = stream.into_inner(); + // Should be UTF-8 but not wanting to panic + let buffer = String::from_utf8_lossy(&buffer); + ::std::println!("{}", buffer) + } else { + use std::io::Write as _; - let mut stream = $crate::stdout(); - match ::std::writeln!(&mut stream, $($arg)*) { - Err(e) if e.kind() != ::std::io::ErrorKind::BrokenPipe => { - ::std::panic!("failed printing to stdout: {e}"); + let mut stream = $crate::stdout(); + match ::std::writeln!(&mut stream, $($arg)*) { + Err(e) if e.kind() != ::std::io::ErrorKind::BrokenPipe => { + ::std::panic!("failed printing to stdout: {e}"); + } + Err(_) | Ok(_) => {} } - Err(_) | Ok(_) => {} } }}; } @@ -139,6 +177,10 @@ macro_rules! println { /// Use `eprint!` only for error and progress messages. Use `print!` /// instead for the primary output of your program. /// +/// **NOTE:** Not all `eprint!` calls will be captured in tests like [`std::eprint!`] +/// - Capturing will automatically be activated in test binaries +/// - Otherwise, only when the `test` feature is enabled +/// /// # Panics /// /// Panics if writing to `stderr` fails for any reason **except** broken pipe. @@ -159,14 +201,29 @@ macro_rules! println { #[macro_export] macro_rules! eprint { ($($arg:tt)*) => {{ - use std::io::Write as _; + if cfg!(any(feature = "test", test)) { + use std::io::Write as _; + + let stdio = std::io::stderr(); + let choice = $crate::AutoStream::choice(&stdio); + let buffer = Vec::new(); + let mut stream = $crate::AutoStream::new(buffer, choice); + // Ignore errors rather than panic + let _ = ::std::write!(&mut stream, $($arg)*); + let buffer = stream.into_inner(); + // Should be UTF-8 but not wanting to panic + let buffer = String::from_utf8_lossy(&buffer); + ::std::eprint!("{}", buffer) + } else { + use std::io::Write as _; - let mut stream = $crate::stderr(); - match ::std::write!(&mut stream, $($arg)*) { - Err(e) if e.kind() != ::std::io::ErrorKind::BrokenPipe => { - ::std::panic!("failed printing to stdout: {e}"); + let mut stream = $crate::stderr(); + match ::std::write!(&mut stream, $($arg)*) { + Err(e) if e.kind() != ::std::io::ErrorKind::BrokenPipe => { + ::std::panic!("failed printing to stdout: {e}"); + } + Err(_) | Ok(_) => {} } - Err(_) | Ok(_) => {} } }}; } @@ -180,6 +237,10 @@ macro_rules! eprint { /// Use `eprintln!` only for error and progress messages. Use `println!` /// instead for the primary output of your program. /// +/// **NOTE:** Not all `eprintln!` calls will be captured in tests like [`std::eprintln!`] +/// - Capturing will automatically be activated in test binaries +/// - Otherwise, only when the `test` feature is enabled +/// /// # Panics /// /// Panics if writing to `stderr` fails for any reason **except** broken pipe. @@ -203,14 +264,29 @@ macro_rules! eprintln { $crate::eprint!("\n") }; ($($arg:tt)*) => {{ - use std::io::Write as _; + if cfg!(any(feature = "test", test)) { + use std::io::Write as _; + + let stdio = std::io::stderr(); + let choice = $crate::AutoStream::choice(&stdio); + let buffer = Vec::new(); + let mut stream = $crate::AutoStream::new(buffer, choice); + // Ignore errors rather than panic + let _ = ::std::write!(&mut stream, $($arg)*); + let buffer = stream.into_inner(); + // Should be UTF-8 but not wanting to panic + let buffer = String::from_utf8_lossy(&buffer); + ::std::eprintln!("{}", buffer) + } else { + use std::io::Write as _; - let mut stream = $crate::stderr(); - match ::std::writeln!(&mut stream, $($arg)*) { - Err(e) if e.kind() != ::std::io::ErrorKind::BrokenPipe => { - ::std::panic!("failed printing to stdout: {e}"); + let mut stream = $crate::stderr(); + match ::std::writeln!(&mut stream, $($arg)*) { + Err(e) if e.kind() != ::std::io::ErrorKind::BrokenPipe => { + ::std::panic!("failed printing to stdout: {e}"); + } + Err(_) | Ok(_) => {} } - Err(_) | Ok(_) => {} } }}; } @@ -301,13 +377,13 @@ macro_rules! panic { let panic_stream = std::io::stderr(); let choice = $crate::AutoStream::choice(&panic_stream); - let buffer = $crate::Buffer::new(); + let buffer = Vec::new(); let mut stream = $crate::AutoStream::new(buffer, choice); // Ignore errors rather than panic let _ = ::std::write!(&mut stream, $($arg)*); let buffer = stream.into_inner(); // Should be UTF-8 but not wanting to panic - let buffer = String::from_utf8_lossy(buffer.as_bytes()).into_owned(); + let buffer = String::from_utf8_lossy(&buffer).into_owned(); ::std::panic!("{}", buffer) }}; } diff --git a/vendor/anstream/src/raw.rs b/vendor/anstream/src/raw.rs deleted file mode 100644 index ecf7c6850..000000000 --- a/vendor/anstream/src/raw.rs +++ /dev/null @@ -1,46 +0,0 @@ -/// Required functionality for underlying [`std::io::Write`] for adaptation -#[cfg(not(any(feature = "auto", all(windows, feature = "wincon"))))] -pub trait RawStream: std::io::Write + private::Sealed {} - -/// Required functionality for underlying [`std::io::Write`] for adaptation -#[cfg(all(feature = "auto", not(all(windows, feature = "wincon"))))] -pub trait RawStream: std::io::Write + is_terminal::IsTerminal + private::Sealed {} - -/// Required functionality for underlying [`std::io::Write`] for adaptation -#[cfg(all(not(feature = "auto"), all(windows, feature = "wincon")))] -pub trait RawStream: std::io::Write + anstyle_wincon::WinconStream + private::Sealed {} - -/// Required functionality for underlying [`std::io::Write`] for adaptation -#[cfg(all(feature = "auto", all(windows, feature = "wincon")))] -pub trait RawStream: - std::io::Write + is_terminal::IsTerminal + anstyle_wincon::WinconStream + private::Sealed -{ -} - -impl RawStream for std::io::Stdout {} - -impl RawStream for std::io::StdoutLock<'static> {} - -impl RawStream for std::io::Stderr {} - -impl RawStream for std::io::StderrLock<'static> {} - -impl RawStream for std::fs::File {} - -impl RawStream for crate::Buffer {} - -mod private { - pub trait Sealed {} - - impl Sealed for std::io::Stdout {} - - impl Sealed for std::io::StdoutLock<'static> {} - - impl Sealed for std::io::Stderr {} - - impl Sealed for std::io::StderrLock<'static> {} - - impl Sealed for std::fs::File {} - - impl Sealed for crate::Buffer {} -} diff --git a/vendor/anstream/src/stream.rs b/vendor/anstream/src/stream.rs new file mode 100644 index 000000000..e2f7e68d9 --- /dev/null +++ b/vendor/anstream/src/stream.rs @@ -0,0 +1,261 @@ +//! Higher-level traits to describe writeable streams + +/// Required functionality for underlying [`std::io::Write`] for adaptation +#[cfg(not(all(windows, feature = "wincon")))] +pub trait RawStream: std::io::Write + IsTerminal + private::Sealed {} + +/// Required functionality for underlying [`std::io::Write`] for adaptation +#[cfg(all(windows, feature = "wincon"))] +pub trait RawStream: + std::io::Write + IsTerminal + anstyle_wincon::WinconStream + private::Sealed +{ +} + +impl RawStream for std::io::Stdout {} + +impl RawStream for std::io::StdoutLock<'_> {} + +impl RawStream for &'_ mut std::io::StdoutLock<'_> {} + +impl RawStream for std::io::Stderr {} + +impl RawStream for std::io::StderrLock<'_> {} + +impl RawStream for &'_ mut std::io::StderrLock<'_> {} + +impl RawStream for Box<dyn std::io::Write> {} + +impl RawStream for &'_ mut Box<dyn std::io::Write> {} + +impl RawStream for Vec<u8> {} + +impl RawStream for &'_ mut Vec<u8> {} + +impl RawStream for std::fs::File {} + +impl RawStream for &'_ mut std::fs::File {} + +#[allow(deprecated)] +impl RawStream for crate::Buffer {} + +#[allow(deprecated)] +impl RawStream for &'_ mut crate::Buffer {} + +pub trait IsTerminal: private::Sealed { + fn is_terminal(&self) -> bool; +} + +impl IsTerminal for std::io::Stdout { + #[inline] + fn is_terminal(&self) -> bool { + std::io::IsTerminal::is_terminal(self) + } +} + +impl IsTerminal for std::io::StdoutLock<'_> { + #[inline] + fn is_terminal(&self) -> bool { + std::io::IsTerminal::is_terminal(self) + } +} + +impl IsTerminal for &'_ mut std::io::StdoutLock<'_> { + #[inline] + fn is_terminal(&self) -> bool { + (**self).is_terminal() + } +} + +impl IsTerminal for std::io::Stderr { + #[inline] + fn is_terminal(&self) -> bool { + std::io::IsTerminal::is_terminal(self) + } +} + +impl IsTerminal for std::io::StderrLock<'_> { + #[inline] + fn is_terminal(&self) -> bool { + std::io::IsTerminal::is_terminal(self) + } +} + +impl IsTerminal for &'_ mut std::io::StderrLock<'_> { + #[inline] + fn is_terminal(&self) -> bool { + (**self).is_terminal() + } +} + +impl IsTerminal for Box<dyn std::io::Write> { + #[inline] + fn is_terminal(&self) -> bool { + false + } +} + +impl IsTerminal for &'_ mut Box<dyn std::io::Write> { + #[inline] + fn is_terminal(&self) -> bool { + false + } +} + +impl IsTerminal for Vec<u8> { + #[inline] + fn is_terminal(&self) -> bool { + false + } +} + +impl IsTerminal for &'_ mut Vec<u8> { + #[inline] + fn is_terminal(&self) -> bool { + false + } +} + +impl IsTerminal for std::fs::File { + #[inline] + fn is_terminal(&self) -> bool { + std::io::IsTerminal::is_terminal(self) + } +} + +impl IsTerminal for &'_ mut std::fs::File { + #[inline] + fn is_terminal(&self) -> bool { + (**self).is_terminal() + } +} + +#[allow(deprecated)] +impl IsTerminal for crate::Buffer { + #[inline] + fn is_terminal(&self) -> bool { + false + } +} + +#[allow(deprecated)] +impl IsTerminal for &'_ mut crate::Buffer { + #[inline] + fn is_terminal(&self) -> bool { + (**self).is_terminal() + } +} + +pub trait AsLockedWrite: private::Sealed { + type Write<'w>: RawStream + 'w + where + Self: 'w; + + fn as_locked_write(&mut self) -> Self::Write<'_>; +} + +impl AsLockedWrite for std::io::Stdout { + type Write<'w> = std::io::StdoutLock<'w>; + + #[inline] + fn as_locked_write(&mut self) -> Self::Write<'_> { + self.lock() + } +} + +impl AsLockedWrite for std::io::StdoutLock<'static> { + type Write<'w> = &'w mut Self; + + #[inline] + fn as_locked_write(&mut self) -> Self::Write<'_> { + self + } +} + +impl AsLockedWrite for std::io::Stderr { + type Write<'w> = std::io::StderrLock<'w>; + + #[inline] + fn as_locked_write(&mut self) -> Self::Write<'_> { + self.lock() + } +} + +impl AsLockedWrite for std::io::StderrLock<'static> { + type Write<'w> = &'w mut Self; + + #[inline] + fn as_locked_write(&mut self) -> Self::Write<'_> { + self + } +} + +impl AsLockedWrite for Box<dyn std::io::Write> { + type Write<'w> = &'w mut Self; + + #[inline] + fn as_locked_write(&mut self) -> Self::Write<'_> { + self + } +} + +impl AsLockedWrite for Vec<u8> { + type Write<'w> = &'w mut Self; + + #[inline] + fn as_locked_write(&mut self) -> Self::Write<'_> { + self + } +} + +impl AsLockedWrite for std::fs::File { + type Write<'w> = &'w mut Self; + + #[inline] + fn as_locked_write(&mut self) -> Self::Write<'_> { + self + } +} + +#[allow(deprecated)] +impl AsLockedWrite for crate::Buffer { + type Write<'w> = &'w mut Self; + + #[inline] + fn as_locked_write(&mut self) -> Self::Write<'_> { + self + } +} + +mod private { + pub trait Sealed {} + + impl Sealed for std::io::Stdout {} + + impl Sealed for std::io::StdoutLock<'_> {} + + impl Sealed for &'_ mut std::io::StdoutLock<'_> {} + + impl Sealed for std::io::Stderr {} + + impl Sealed for std::io::StderrLock<'_> {} + + impl Sealed for &'_ mut std::io::StderrLock<'_> {} + + impl Sealed for Box<dyn std::io::Write> {} + + impl Sealed for &'_ mut Box<dyn std::io::Write> {} + + impl Sealed for Vec<u8> {} + + impl Sealed for &'_ mut Vec<u8> {} + + impl Sealed for std::fs::File {} + + impl Sealed for &'_ mut std::fs::File {} + + #[allow(deprecated)] + impl Sealed for crate::Buffer {} + + #[allow(deprecated)] + impl Sealed for &'_ mut crate::Buffer {} +} diff --git a/vendor/anstream/src/strip.rs b/vendor/anstream/src/strip.rs index 0dd017497..d7fda04a7 100644 --- a/vendor/anstream/src/strip.rs +++ b/vendor/anstream/src/strip.rs @@ -1,10 +1,13 @@ use crate::adapter::StripBytes; -use crate::Lockable; -use crate::RawStream; +use crate::stream::AsLockedWrite; +use crate::stream::RawStream; /// Only pass printable data to the inner `Write` #[derive(Debug)] -pub struct StripStream<S> { +pub struct StripStream<S> +where + S: RawStream, +{ raw: S, state: StripBytes, } @@ -29,47 +32,73 @@ where } #[inline] - #[cfg(feature = "auto")] pub fn is_terminal(&self) -> bool { self.raw.is_terminal() } } -#[cfg(feature = "auto")] -impl<S> is_terminal::IsTerminal for StripStream<S> -where - S: RawStream, -{ +impl StripStream<std::io::Stdout> { + /// Get exclusive access to the `StripStream` + /// + /// Why? + /// - Faster performance when writing in a loop + /// - Avoid other threads interleaving output with the current thread + #[inline] + pub fn lock(self) -> StripStream<std::io::StdoutLock<'static>> { + StripStream { + raw: self.raw.lock(), + state: self.state, + } + } +} + +impl StripStream<std::io::Stderr> { + /// Get exclusive access to the `StripStream` + /// + /// Why? + /// - Faster performance when writing in a loop + /// - Avoid other threads interleaving output with the current thread #[inline] - fn is_terminal(&self) -> bool { - self.is_terminal() + pub fn lock(self) -> StripStream<std::io::StderrLock<'static>> { + StripStream { + raw: self.raw.lock(), + state: self.state, + } } } impl<S> std::io::Write for StripStream<S> where - S: RawStream, + S: RawStream + AsLockedWrite, { + // Must forward all calls to ensure locking happens appropriately #[inline] fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { - write(&mut self.raw, &mut self.state, buf) + write(&mut self.raw.as_locked_write(), &mut self.state, buf) } - + #[inline] + fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result<usize> { + let buf = bufs + .iter() + .find(|b| !b.is_empty()) + .map(|b| &**b) + .unwrap_or(&[][..]); + self.write(buf) + } + // is_write_vectored: nightly only #[inline] fn flush(&mut self) -> std::io::Result<()> { - self.raw.flush() + self.raw.as_locked_write().flush() } - - // Provide explicit implementations of trait methods - // - To reduce bookkeeping - // - Avoid acquiring / releasing locks in a loop - #[inline] fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> { - write_all(&mut self.raw, &mut self.state, buf) + write_all(&mut self.raw.as_locked_write(), &mut self.state, buf) + } + // write_all_vectored: nightly only + #[inline] + fn write_fmt(&mut self, args: std::fmt::Arguments<'_>) -> std::io::Result<()> { + write_fmt(&mut self.raw.as_locked_write(), &mut self.state, args) } - - // Not bothering with `write_fmt` as it just calls `write_all` } fn write( @@ -105,6 +134,15 @@ fn write_all( Ok(()) } +fn write_fmt( + raw: &mut dyn std::io::Write, + state: &mut StripBytes, + args: std::fmt::Arguments<'_>, +) -> std::io::Result<()> { + let write_all = |buf: &[u8]| write_all(raw, state, buf); + crate::fmt::Adapter::new(write_all).write_fmt(args) +} + #[inline] fn offset_to(total: &[u8], subslice: &[u8]) -> usize { let total = total.as_ptr(); @@ -117,21 +155,6 @@ fn offset_to(total: &[u8], subslice: &[u8]) -> usize { subslice as usize - total as usize } -impl<S> Lockable for StripStream<S> -where - S: Lockable, -{ - type Locked = StripStream<<S as Lockable>::Locked>; - - #[inline] - fn lock(self) -> Self::Locked { - Self::Locked { - raw: self.raw.lock(), - state: self.state, - } - } -} - #[cfg(test)] mod test { use super::*; @@ -142,7 +165,7 @@ mod test { #[test] #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 fn write_all_no_escapes(s in "\\PC*") { - let buffer = crate::Buffer::new(); + let buffer = Vec::new(); let mut stream = StripStream::new(buffer); stream.write_all(s.as_bytes()).unwrap(); let buffer = stream.into_inner(); @@ -153,7 +176,7 @@ mod test { #[test] #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 fn write_byte_no_escapes(s in "\\PC*") { - let buffer = crate::Buffer::new(); + let buffer = Vec::new(); let mut stream = StripStream::new(buffer); for byte in s.as_bytes() { stream.write_all(&[*byte]).unwrap(); @@ -166,7 +189,7 @@ mod test { #[test] #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 fn write_all_random(s in any::<Vec<u8>>()) { - let buffer = crate::Buffer::new(); + let buffer = Vec::new(); let mut stream = StripStream::new(buffer); stream.write_all(s.as_slice()).unwrap(); let buffer = stream.into_inner(); @@ -180,7 +203,7 @@ mod test { #[test] #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 fn write_byte_random(s in any::<Vec<u8>>()) { - let buffer = crate::Buffer::new(); + let buffer = Vec::new(); let mut stream = StripStream::new(buffer); for byte in s.as_slice() { stream.write_all(&[*byte]).unwrap(); diff --git a/vendor/anstream/src/wincon.rs b/vendor/anstream/src/wincon.rs index 6627bbb59..a5aa5e747 100644 --- a/vendor/anstream/src/wincon.rs +++ b/vendor/anstream/src/wincon.rs @@ -1,6 +1,6 @@ use crate::adapter::WinconBytes; -use crate::Lockable; -use crate::RawStream; +use crate::stream::AsLockedWrite; +use crate::stream::RawStream; /// Only pass printable data to the inner `Write` #[cfg(feature = "wincon")] // here mostly for documentation purposes @@ -9,7 +9,7 @@ pub struct WinconStream<S> where S: RawStream, { - console: anstyle_wincon::Console<S>, + raw: S, // `WinconBytes` is especially large compared to other variants of `AutoStream`, so boxing it // here so `AutoStream` doesn't have to discard one allocation and create another one when // calling `AutoStream::lock` @@ -22,76 +22,132 @@ where { /// Only pass printable data to the inner `Write` #[inline] - pub fn new(console: anstyle_wincon::Console<S>) -> Self { + pub fn new(raw: S) -> Self { Self { - console, - state: Box::default(), + raw, + state: Default::default(), } } /// Get the wrapped [`RawStream`] #[inline] - pub fn into_inner(self) -> anstyle_wincon::Console<S> { - self.console + pub fn into_inner(self) -> S { + self.raw } #[inline] - #[cfg(feature = "auto")] pub fn is_terminal(&self) -> bool { - // HACK: We can't get the console's stream to check but if there is a console, it likely is - // a terminal - true + self.raw.is_terminal() } } -#[cfg(feature = "auto")] -impl<S> is_terminal::IsTerminal for WinconStream<S> -where - S: RawStream, -{ +impl WinconStream<std::io::Stdout> { + /// Get exclusive access to the `WinconStream` + /// + /// Why? + /// - Faster performance when writing in a loop + /// - Avoid other threads interleaving output with the current thread + #[inline] + pub fn lock(self) -> WinconStream<std::io::StdoutLock<'static>> { + WinconStream { + raw: self.raw.lock(), + state: self.state, + } + } +} + +impl WinconStream<std::io::Stderr> { + /// Get exclusive access to the `WinconStream` + /// + /// Why? + /// - Faster performance when writing in a loop + /// - Avoid other threads interleaving output with the current thread #[inline] - fn is_terminal(&self) -> bool { - self.is_terminal() + pub fn lock(self) -> WinconStream<std::io::StderrLock<'static>> { + WinconStream { + raw: self.raw.lock(), + state: self.state, + } } } impl<S> std::io::Write for WinconStream<S> where - S: RawStream, + S: RawStream + AsLockedWrite, { + // Must forward all calls to ensure locking happens appropriately + #[inline] fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { - for (style, printable) in self.state.extract_next(buf) { - let fg = style.get_fg_color().and_then(cap_wincon_color); - let bg = style.get_bg_color().and_then(cap_wincon_color); - let written = self.console.write(fg, bg, printable.as_bytes())?; - let possible = printable.len(); - if possible != written { - // HACK: Unsupported atm - break; - } - } - Ok(buf.len()) + write(&mut self.raw.as_locked_write(), &mut self.state, buf) } #[inline] + fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result<usize> { + let buf = bufs + .iter() + .find(|b| !b.is_empty()) + .map(|b| &**b) + .unwrap_or(&[][..]); + self.write(buf) + } + // is_write_vectored: nightly only + #[inline] fn flush(&mut self) -> std::io::Result<()> { - self.console.flush() + self.raw.as_locked_write().flush() + } + #[inline] + fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> { + write_all(&mut self.raw.as_locked_write(), &mut self.state, buf) + } + // write_all_vectored: nightly only + #[inline] + fn write_fmt(&mut self, args: std::fmt::Arguments<'_>) -> std::io::Result<()> { + write_fmt(&mut self.raw.as_locked_write(), &mut self.state, args) } } -impl<S> Lockable for WinconStream<S> -where - S: RawStream + Lockable, - <S as Lockable>::Locked: RawStream, -{ - type Locked = WinconStream<<S as Lockable>::Locked>; +fn write(raw: &mut dyn RawStream, state: &mut WinconBytes, buf: &[u8]) -> std::io::Result<usize> { + for (style, printable) in state.extract_next(buf) { + let fg = style.get_fg_color().and_then(cap_wincon_color); + let bg = style.get_bg_color().and_then(cap_wincon_color); + let written = raw.write_colored(fg, bg, printable.as_bytes())?; + let possible = printable.len(); + if possible != written { + // HACK: Unsupported atm + break; + } + } + Ok(buf.len()) +} - #[inline] - fn lock(self) -> Self::Locked { - Self::Locked { - console: self.console.lock(), - state: self.state, +fn write_all(raw: &mut dyn RawStream, state: &mut WinconBytes, buf: &[u8]) -> std::io::Result<()> { + for (style, printable) in state.extract_next(buf) { + let mut buf = printable.as_bytes(); + let fg = style.get_fg_color().and_then(cap_wincon_color); + let bg = style.get_bg_color().and_then(cap_wincon_color); + while !buf.is_empty() { + match raw.write_colored(fg, bg, buf) { + Ok(0) => { + return Err(std::io::Error::new( + std::io::ErrorKind::WriteZero, + "failed to write whole buffer", + )); + } + Ok(n) => buf = &buf[n..], + Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } } } + Ok(()) +} + +fn write_fmt( + raw: &mut dyn RawStream, + state: &mut WinconBytes, + args: std::fmt::Arguments<'_>, +) -> std::io::Result<()> { + let write_all = |buf: &[u8]| write_all(raw, state, buf); + crate::fmt::Adapter::new(write_all).write_fmt(args) } fn cap_wincon_color(color: anstyle::Color) -> Option<anstyle::AnsiColor> { @@ -112,10 +168,10 @@ mod test { #[test] #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 fn write_all_no_escapes(s in "\\PC*") { - let buffer = crate::Buffer::new(); - let mut stream = WinconStream::new(anstyle_wincon::Console::new(buffer).unwrap()); + let buffer = Vec::new(); + let mut stream = WinconStream::new(buffer); stream.write_all(s.as_bytes()).unwrap(); - let buffer = stream.into_inner().into_inner(); + let buffer = stream.into_inner(); let actual = std::str::from_utf8(buffer.as_ref()).unwrap(); assert_eq!(s, actual); } @@ -123,12 +179,12 @@ mod test { #[test] #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 fn write_byte_no_escapes(s in "\\PC*") { - let buffer = crate::Buffer::new(); - let mut stream = WinconStream::new(anstyle_wincon::Console::new(buffer).unwrap()); + let buffer = Vec::new(); + let mut stream = WinconStream::new(buffer); for byte in s.as_bytes() { stream.write_all(&[*byte]).unwrap(); } - let buffer = stream.into_inner().into_inner(); + let buffer = stream.into_inner(); let actual = std::str::from_utf8(buffer.as_ref()).unwrap(); assert_eq!(s, actual); } @@ -136,16 +192,16 @@ mod test { #[test] #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 fn write_all_random(s in any::<Vec<u8>>()) { - let buffer = crate::Buffer::new(); - let mut stream = WinconStream::new(anstyle_wincon::Console::new(buffer).unwrap()); + let buffer = Vec::new(); + let mut stream = WinconStream::new(buffer); stream.write_all(s.as_slice()).unwrap(); } #[test] #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 fn write_byte_random(s in any::<Vec<u8>>()) { - let buffer = crate::Buffer::new(); - let mut stream = WinconStream::new(anstyle_wincon::Console::new(buffer).unwrap()); + let buffer = Vec::new(); + let mut stream = WinconStream::new(buffer); for byte in s.as_slice() { stream.write_all(&[*byte]).unwrap(); } |