system_interface/io/
is_read_write.rs1use std::io;
2#[cfg(not(windows))]
3use {io_lifetimes::AsFilelike, rustix::io::is_read_write};
4#[cfg(windows)]
5use {
6 std::{
7 os::windows::io::{AsRawSocket, RawSocket},
8 ptr,
9 },
10 windows_sys::Win32::Networking::WinSock::{
11 recv, send, MSG_PEEK, SOCKET, SOCKET_ERROR, WSAEFAULT, WSAESHUTDOWN, WSAEWOULDBLOCK,
12 },
13};
14
15pub trait IsReadWrite {
17 fn is_read_write(&self) -> io::Result<(bool, bool)>;
19}
20
21#[cfg(not(windows))]
22impl<T: AsFilelike> IsReadWrite for T {
23 #[inline]
24 fn is_read_write(&self) -> io::Result<(bool, bool)> {
25 Ok(is_read_write(self)?)
26 }
27}
28
29#[cfg(windows)]
30impl IsReadWrite for std::fs::File {
31 #[inline]
32 fn is_read_write(&self) -> io::Result<(bool, bool)> {
33 file_is_read_write(self)
34 }
35}
36
37#[cfg(all(windows, feature = "cap_std_impls"))]
38impl IsReadWrite for cap_std::fs::File {
39 #[inline]
40 fn is_read_write(&self) -> io::Result<(bool, bool)> {
41 use io_lifetimes::AsFilelike;
42 file_is_read_write(&self.as_filelike_view::<std::fs::File>())
43 }
44}
45
46#[cfg(all(windows, feature = "cap_std_impls_fs_utf8"))]
47impl IsReadWrite for cap_std::fs_utf8::File {
48 #[inline]
49 fn is_read_write(&self) -> io::Result<(bool, bool)> {
50 use io_lifetimes::AsFilelike;
51 file_is_read_write(&self.as_filelike_view::<std::fs::File>())
52 }
53}
54
55#[cfg(all(windows, feature = "async-std"))]
56impl IsReadWrite for async_std::fs::File {
57 #[inline]
58 fn is_read_write(&self) -> io::Result<(bool, bool)> {
59 use io_lifetimes::AsFilelike;
60 file_is_read_write(&self.as_filelike_view::<std::fs::File>())
61 }
62}
63
64#[cfg(all(windows, feature = "async-std"))]
65impl IsReadWrite for cap_async_std::fs::File {
66 #[inline]
67 fn is_read_write(&self) -> io::Result<(bool, bool)> {
68 use io_lifetimes::AsFilelike;
69 file_is_read_write(&self.as_filelike_view::<std::fs::File>())
70 }
71}
72
73#[cfg(all(
74 windows,
75 feature = "async-std",
76 feature = "cap_async_std_impls_fs_utf8"
77))]
78impl IsReadWrite for cap_async_std::fs_utf8::File {
79 #[inline]
80 fn is_read_write(&self) -> io::Result<(bool, bool)> {
81 use io_lifetimes::AsFilelike;
82 file_is_read_write(&self.as_filelike_view::<std::fs::File>())
83 }
84}
85
86#[cfg(windows)]
87impl IsReadWrite for std::net::TcpStream {
88 #[inline]
89 fn is_read_write(&self) -> io::Result<(bool, bool)> {
90 raw_socket_is_read_write(self.as_raw_socket())
91 }
92}
93
94#[cfg(all(windows, feature = "cap_std_impls"))]
95impl IsReadWrite for cap_std::net::TcpStream {
96 #[inline]
97 fn is_read_write(&self) -> io::Result<(bool, bool)> {
98 raw_socket_is_read_write(self.as_raw_socket())
99 }
100}
101
102#[cfg(all(windows, feature = "cap_async_std_impls"))]
103impl IsReadWrite for async_std::net::TcpStream {
104 #[inline]
105 fn is_read_write(&self) -> io::Result<(bool, bool)> {
106 raw_socket_is_read_write(self.as_raw_socket())
107 }
108}
109
110#[cfg(all(windows, feature = "cap_async_std_impls"))]
111impl IsReadWrite for cap_async_std::net::TcpStream {
112 #[inline]
113 fn is_read_write(&self) -> io::Result<(bool, bool)> {
114 raw_socket_is_read_write(self.as_raw_socket())
115 }
116}
117
118#[cfg(windows)]
119#[inline]
120fn file_is_read_write(file: &std::fs::File) -> std::io::Result<(bool, bool)> {
121 cap_fs_ext::IsFileReadWrite::is_file_read_write(file)
122}
123
124#[cfg(windows)]
125fn raw_socket_is_read_write(raw_socket: RawSocket) -> io::Result<(bool, bool)> {
126 let (mut read, mut write) = (true, true);
127
128 let socket = raw_socket as SOCKET;
131 let write_result = unsafe { send(socket, ptr::null_mut(), 0, 0) };
132 if write_result == SOCKET_ERROR {
133 let err = io::Error::last_os_error();
134 match err.raw_os_error() {
135 Some(WSAESHUTDOWN) => write = false,
136 Some(WSAEWOULDBLOCK) => (),
137 _ => return Err(err),
138 }
139 }
140
141 let read_result = unsafe { recv(socket, usize::MAX as *mut _, 1, MSG_PEEK) };
145 if read_result == SOCKET_ERROR {
146 let err = io::Error::last_os_error();
147 match err.raw_os_error() {
148 Some(WSAEFAULT) => (),
149 Some(WSAESHUTDOWN) => read = false,
150 _ => return Err(err),
151 }
152 }
153
154 Ok((read, write))
155}
156
157#[cfg(all(windows, feature = "socket2"))]
158impl IsReadWrite for socket2::Socket {
159 #[inline]
160 fn is_read_write(&self) -> io::Result<(bool, bool)> {
161 use io_lifetimes::AsSocketlike;
162 self.as_socketlike_view::<std::net::TcpStream>()
163 .is_read_write()
164 }
165}