]> git.proxmox.com Git - rustc.git/blob - vendor/anstream/src/wincon.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / vendor / anstream / src / wincon.rs
1 use crate::adapter::WinconBytes;
2 use crate::Lockable;
3 use crate::RawStream;
4
5 /// Only pass printable data to the inner `Write`
6 #[cfg(feature = "wincon")] // here mostly for documentation purposes
7 #[derive(Debug)]
8 pub struct WinconStream<S>
9 where
10 S: RawStream,
11 {
12 console: anstyle_wincon::Console<S>,
13 // `WinconBytes` is especially large compared to other variants of `AutoStream`, so boxing it
14 // here so `AutoStream` doesn't have to discard one allocation and create another one when
15 // calling `AutoStream::lock`
16 state: Box<WinconBytes>,
17 }
18
19 impl<S> WinconStream<S>
20 where
21 S: RawStream,
22 {
23 /// Only pass printable data to the inner `Write`
24 #[inline]
25 pub fn new(console: anstyle_wincon::Console<S>) -> Self {
26 Self {
27 console,
28 state: Box::default(),
29 }
30 }
31
32 /// Get the wrapped [`RawStream`]
33 #[inline]
34 pub fn into_inner(self) -> anstyle_wincon::Console<S> {
35 self.console
36 }
37
38 #[inline]
39 #[cfg(feature = "auto")]
40 pub fn is_terminal(&self) -> bool {
41 // HACK: We can't get the console's stream to check but if there is a console, it likely is
42 // a terminal
43 true
44 }
45 }
46
47 #[cfg(feature = "auto")]
48 impl<S> is_terminal::IsTerminal for WinconStream<S>
49 where
50 S: RawStream,
51 {
52 #[inline]
53 fn is_terminal(&self) -> bool {
54 self.is_terminal()
55 }
56 }
57
58 impl<S> std::io::Write for WinconStream<S>
59 where
60 S: RawStream,
61 {
62 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
63 for (style, printable) in self.state.extract_next(buf) {
64 let fg = style.get_fg_color().and_then(cap_wincon_color);
65 let bg = style.get_bg_color().and_then(cap_wincon_color);
66 let written = self.console.write(fg, bg, printable.as_bytes())?;
67 let possible = printable.len();
68 if possible != written {
69 // HACK: Unsupported atm
70 break;
71 }
72 }
73 Ok(buf.len())
74 }
75 #[inline]
76 fn flush(&mut self) -> std::io::Result<()> {
77 self.console.flush()
78 }
79 }
80
81 impl<S> Lockable for WinconStream<S>
82 where
83 S: RawStream + Lockable,
84 <S as Lockable>::Locked: RawStream,
85 {
86 type Locked = WinconStream<<S as Lockable>::Locked>;
87
88 #[inline]
89 fn lock(self) -> Self::Locked {
90 Self::Locked {
91 console: self.console.lock(),
92 state: self.state,
93 }
94 }
95 }
96
97 fn cap_wincon_color(color: anstyle::Color) -> Option<anstyle::AnsiColor> {
98 match color {
99 anstyle::Color::Ansi(c) => Some(c),
100 anstyle::Color::Ansi256(c) => c.into_ansi(),
101 anstyle::Color::Rgb(_) => None,
102 }
103 }
104
105 #[cfg(test)]
106 mod test {
107 use super::*;
108 use proptest::prelude::*;
109 use std::io::Write as _;
110
111 proptest! {
112 #[test]
113 #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253
114 fn write_all_no_escapes(s in "\\PC*") {
115 let buffer = crate::Buffer::new();
116 let mut stream = WinconStream::new(anstyle_wincon::Console::new(buffer).unwrap());
117 stream.write_all(s.as_bytes()).unwrap();
118 let buffer = stream.into_inner().into_inner();
119 let actual = std::str::from_utf8(buffer.as_ref()).unwrap();
120 assert_eq!(s, actual);
121 }
122
123 #[test]
124 #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253
125 fn write_byte_no_escapes(s in "\\PC*") {
126 let buffer = crate::Buffer::new();
127 let mut stream = WinconStream::new(anstyle_wincon::Console::new(buffer).unwrap());
128 for byte in s.as_bytes() {
129 stream.write_all(&[*byte]).unwrap();
130 }
131 let buffer = stream.into_inner().into_inner();
132 let actual = std::str::from_utf8(buffer.as_ref()).unwrap();
133 assert_eq!(s, actual);
134 }
135
136 #[test]
137 #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253
138 fn write_all_random(s in any::<Vec<u8>>()) {
139 let buffer = crate::Buffer::new();
140 let mut stream = WinconStream::new(anstyle_wincon::Console::new(buffer).unwrap());
141 stream.write_all(s.as_slice()).unwrap();
142 }
143
144 #[test]
145 #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253
146 fn write_byte_random(s in any::<Vec<u8>>()) {
147 let buffer = crate::Buffer::new();
148 let mut stream = WinconStream::new(anstyle_wincon::Console::new(buffer).unwrap());
149 for byte in s.as_slice() {
150 stream.write_all(&[*byte]).unwrap();
151 }
152 }
153 }
154 }