layered_io/
layered_writer.rs

1use crate::{Bufferable, WriteLayered};
2#[cfg(windows)]
3use io_extras::os::windows::{
4    AsHandleOrSocket, AsRawHandleOrSocket, BorrowedHandleOrSocket, RawHandleOrSocket,
5};
6use std::fmt::{self, Arguments};
7use std::io::{self, IoSlice, Write};
8#[cfg(not(windows))]
9use {
10    io_extras::os::rustix::{AsRawFd, RawFd},
11    std::os::fd::{AsFd, BorrowedFd},
12};
13
14/// Adapts a [`std::io::Write`] to implement [`WriteLayered`].
15pub struct LayeredWriter<Inner> {
16    inner: Option<Inner>,
17}
18
19impl<Inner: Write> LayeredWriter<Inner> {
20    /// Construct a new `LayeredWriter` which wraps `inner`.
21    pub fn new(inner: Inner) -> Self {
22        Self { inner: Some(inner) }
23    }
24
25    /// Gets a reference to the underlying writer.
26    pub fn get_ref(&self) -> &Inner {
27        self.inner
28            .as_ref()
29            .expect("get_ref() called on closed LayeredWriter")
30    }
31
32    /// Gets a mutable reference to the underlying writer.
33    ///
34    /// It is inadvisable to directly write to the underlying writer.
35    pub fn get_mut(&mut self) -> &mut Inner {
36        self.inner
37            .as_mut()
38            .expect("get_mut() called on closed LayeredWriter")
39    }
40
41    /// Close this `LayeredWriter` and return the inner stream.
42    pub fn close_into_inner(mut self) -> io::Result<Inner> {
43        match &mut self.inner {
44            Some(_) => {
45                let mut inner = self.inner.take().unwrap();
46                inner.flush()?;
47                Ok(inner)
48            }
49            None => Err(stream_already_ended()),
50        }
51    }
52
53    /// Consume this `LayeredWriter` and return the inner stream.
54    pub fn abandon_into_inner(mut self) -> Option<Inner> {
55        self.inner.take()
56    }
57}
58
59impl<Inner: Write> WriteLayered for LayeredWriter<Inner> {
60    #[inline]
61    fn close(&mut self) -> io::Result<()> {
62        match &mut self.inner {
63            Some(_) => self.inner.take().unwrap().flush(),
64            None => Err(stream_already_ended()),
65        }
66    }
67}
68
69impl<Inner> Bufferable for LayeredWriter<Inner> {
70    #[inline]
71    fn abandon(&mut self) {
72        self.inner = None;
73    }
74}
75
76impl<Inner: Write> Write for LayeredWriter<Inner> {
77    #[inline]
78    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
79        match &mut self.inner {
80            Some(inner) => inner.write(buf).map_err(|e| {
81                drop(self.inner.take().unwrap());
82                e
83            }),
84            None => Err(stream_already_ended()),
85        }
86    }
87
88    #[inline]
89    fn flush(&mut self) -> io::Result<()> {
90        match &mut self.inner {
91            Some(inner) => inner.flush().map_err(|e| {
92                drop(self.inner.take().unwrap());
93                e
94            }),
95            None => Err(stream_already_ended()),
96        }
97    }
98
99    #[inline]
100    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
101        match &mut self.inner {
102            Some(inner) => inner.write_vectored(bufs).map_err(|e| {
103                drop(self.inner.take().unwrap());
104                e
105            }),
106            None => Err(stream_already_ended()),
107        }
108    }
109
110    #[cfg(can_vector)]
111    #[inline]
112    fn is_write_vectored(&self) -> bool {
113        match &self.inner {
114            Some(inner) => inner.is_write_vectored(),
115            None => false,
116        }
117    }
118
119    #[inline]
120    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
121        match &mut self.inner {
122            Some(inner) => inner.write_all(buf).map_err(|e| {
123                drop(self.inner.take().unwrap());
124                e
125            }),
126            None => Err(stream_already_ended()),
127        }
128    }
129
130    #[cfg(write_all_vectored)]
131    #[inline]
132    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
133        match &mut self.inner {
134            Some(inner) => inner.write_all_vectored(bufs).map_err(|e| {
135                drop(self.inner.take().unwrap());
136                e
137            }),
138            None => Err(stream_already_ended()),
139        }
140    }
141
142    #[inline]
143    fn write_fmt(&mut self, fmt: Arguments<'_>) -> io::Result<()> {
144        match &mut self.inner {
145            Some(inner) => inner.write_fmt(fmt).map_err(|e| {
146                drop(self.inner.take().unwrap());
147                e
148            }),
149            None => Err(stream_already_ended()),
150        }
151    }
152}
153
154#[cfg(feature = "terminal-io")]
155impl<RW: terminal_io::WriteTerminal> terminal_io::Terminal for LayeredWriter<RW> {}
156
157#[cfg(feature = "terminal-io")]
158impl<RW: terminal_io::WriteTerminal> terminal_io::WriteTerminal for LayeredWriter<RW> {
159    #[inline]
160    fn color_support(&self) -> terminal_io::TerminalColorSupport {
161        self.inner.as_ref().unwrap().color_support()
162    }
163
164    #[inline]
165    fn color_preference(&self) -> bool {
166        self.inner.as_ref().unwrap().color_preference()
167    }
168
169    #[inline]
170    fn is_output_terminal(&self) -> bool {
171        self.inner
172            .as_ref()
173            .map(|c| c.is_output_terminal())
174            .unwrap_or(false)
175    }
176}
177
178#[cfg(not(windows))]
179impl<Inner: Write + AsRawFd> AsRawFd for LayeredWriter<Inner> {
180    #[inline]
181    fn as_raw_fd(&self) -> RawFd {
182        match &self.inner {
183            Some(inner) => inner.as_raw_fd(),
184            None => panic!("as_raw_fd() called on closed LayeredWriter"),
185        }
186    }
187}
188
189#[cfg(not(windows))]
190impl<Inner: Write + AsFd> AsFd for LayeredWriter<Inner> {
191    #[inline]
192    fn as_fd(&self) -> BorrowedFd<'_> {
193        match &self.inner {
194            Some(inner) => inner.as_fd(),
195            None => panic!("as_fd() called on closed LayeredWriter"),
196        }
197    }
198}
199
200#[cfg(windows)]
201impl<Inner: Write + AsRawHandleOrSocket> AsRawHandleOrSocket for LayeredWriter<Inner> {
202    #[inline]
203    fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket {
204        match &self.inner {
205            Some(inner) => inner.as_raw_handle_or_socket(),
206            None => panic!("as_raw_handle_or_socket() called on closed LayeredWriter"),
207        }
208    }
209}
210
211#[cfg(windows)]
212impl<Inner: Write + AsHandleOrSocket> AsHandleOrSocket for LayeredWriter<Inner> {
213    #[inline]
214    fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> {
215        match &self.inner {
216            Some(inner) => inner.as_handle_or_socket(),
217            None => panic!("as_handle_or_socket() called on closed LayeredWriter"),
218        }
219    }
220}
221
222impl<Inner: fmt::Debug> fmt::Debug for LayeredWriter<Inner> {
223    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
224        let mut b = f.debug_struct("LayeredWriter");
225        b.field("inner", &self.inner);
226        b.finish()
227    }
228}
229
230fn stream_already_ended() -> io::Error {
231    io::Error::new(io::ErrorKind::BrokenPipe, "stream has already ended")
232}
233
234impl<Inner> Drop for LayeredWriter<Inner> {
235    fn drop(&mut self) {
236        assert!(self.inner.is_none(), "stream was not closed or abandoned");
237    }
238}