1#![stable(feature = "io_safety", since = "1.63.0")]
4#![deny(unsafe_op_in_unsafe_fn)]
5
6use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
7use crate::marker::PhantomData;
8use crate::mem::ManuallyDrop;
9#[cfg(not(any(target_arch = "wasm32", target_env = "sgx", target_os = "hermit")))]
10use crate::sys::cvt;
11use crate::sys_common::{AsInner, FromInner, IntoInner};
12use crate::{fmt, fs, io};
13
14type ValidRawFd = core::num::niche_types::NotAllOnes<RawFd>;
15
16#[derive(Copy, Clone)]
36#[repr(transparent)]
37#[rustc_nonnull_optimization_guaranteed]
38#[stable(feature = "io_safety", since = "1.63.0")]
39pub struct BorrowedFd<'fd> {
40 fd: ValidRawFd,
41 _phantom: PhantomData<&'fd OwnedFd>,
42}
43
44#[repr(transparent)]
56#[rustc_nonnull_optimization_guaranteed]
57#[stable(feature = "io_safety", since = "1.63.0")]
58pub struct OwnedFd {
59 fd: ValidRawFd,
60}
61
62impl BorrowedFd<'_> {
63 #[inline]
70 #[track_caller]
71 #[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
72 #[stable(feature = "io_safety", since = "1.63.0")]
73 pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
74 Self { fd: ValidRawFd::new(fd).expect("fd != -1"), _phantom: PhantomData }
75 }
76}
77
78impl OwnedFd {
79 #[stable(feature = "io_safety", since = "1.63.0")]
82 pub fn try_clone(&self) -> crate::io::Result<Self> {
83 self.as_fd().try_clone_to_owned()
84 }
85}
86
87impl BorrowedFd<'_> {
88 #[cfg(not(any(target_arch = "wasm32", target_os = "hermit")))]
91 #[stable(feature = "io_safety", since = "1.63.0")]
92 pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
93 #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
97 let cmd = libc::F_DUPFD_CLOEXEC;
98
99 #[cfg(any(target_os = "espidf", target_os = "vita"))]
104 let cmd = libc::F_DUPFD;
105
106 let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 3) })?;
108 Ok(unsafe { OwnedFd::from_raw_fd(fd) })
109 }
110
111 #[cfg(any(target_arch = "wasm32", target_os = "hermit"))]
114 #[stable(feature = "io_safety", since = "1.63.0")]
115 pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
116 Err(crate::io::Error::UNSUPPORTED_PLATFORM)
117 }
118}
119
120#[stable(feature = "io_safety", since = "1.63.0")]
121impl AsRawFd for BorrowedFd<'_> {
122 #[inline]
123 fn as_raw_fd(&self) -> RawFd {
124 self.fd.as_inner()
125 }
126}
127
128#[stable(feature = "io_safety", since = "1.63.0")]
129impl AsRawFd for OwnedFd {
130 #[inline]
131 fn as_raw_fd(&self) -> RawFd {
132 self.fd.as_inner()
133 }
134}
135
136#[stable(feature = "io_safety", since = "1.63.0")]
137impl IntoRawFd for OwnedFd {
138 #[inline]
139 fn into_raw_fd(self) -> RawFd {
140 ManuallyDrop::new(self).fd.as_inner()
141 }
142}
143
144#[stable(feature = "io_safety", since = "1.63.0")]
145impl FromRawFd for OwnedFd {
146 #[inline]
155 #[track_caller]
156 unsafe fn from_raw_fd(fd: RawFd) -> Self {
157 Self { fd: ValidRawFd::new(fd).expect("fd != -1") }
158 }
159}
160
161#[stable(feature = "io_safety", since = "1.63.0")]
162impl Drop for OwnedFd {
163 #[inline]
164 fn drop(&mut self) {
165 unsafe {
166 #[cfg(not(target_os = "hermit"))]
178 {
179 #[cfg(unix)]
180 crate::sys::fs::debug_assert_fd_is_open(self.fd.as_inner());
181
182 let _ = libc::close(self.fd.as_inner());
183 }
184 #[cfg(target_os = "hermit")]
185 let _ = hermit_abi::close(self.fd.as_inner());
186 }
187 }
188}
189
190#[stable(feature = "io_safety", since = "1.63.0")]
191impl fmt::Debug for BorrowedFd<'_> {
192 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193 f.debug_struct("BorrowedFd").field("fd", &self.fd).finish()
194 }
195}
196
197#[stable(feature = "io_safety", since = "1.63.0")]
198impl fmt::Debug for OwnedFd {
199 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
200 f.debug_struct("OwnedFd").field("fd", &self.fd).finish()
201 }
202}
203
204macro_rules! impl_is_terminal {
205 ($($t:ty),*$(,)?) => {$(
206 #[unstable(feature = "sealed", issue = "none")]
207 impl crate::sealed::Sealed for $t {}
208
209 #[stable(feature = "is_terminal", since = "1.70.0")]
210 impl crate::io::IsTerminal for $t {
211 #[inline]
212 fn is_terminal(&self) -> bool {
213 crate::sys::io::is_terminal(self)
214 }
215 }
216 )*}
217}
218
219impl_is_terminal!(BorrowedFd<'_>, OwnedFd);
220
221#[stable(feature = "io_safety", since = "1.63.0")]
227pub trait AsFd {
228 #[stable(feature = "io_safety", since = "1.63.0")]
244 fn as_fd(&self) -> BorrowedFd<'_>;
245}
246
247#[stable(feature = "io_safety", since = "1.63.0")]
248impl<T: AsFd + ?Sized> AsFd for &T {
249 #[inline]
250 fn as_fd(&self) -> BorrowedFd<'_> {
251 T::as_fd(self)
252 }
253}
254
255#[stable(feature = "io_safety", since = "1.63.0")]
256impl<T: AsFd + ?Sized> AsFd for &mut T {
257 #[inline]
258 fn as_fd(&self) -> BorrowedFd<'_> {
259 T::as_fd(self)
260 }
261}
262
263#[stable(feature = "io_safety", since = "1.63.0")]
264impl AsFd for BorrowedFd<'_> {
265 #[inline]
266 fn as_fd(&self) -> BorrowedFd<'_> {
267 *self
268 }
269}
270
271#[stable(feature = "io_safety", since = "1.63.0")]
272impl AsFd for OwnedFd {
273 #[inline]
274 fn as_fd(&self) -> BorrowedFd<'_> {
275 unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
279 }
280}
281
282#[stable(feature = "io_safety", since = "1.63.0")]
283impl AsFd for fs::File {
284 #[inline]
285 fn as_fd(&self) -> BorrowedFd<'_> {
286 self.as_inner().as_fd()
287 }
288}
289
290#[stable(feature = "io_safety", since = "1.63.0")]
291impl From<fs::File> for OwnedFd {
292 #[inline]
294 fn from(file: fs::File) -> OwnedFd {
295 file.into_inner().into_inner().into_inner()
296 }
297}
298
299#[stable(feature = "io_safety", since = "1.63.0")]
300impl From<OwnedFd> for fs::File {
301 #[inline]
304 fn from(owned_fd: OwnedFd) -> Self {
305 Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd)))
306 }
307}
308
309#[stable(feature = "io_safety", since = "1.63.0")]
310impl AsFd for crate::net::TcpStream {
311 #[inline]
312 fn as_fd(&self) -> BorrowedFd<'_> {
313 self.as_inner().socket().as_fd()
314 }
315}
316
317#[stable(feature = "io_safety", since = "1.63.0")]
318impl From<crate::net::TcpStream> for OwnedFd {
319 #[inline]
321 fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd {
322 tcp_stream.into_inner().into_socket().into_inner().into_inner().into()
323 }
324}
325
326#[stable(feature = "io_safety", since = "1.63.0")]
327impl From<OwnedFd> for crate::net::TcpStream {
328 #[inline]
329 fn from(owned_fd: OwnedFd) -> Self {
330 Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
331 owned_fd,
332 ))))
333 }
334}
335
336#[stable(feature = "io_safety", since = "1.63.0")]
337impl AsFd for crate::net::TcpListener {
338 #[inline]
339 fn as_fd(&self) -> BorrowedFd<'_> {
340 self.as_inner().socket().as_fd()
341 }
342}
343
344#[stable(feature = "io_safety", since = "1.63.0")]
345impl From<crate::net::TcpListener> for OwnedFd {
346 #[inline]
348 fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd {
349 tcp_listener.into_inner().into_socket().into_inner().into_inner().into()
350 }
351}
352
353#[stable(feature = "io_safety", since = "1.63.0")]
354impl From<OwnedFd> for crate::net::TcpListener {
355 #[inline]
356 fn from(owned_fd: OwnedFd) -> Self {
357 Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
358 owned_fd,
359 ))))
360 }
361}
362
363#[stable(feature = "io_safety", since = "1.63.0")]
364impl AsFd for crate::net::UdpSocket {
365 #[inline]
366 fn as_fd(&self) -> BorrowedFd<'_> {
367 self.as_inner().socket().as_fd()
368 }
369}
370
371#[stable(feature = "io_safety", since = "1.63.0")]
372impl From<crate::net::UdpSocket> for OwnedFd {
373 #[inline]
375 fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd {
376 udp_socket.into_inner().into_socket().into_inner().into_inner().into()
377 }
378}
379
380#[stable(feature = "io_safety", since = "1.63.0")]
381impl From<OwnedFd> for crate::net::UdpSocket {
382 #[inline]
383 fn from(owned_fd: OwnedFd) -> Self {
384 Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
385 owned_fd,
386 ))))
387 }
388}
389
390#[stable(feature = "asfd_ptrs", since = "1.64.0")]
391impl<T: AsFd + ?Sized> AsFd for crate::sync::Arc<T> {
407 #[inline]
408 fn as_fd(&self) -> BorrowedFd<'_> {
409 (**self).as_fd()
410 }
411}
412
413#[stable(feature = "asfd_rc", since = "1.69.0")]
414impl<T: AsFd + ?Sized> AsFd for crate::rc::Rc<T> {
415 #[inline]
416 fn as_fd(&self) -> BorrowedFd<'_> {
417 (**self).as_fd()
418 }
419}
420
421#[unstable(feature = "unique_rc_arc", issue = "112566")]
422impl<T: AsFd + ?Sized> AsFd for crate::rc::UniqueRc<T> {
423 #[inline]
424 fn as_fd(&self) -> BorrowedFd<'_> {
425 (**self).as_fd()
426 }
427}
428
429#[stable(feature = "asfd_ptrs", since = "1.64.0")]
430impl<T: AsFd + ?Sized> AsFd for Box<T> {
431 #[inline]
432 fn as_fd(&self) -> BorrowedFd<'_> {
433 (**self).as_fd()
434 }
435}
436
437#[stable(feature = "io_safety", since = "1.63.0")]
438impl AsFd for io::Stdin {
439 #[inline]
440 fn as_fd(&self) -> BorrowedFd<'_> {
441 unsafe { BorrowedFd::borrow_raw(0) }
442 }
443}
444
445#[stable(feature = "io_safety", since = "1.63.0")]
446impl<'a> AsFd for io::StdinLock<'a> {
447 #[inline]
448 fn as_fd(&self) -> BorrowedFd<'_> {
449 unsafe { BorrowedFd::borrow_raw(0) }
451 }
452}
453
454#[stable(feature = "io_safety", since = "1.63.0")]
455impl AsFd for io::Stdout {
456 #[inline]
457 fn as_fd(&self) -> BorrowedFd<'_> {
458 unsafe { BorrowedFd::borrow_raw(1) }
459 }
460}
461
462#[stable(feature = "io_safety", since = "1.63.0")]
463impl<'a> AsFd for io::StdoutLock<'a> {
464 #[inline]
465 fn as_fd(&self) -> BorrowedFd<'_> {
466 unsafe { BorrowedFd::borrow_raw(1) }
468 }
469}
470
471#[stable(feature = "io_safety", since = "1.63.0")]
472impl AsFd for io::Stderr {
473 #[inline]
474 fn as_fd(&self) -> BorrowedFd<'_> {
475 unsafe { BorrowedFd::borrow_raw(2) }
476 }
477}
478
479#[stable(feature = "io_safety", since = "1.63.0")]
480impl<'a> AsFd for io::StderrLock<'a> {
481 #[inline]
482 fn as_fd(&self) -> BorrowedFd<'_> {
483 unsafe { BorrowedFd::borrow_raw(2) }
485 }
486}