From 1b6a04ca5504955c571d1c97504fb45ea0befee4 Mon Sep 17 00:00:00 2001
From: Valentin Popov <valentin@popov.link>
Date: Mon, 8 Jan 2024 01:21:28 +0400
Subject: Initial vendor packages

Signed-off-by: Valentin Popov <valentin@popov.link>
---
 vendor/anstream/src/wincon.rs | 210 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 210 insertions(+)
 create mode 100644 vendor/anstream/src/wincon.rs

(limited to 'vendor/anstream/src/wincon.rs')

diff --git a/vendor/anstream/src/wincon.rs b/vendor/anstream/src/wincon.rs
new file mode 100644
index 0000000..a5aa5e7
--- /dev/null
+++ b/vendor/anstream/src/wincon.rs
@@ -0,0 +1,210 @@
+use crate::adapter::WinconBytes;
+use crate::stream::AsLockedWrite;
+use crate::stream::RawStream;
+
+/// Only pass printable data to the inner `Write`
+#[cfg(feature = "wincon")] // here mostly for documentation purposes
+#[derive(Debug)]
+pub struct WinconStream<S>
+where
+    S: RawStream,
+{
+    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`
+    state: Box<WinconBytes>,
+}
+
+impl<S> WinconStream<S>
+where
+    S: RawStream,
+{
+    /// Only pass printable data to the inner `Write`
+    #[inline]
+    pub fn new(raw: S) -> Self {
+        Self {
+            raw,
+            state: Default::default(),
+        }
+    }
+
+    /// Get the wrapped [`RawStream`]
+    #[inline]
+    pub fn into_inner(self) -> S {
+        self.raw
+    }
+
+    #[inline]
+    pub fn is_terminal(&self) -> bool {
+        self.raw.is_terminal()
+    }
+}
+
+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]
+    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 + 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.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.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)
+    }
+}
+
+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())
+}
+
+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> {
+    match color {
+        anstyle::Color::Ansi(c) => Some(c),
+        anstyle::Color::Ansi256(c) => c.into_ansi(),
+        anstyle::Color::Rgb(_) => None,
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use proptest::prelude::*;
+    use std::io::Write as _;
+
+    proptest! {
+        #[test]
+        #[cfg_attr(miri, ignore)]  // See https://github.com/AltSysrq/proptest/issues/253
+        fn write_all_no_escapes(s in "\\PC*") {
+            let buffer = Vec::new();
+            let mut stream = WinconStream::new(buffer);
+            stream.write_all(s.as_bytes()).unwrap();
+            let buffer = stream.into_inner();
+            let actual = std::str::from_utf8(buffer.as_ref()).unwrap();
+            assert_eq!(s, actual);
+        }
+
+        #[test]
+        #[cfg_attr(miri, ignore)]  // See https://github.com/AltSysrq/proptest/issues/253
+        fn write_byte_no_escapes(s in "\\PC*") {
+            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();
+            let actual = std::str::from_utf8(buffer.as_ref()).unwrap();
+            assert_eq!(s, actual);
+        }
+
+        #[test]
+        #[cfg_attr(miri, ignore)]  // See https://github.com/AltSysrq/proptest/issues/253
+        fn write_all_random(s in any::<Vec<u8>>()) {
+            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 = Vec::new();
+            let mut stream = WinconStream::new(buffer);
+            for byte in s.as_slice() {
+                stream.write_all(&[*byte]).unwrap();
+            }
+        }
+    }
+}
-- 
cgit v1.2.3