1#![cfg_attr(docsrs, feature(doc_cfg))]
2
3use std::io::{Error, Result, Write};
49
50pub mod fs;
51
52pub trait Close: Write {
54 fn close(self) -> Result<()>;
60}
61
62macro_rules! unix_impl_close_raw_fd {
65 ($ty:ty, "std" $(,$lt:lifetime)* $(,$id:ident)*) => {
66 unix_impl_close_raw_fd!($ty, "unix" $(,$lt)* $(,$id)*);
67 };
68 ($ty:ty, $ft_fm:literal $(,$lt:lifetime)* $(,$id:ident)*) => {
69 #[cfg(unix)]
70 #[cfg(any(feature = $ft_fm, target_family = $ft_fm))]
71 #[cfg_attr(all(docsrs, feature = $ft_fm), doc(cfg(feature = $ft_fm)))]
72 impl<$($lt,)* $($id,)*> Close for $ty {
73 fn close(mut self) -> Result<()> {
75 use std::io::ErrorKind;
76 use std::os::unix::io::IntoRawFd;
77
78 self.flush()?;
79 let fd = self.into_raw_fd();
80 let rv = unsafe { libc::close(fd) };
81 if rv != -1 {
82 Ok(())
83 } else {
84 match Error::last_os_error() {
85 e if e.kind() == ErrorKind::Interrupted => Ok(()),
86 e => Err(e),
87 }
88 }
89 }
90 }
91 };
92}
93
94macro_rules! windows_impl_close_raw_handle {
95 ($ty:ty, "std" $(,$lt:lifetime)* $(,$id:ident)*) => {
96 windows_impl_close_raw_handle!($ty, "windows" $(,$lt)* $(,$id)*);
97 };
98 ($ty:ty, $ft_fm:literal $(,$lt:lifetime)* $(,$id:ident)*) => {
99 #[cfg(windows)]
100 #[cfg(any(feature = $ft_fm, target_family = $ft_fm))]
101 #[cfg_attr(all(docsrs, feature = $ft_fm), doc(cfg(feature = $ft_fm)))]
102 impl<$($lt,)* $($id,)*> Close for $ty {
103 fn close(mut self) -> Result<()> {
105 use std::os::windows::io::IntoRawHandle;
106 use winapi::um::handleapi;
107
108 self.flush()?;
109 let handle = self.into_raw_handle();
110 let rv = unsafe { handleapi::CloseHandle(handle) };
111 if rv != 0 {
112 Ok(())
113 } else {
114 Err(Error::last_os_error())
115 }
116 }
117 }
118 };
119}
120
121macro_rules! windows_impl_close_raw_socket {
122 ($ty:ty, "std" $(,$lt:lifetime)* $(,$id:ident)*) => {
123 windows_impl_close_raw_socket!($ty, "windows" $(,$lt)* $(,$id)*);
124 };
125 ($ty:ty, $ft_fm:literal $(,$lt:lifetime)* $(,$id:ident)*) => {
126 #[cfg(windows)]
127 #[cfg(any(feature = $ft_fm, target_family = $ft_fm))]
128 #[cfg_attr(all(docsrs, feature = $ft_fm), doc(cfg(feature = $ft_fm)))]
129 impl<$($lt,)* $($id,)*> Close for $ty {
130 fn close(mut self) -> Result<()> {
132 use std::convert::TryInto;
133 use std::os::windows::io::IntoRawSocket;
134 use winapi::um::winsock2;
135
136 self.flush()?;
137 let socket = self.into_raw_socket().try_into().unwrap();
138 let rv = unsafe { winsock2::closesocket(socket) };
139 if rv == 0 {
140 Ok(())
141 } else {
142 Err(Error::from_raw_os_error(unsafe {
143 winsock2::WSAGetLastError()
144 }))
145 }
146 }
147 }
148 };
149}
150
151macro_rules! impl_close_no_error_no_flush {
152 ($ty:ty, "std" $(,$lt:lifetime)* $(,$id:ident)*) => {
153 #[cfg(unix)]
154 impl_close_no_error_no_flush!($ty, "unix" $(,$lt)* $(,$id)*);
155 #[cfg(windows)]
156 impl_close_no_error_no_flush!($ty, "windows" $(,$lt)* $(,$id)*);
157 };
158 ($ty:ty, $ft_fm:literal $(,$lt:lifetime)* $(,$id:ident)*) => {
159 #[cfg(any(unix, windows))]
160 #[cfg(any(feature = $ft_fm, target_family = $ft_fm))]
161 #[cfg_attr(all(docsrs, feature = $ft_fm), doc(cfg(feature = $ft_fm)))]
162 impl<$($lt,)* $($id,)*> Close for $ty {
163 #[inline]
166 fn close(self) -> Result<()> {
167 Ok(())
168 }
169 }
170 };
171}
172
173macro_rules! impl_close_into_inner {
174 ($ty:ty, "std" $(,$lt:lifetime)* $(,$id:ident)*) => {
175 #[cfg(unix)]
176 impl_close_into_inner!($ty, "unix" $(,$lt)* $(,$id)*);
177 #[cfg(windows)]
178 impl_close_into_inner!($ty, "windows" $(,$lt)* $(,$id)*);
179 };
180 ($ty:ty, $ft_fm:literal $(,$lt:lifetime)* $(,$id:ident)*) => {
181 #[cfg(any(unix, windows))]
182 #[cfg(any(feature = $ft_fm, target_family = $ft_fm))]
183 #[cfg_attr(all(docsrs, feature = $ft_fm), doc(cfg(feature = $ft_fm)))]
184 impl<$($lt,)* W: Close, $($id,)*> Close for $ty {
185 fn close(self) -> Result<()> {
188 self.into_inner()?.close()
189 }
190 }
191 };
192}
193
194unix_impl_close_raw_fd!(std::fs::File, "std");
207unix_impl_close_raw_fd!(std::net::TcpStream, "std");
208unix_impl_close_raw_fd!(std::os::unix::net::UnixStream, "std");
209unix_impl_close_raw_fd!(std::process::ChildStdin, "std");
210unix_impl_close_raw_fd!(os_pipe::PipeWriter, "os_pipe");
211
212windows_impl_close_raw_handle!(std::fs::File, "std");
213windows_impl_close_raw_socket!(std::net::TcpStream, "std");
214windows_impl_close_raw_handle!(std::process::ChildStdin, "std");
215windows_impl_close_raw_handle!(os_pipe::PipeWriter, "os_pipe");
216
217impl_close_no_error_no_flush!(&mut [u8], "std");
218impl_close_no_error_no_flush!(std::io::Cursor<&mut Vec<u8>>, "std");
219impl_close_no_error_no_flush!(std::io::Cursor<&mut [u8]>, "std");
220impl_close_no_error_no_flush!(std::io::Cursor<Box<[u8]>>, "std");
221impl_close_no_error_no_flush!(std::io::Cursor<Vec<u8>>, "std");
222impl_close_no_error_no_flush!(std::io::Sink, "std");
223impl_close_no_error_no_flush!(Vec<u8>, "std");
224
225impl_close_into_inner!(std::io::BufWriter<W>, "std");
226impl_close_into_inner!(std::io::LineWriter<W>, "std");