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/src/wincon.rs | |
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/src/wincon.rs')
-rw-r--r-- | vendor/anstream/src/wincon.rs | 162 |
1 files changed, 109 insertions, 53 deletions
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(); } |