anstream/
stream.rs

1//! Higher-level traits to describe writeable streams
2
3/// Required functionality for underlying [`std::io::Write`] for adaptation
4#[cfg(not(all(windows, feature = "wincon")))]
5pub trait RawStream: std::io::Write + IsTerminal + private::Sealed {}
6
7/// Required functionality for underlying [`std::io::Write`] for adaptation
8#[cfg(all(windows, feature = "wincon"))]
9pub trait RawStream:
10    std::io::Write + IsTerminal + anstyle_wincon::WinconStream + private::Sealed
11{
12}
13
14impl<T: RawStream + ?Sized> RawStream for &mut T {}
15impl<T: RawStream + ?Sized> RawStream for Box<T> {}
16
17impl RawStream for std::io::Stdout {}
18
19impl RawStream for std::io::StdoutLock<'_> {}
20
21impl RawStream for std::io::Stderr {}
22
23impl RawStream for std::io::StderrLock<'_> {}
24
25impl RawStream for dyn std::io::Write {}
26impl RawStream for dyn std::io::Write + Send {}
27impl RawStream for dyn std::io::Write + Send + Sync {}
28
29impl RawStream for Vec<u8> {}
30
31impl RawStream for std::fs::File {}
32
33#[allow(deprecated)]
34impl RawStream for crate::Buffer {}
35
36/// Trait to determine if a descriptor/handle refers to a terminal/tty.
37pub trait IsTerminal: private::Sealed {
38    /// Returns `true` if the descriptor/handle refers to a terminal/tty.
39    fn is_terminal(&self) -> bool;
40}
41
42impl<T: IsTerminal + ?Sized> IsTerminal for &T {
43    #[inline]
44    fn is_terminal(&self) -> bool {
45        (**self).is_terminal()
46    }
47}
48
49impl<T: IsTerminal + ?Sized> IsTerminal for &mut T {
50    #[inline]
51    fn is_terminal(&self) -> bool {
52        (**self).is_terminal()
53    }
54}
55
56impl<T: IsTerminal + ?Sized> IsTerminal for Box<T> {
57    #[inline]
58    fn is_terminal(&self) -> bool {
59        (**self).is_terminal()
60    }
61}
62
63impl IsTerminal for std::io::Stdout {
64    #[inline]
65    fn is_terminal(&self) -> bool {
66        is_terminal_polyfill::IsTerminal::is_terminal(self)
67    }
68}
69
70impl IsTerminal for std::io::StdoutLock<'_> {
71    #[inline]
72    fn is_terminal(&self) -> bool {
73        is_terminal_polyfill::IsTerminal::is_terminal(self)
74    }
75}
76
77impl IsTerminal for std::io::Stderr {
78    #[inline]
79    fn is_terminal(&self) -> bool {
80        is_terminal_polyfill::IsTerminal::is_terminal(self)
81    }
82}
83
84impl IsTerminal for std::io::StderrLock<'_> {
85    #[inline]
86    fn is_terminal(&self) -> bool {
87        is_terminal_polyfill::IsTerminal::is_terminal(self)
88    }
89}
90
91impl IsTerminal for dyn std::io::Write {
92    #[inline]
93    fn is_terminal(&self) -> bool {
94        false
95    }
96}
97
98impl IsTerminal for dyn std::io::Write + Send {
99    #[inline]
100    fn is_terminal(&self) -> bool {
101        false
102    }
103}
104
105impl IsTerminal for dyn std::io::Write + Send + Sync {
106    #[inline]
107    fn is_terminal(&self) -> bool {
108        false
109    }
110}
111
112impl IsTerminal for Vec<u8> {
113    #[inline]
114    fn is_terminal(&self) -> bool {
115        false
116    }
117}
118
119impl IsTerminal for std::fs::File {
120    #[inline]
121    fn is_terminal(&self) -> bool {
122        is_terminal_polyfill::IsTerminal::is_terminal(self)
123    }
124}
125
126#[allow(deprecated)]
127impl IsTerminal for crate::Buffer {
128    #[inline]
129    fn is_terminal(&self) -> bool {
130        false
131    }
132}
133
134/// Lock a stream
135pub trait AsLockedWrite: private::Sealed {
136    /// Locked writer type
137    type Write<'w>: RawStream + 'w
138    where
139        Self: 'w;
140
141    /// Lock a stream
142    fn as_locked_write(&mut self) -> Self::Write<'_>;
143}
144
145impl<T: AsLockedWrite + ?Sized> AsLockedWrite for &mut T {
146    type Write<'w>
147        = T::Write<'w>
148    where
149        Self: 'w;
150
151    #[inline]
152    fn as_locked_write(&mut self) -> Self::Write<'_> {
153        (**self).as_locked_write()
154    }
155}
156
157impl<T: AsLockedWrite + ?Sized> AsLockedWrite for Box<T> {
158    type Write<'w>
159        = T::Write<'w>
160    where
161        Self: 'w;
162
163    #[inline]
164    fn as_locked_write(&mut self) -> Self::Write<'_> {
165        (**self).as_locked_write()
166    }
167}
168
169impl AsLockedWrite for std::io::Stdout {
170    type Write<'w> = std::io::StdoutLock<'w>;
171
172    #[inline]
173    fn as_locked_write(&mut self) -> Self::Write<'_> {
174        self.lock()
175    }
176}
177
178impl AsLockedWrite for std::io::StdoutLock<'static> {
179    type Write<'w> = &'w mut Self;
180
181    #[inline]
182    fn as_locked_write(&mut self) -> Self::Write<'_> {
183        self
184    }
185}
186
187impl AsLockedWrite for std::io::Stderr {
188    type Write<'w> = std::io::StderrLock<'w>;
189
190    #[inline]
191    fn as_locked_write(&mut self) -> Self::Write<'_> {
192        self.lock()
193    }
194}
195
196impl AsLockedWrite for std::io::StderrLock<'static> {
197    type Write<'w> = &'w mut Self;
198
199    #[inline]
200    fn as_locked_write(&mut self) -> Self::Write<'_> {
201        self
202    }
203}
204
205impl AsLockedWrite for dyn std::io::Write {
206    type Write<'w> = &'w mut Self;
207
208    #[inline]
209    fn as_locked_write(&mut self) -> Self::Write<'_> {
210        self
211    }
212}
213
214impl AsLockedWrite for dyn std::io::Write + Send {
215    type Write<'w> = &'w mut Self;
216
217    #[inline]
218    fn as_locked_write(&mut self) -> Self::Write<'_> {
219        self
220    }
221}
222
223impl AsLockedWrite for dyn std::io::Write + Send + Sync {
224    type Write<'w> = &'w mut Self;
225
226    #[inline]
227    fn as_locked_write(&mut self) -> Self::Write<'_> {
228        self
229    }
230}
231
232impl AsLockedWrite for Vec<u8> {
233    type Write<'w> = &'w mut Self;
234
235    #[inline]
236    fn as_locked_write(&mut self) -> Self::Write<'_> {
237        self
238    }
239}
240
241impl AsLockedWrite for std::fs::File {
242    type Write<'w> = &'w mut Self;
243
244    #[inline]
245    fn as_locked_write(&mut self) -> Self::Write<'_> {
246        self
247    }
248}
249
250#[allow(deprecated)]
251impl AsLockedWrite for crate::Buffer {
252    type Write<'w> = &'w mut Self;
253
254    #[inline]
255    fn as_locked_write(&mut self) -> Self::Write<'_> {
256        self
257    }
258}
259
260mod private {
261    pub trait Sealed {}
262
263    impl<T: Sealed + ?Sized> Sealed for &T {}
264    impl<T: Sealed + ?Sized> Sealed for &mut T {}
265    impl<T: Sealed + ?Sized> Sealed for Box<T> {}
266
267    impl Sealed for std::io::Stdout {}
268
269    impl Sealed for std::io::StdoutLock<'_> {}
270
271    impl Sealed for std::io::Stderr {}
272
273    impl Sealed for std::io::StderrLock<'_> {}
274
275    impl Sealed for dyn std::io::Write {}
276    impl Sealed for dyn std::io::Write + Send {}
277    impl Sealed for dyn std::io::Write + Send + Sync {}
278
279    impl Sealed for Vec<u8> {}
280
281    impl Sealed for std::fs::File {}
282
283    #[allow(deprecated)]
284    impl Sealed for crate::Buffer {}
285}
286
287#[cfg(test)]
288mod tests {
289    use super::*;
290
291    fn assert_raw_stream<T: RawStream>()
292    where
293        crate::AutoStream<T>: std::io::Write,
294    {
295    }
296
297    #[test]
298    fn test() {
299        assert_raw_stream::<Box<dyn std::io::Write>>();
300        assert_raw_stream::<Box<dyn std::io::Write + 'static>>();
301        assert_raw_stream::<Box<dyn std::io::Write + Send>>();
302        assert_raw_stream::<Box<dyn std::io::Write + Send + Sync>>();
303
304        assert_raw_stream::<&mut (dyn std::io::Write)>();
305        assert_raw_stream::<&mut (dyn std::io::Write + 'static)>();
306        assert_raw_stream::<&mut (dyn std::io::Write + Send)>();
307        assert_raw_stream::<&mut (dyn std::io::Write + Send + Sync)>();
308
309        assert_raw_stream::<Vec<u8>>();
310        assert_raw_stream::<&mut Vec<u8>>();
311
312        assert_raw_stream::<std::fs::File>();
313        assert_raw_stream::<&mut std::fs::File>();
314    }
315}