1#![stable(feature = "io_safety", since = "1.63.0")]
4#![deny(unsafe_op_in_unsafe_fn)]
5
6use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
7#[cfg(not(target_os = "trusty"))]
8use crate::fs;
9use crate::marker::PhantomData;
10use crate::mem::ManuallyDrop;
11#[cfg(not(any(
12 target_arch = "wasm32",
13 target_env = "sgx",
14 target_os = "hermit",
15 target_os = "trusty"
16)))]
17use crate::sys::cvt;
18#[cfg(not(target_os = "trusty"))]
19use crate::sys_common::{AsInner, FromInner, IntoInner};
20use crate::{fmt, io};
21
22type ValidRawFd = core::num::niche_types::NotAllOnes<RawFd>;
23
24#[derive(Copy, Clone)]
44#[repr(transparent)]
45#[rustc_nonnull_optimization_guaranteed]
46#[stable(feature = "io_safety", since = "1.63.0")]
47pub struct BorrowedFd<'fd> {
48 fd: ValidRawFd,
49 _phantom: PhantomData<&'fd OwnedFd>,
50}
51
52#[repr(transparent)]
64#[rustc_nonnull_optimization_guaranteed]
65#[stable(feature = "io_safety", since = "1.63.0")]
66pub struct OwnedFd {
67 fd: ValidRawFd,
68}
69
70impl BorrowedFd<'_> {
71 #[inline]
78 #[track_caller]
79 #[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
80 #[stable(feature = "io_safety", since = "1.63.0")]
81 pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
82 Self { fd: ValidRawFd::new(fd).expect("fd != -1"), _phantom: PhantomData }
83 }
84}
85
86impl OwnedFd {
87 #[stable(feature = "io_safety", since = "1.63.0")]
90 pub fn try_clone(&self) -> crate::io::Result<Self> {
91 self.as_fd().try_clone_to_owned()
92 }
93}
94
95impl BorrowedFd<'_> {
96 #[cfg(not(any(target_arch = "wasm32", target_os = "hermit", target_os = "trusty")))]
99 #[stable(feature = "io_safety", since = "1.63.0")]
100 pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
101 #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
105 let cmd = libc::F_DUPFD_CLOEXEC;
106
107 #[cfg(any(target_os = "espidf", target_os = "vita"))]
112 let cmd = libc::F_DUPFD;
113
114 let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 3) })?;
116 Ok(unsafe { OwnedFd::from_raw_fd(fd) })
117 }
118
119 #[cfg(any(target_arch = "wasm32", target_os = "hermit", target_os = "trusty"))]
122 #[stable(feature = "io_safety", since = "1.63.0")]
123 pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
124 Err(crate::io::Error::UNSUPPORTED_PLATFORM)
125 }
126}
127
128#[stable(feature = "io_safety", since = "1.63.0")]
129impl AsRawFd for BorrowedFd<'_> {
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 AsRawFd for OwnedFd {
138 #[inline]
139 fn as_raw_fd(&self) -> RawFd {
140 self.fd.as_inner()
141 }
142}
143
144#[stable(feature = "io_safety", since = "1.63.0")]
145impl IntoRawFd for OwnedFd {
146 #[inline]
147 fn into_raw_fd(self) -> RawFd {
148 ManuallyDrop::new(self).fd.as_inner()
149 }
150}
151
152#[stable(feature = "io_safety", since = "1.63.0")]
153impl FromRawFd for OwnedFd {
154 #[inline]
163 #[track_caller]
164 unsafe fn from_raw_fd(fd: RawFd) -> Self {
165 Self { fd: ValidRawFd::new(fd).expect("fd != -1") }
166 }
167}
168
169#[stable(feature = "io_safety", since = "1.63.0")]
170impl Drop for OwnedFd {
171 #[inline]
172 fn drop(&mut self) {
173 unsafe {
174 #[cfg(not(target_os = "hermit"))]
186 {
187 #[cfg(unix)]
188 crate::sys::fs::debug_assert_fd_is_open(self.fd.as_inner());
189
190 let _ = libc::close(self.fd.as_inner());
191 }
192 #[cfg(target_os = "hermit")]
193 let _ = hermit_abi::close(self.fd.as_inner());
194 }
195 }
196}
197
198#[stable(feature = "io_safety", since = "1.63.0")]
199impl fmt::Debug for BorrowedFd<'_> {
200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201 f.debug_struct("BorrowedFd").field("fd", &self.fd).finish()
202 }
203}
204
205#[stable(feature = "io_safety", since = "1.63.0")]
206impl fmt::Debug for OwnedFd {
207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208 f.debug_struct("OwnedFd").field("fd", &self.fd).finish()
209 }
210}
211
212macro_rules! impl_is_terminal {
213 ($($t:ty),*$(,)?) => {$(
214 #[unstable(feature = "sealed", issue = "none")]
215 impl crate::sealed::Sealed for $t {}
216
217 #[stable(feature = "is_terminal", since = "1.70.0")]
218 impl crate::io::IsTerminal for $t {
219 #[inline]
220 fn is_terminal(&self) -> bool {
221 crate::sys::io::is_terminal(self)
222 }
223 }
224 )*}
225}
226
227impl_is_terminal!(BorrowedFd<'_>, OwnedFd);
228
229#[stable(feature = "io_safety", since = "1.63.0")]
235pub trait AsFd {
236 #[stable(feature = "io_safety", since = "1.63.0")]
252 fn as_fd(&self) -> BorrowedFd<'_>;
253}
254
255#[stable(feature = "io_safety", since = "1.63.0")]
256impl<T: AsFd + ?Sized> AsFd for &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<T: AsFd + ?Sized> AsFd for &mut T {
265 #[inline]
266 fn as_fd(&self) -> BorrowedFd<'_> {
267 T::as_fd(self)
268 }
269}
270
271#[stable(feature = "io_safety", since = "1.63.0")]
272impl AsFd for BorrowedFd<'_> {
273 #[inline]
274 fn as_fd(&self) -> BorrowedFd<'_> {
275 *self
276 }
277}
278
279#[stable(feature = "io_safety", since = "1.63.0")]
280impl AsFd for OwnedFd {
281 #[inline]
282 fn as_fd(&self) -> BorrowedFd<'_> {
283 unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
287 }
288}
289
290#[stable(feature = "io_safety", since = "1.63.0")]
291#[cfg(not(target_os = "trusty"))]
292impl AsFd for fs::File {
293 #[inline]
294 fn as_fd(&self) -> BorrowedFd<'_> {
295 self.as_inner().as_fd()
296 }
297}
298
299#[stable(feature = "io_safety", since = "1.63.0")]
300#[cfg(not(target_os = "trusty"))]
301impl From<fs::File> for OwnedFd {
302 #[inline]
304 fn from(file: fs::File) -> OwnedFd {
305 file.into_inner().into_inner().into_inner()
306 }
307}
308
309#[stable(feature = "io_safety", since = "1.63.0")]
310#[cfg(not(target_os = "trusty"))]
311impl From<OwnedFd> for fs::File {
312 #[inline]
315 fn from(owned_fd: OwnedFd) -> Self {
316 Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd)))
317 }
318}
319
320#[stable(feature = "io_safety", since = "1.63.0")]
321#[cfg(not(target_os = "trusty"))]
322impl AsFd for crate::net::TcpStream {
323 #[inline]
324 fn as_fd(&self) -> BorrowedFd<'_> {
325 self.as_inner().socket().as_fd()
326 }
327}
328
329#[stable(feature = "io_safety", since = "1.63.0")]
330#[cfg(not(target_os = "trusty"))]
331impl From<crate::net::TcpStream> for OwnedFd {
332 #[inline]
334 fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd {
335 tcp_stream.into_inner().into_socket().into_inner().into_inner().into()
336 }
337}
338
339#[stable(feature = "io_safety", since = "1.63.0")]
340#[cfg(not(target_os = "trusty"))]
341impl From<OwnedFd> for crate::net::TcpStream {
342 #[inline]
343 fn from(owned_fd: OwnedFd) -> Self {
344 Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
345 owned_fd,
346 ))))
347 }
348}
349
350#[stable(feature = "io_safety", since = "1.63.0")]
351#[cfg(not(target_os = "trusty"))]
352impl AsFd for crate::net::TcpListener {
353 #[inline]
354 fn as_fd(&self) -> BorrowedFd<'_> {
355 self.as_inner().socket().as_fd()
356 }
357}
358
359#[stable(feature = "io_safety", since = "1.63.0")]
360#[cfg(not(target_os = "trusty"))]
361impl From<crate::net::TcpListener> for OwnedFd {
362 #[inline]
364 fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd {
365 tcp_listener.into_inner().into_socket().into_inner().into_inner().into()
366 }
367}
368
369#[stable(feature = "io_safety", since = "1.63.0")]
370#[cfg(not(target_os = "trusty"))]
371impl From<OwnedFd> for crate::net::TcpListener {
372 #[inline]
373 fn from(owned_fd: OwnedFd) -> Self {
374 Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
375 owned_fd,
376 ))))
377 }
378}
379
380#[stable(feature = "io_safety", since = "1.63.0")]
381#[cfg(not(target_os = "trusty"))]
382impl AsFd for crate::net::UdpSocket {
383 #[inline]
384 fn as_fd(&self) -> BorrowedFd<'_> {
385 self.as_inner().socket().as_fd()
386 }
387}
388
389#[stable(feature = "io_safety", since = "1.63.0")]
390#[cfg(not(target_os = "trusty"))]
391impl From<crate::net::UdpSocket> for OwnedFd {
392 #[inline]
394 fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd {
395 udp_socket.into_inner().into_socket().into_inner().into_inner().into()
396 }
397}
398
399#[stable(feature = "io_safety", since = "1.63.0")]
400#[cfg(not(target_os = "trusty"))]
401impl From<OwnedFd> for crate::net::UdpSocket {
402 #[inline]
403 fn from(owned_fd: OwnedFd) -> Self {
404 Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
405 owned_fd,
406 ))))
407 }
408}
409
410#[stable(feature = "asfd_ptrs", since = "1.64.0")]
411impl<T: AsFd + ?Sized> AsFd for crate::sync::Arc<T> {
427 #[inline]
428 fn as_fd(&self) -> BorrowedFd<'_> {
429 (**self).as_fd()
430 }
431}
432
433#[stable(feature = "asfd_rc", since = "1.69.0")]
434impl<T: AsFd + ?Sized> AsFd for crate::rc::Rc<T> {
435 #[inline]
436 fn as_fd(&self) -> BorrowedFd<'_> {
437 (**self).as_fd()
438 }
439}
440
441#[unstable(feature = "unique_rc_arc", issue = "112566")]
442impl<T: AsFd + ?Sized> AsFd for crate::rc::UniqueRc<T> {
443 #[inline]
444 fn as_fd(&self) -> BorrowedFd<'_> {
445 (**self).as_fd()
446 }
447}
448
449#[stable(feature = "asfd_ptrs", since = "1.64.0")]
450impl<T: AsFd + ?Sized> AsFd for Box<T> {
451 #[inline]
452 fn as_fd(&self) -> BorrowedFd<'_> {
453 (**self).as_fd()
454 }
455}
456
457#[stable(feature = "io_safety", since = "1.63.0")]
458impl AsFd for io::Stdin {
459 #[inline]
460 fn as_fd(&self) -> BorrowedFd<'_> {
461 unsafe { BorrowedFd::borrow_raw(0) }
462 }
463}
464
465#[stable(feature = "io_safety", since = "1.63.0")]
466impl<'a> AsFd for io::StdinLock<'a> {
467 #[inline]
468 fn as_fd(&self) -> BorrowedFd<'_> {
469 unsafe { BorrowedFd::borrow_raw(0) }
471 }
472}
473
474#[stable(feature = "io_safety", since = "1.63.0")]
475impl AsFd for io::Stdout {
476 #[inline]
477 fn as_fd(&self) -> BorrowedFd<'_> {
478 unsafe { BorrowedFd::borrow_raw(1) }
479 }
480}
481
482#[stable(feature = "io_safety", since = "1.63.0")]
483impl<'a> AsFd for io::StdoutLock<'a> {
484 #[inline]
485 fn as_fd(&self) -> BorrowedFd<'_> {
486 unsafe { BorrowedFd::borrow_raw(1) }
488 }
489}
490
491#[stable(feature = "io_safety", since = "1.63.0")]
492impl AsFd for io::Stderr {
493 #[inline]
494 fn as_fd(&self) -> BorrowedFd<'_> {
495 unsafe { BorrowedFd::borrow_raw(2) }
496 }
497}
498
499#[stable(feature = "io_safety", since = "1.63.0")]
500impl<'a> AsFd for io::StderrLock<'a> {
501 #[inline]
502 fn as_fd(&self) -> BorrowedFd<'_> {
503 unsafe { BorrowedFd::borrow_raw(2) }
505 }
506}
507
508#[stable(feature = "anonymous_pipe", since = "1.87.0")]
509#[cfg(not(target_os = "trusty"))]
510impl AsFd for io::PipeReader {
511 fn as_fd(&self) -> BorrowedFd<'_> {
512 self.0.as_fd()
513 }
514}
515
516#[stable(feature = "anonymous_pipe", since = "1.87.0")]
517#[cfg(not(target_os = "trusty"))]
518impl From<io::PipeReader> for OwnedFd {
519 fn from(pipe: io::PipeReader) -> Self {
520 pipe.0.into_inner()
521 }
522}
523
524#[stable(feature = "anonymous_pipe", since = "1.87.0")]
525#[cfg(not(target_os = "trusty"))]
526impl AsFd for io::PipeWriter {
527 fn as_fd(&self) -> BorrowedFd<'_> {
528 self.0.as_fd()
529 }
530}
531
532#[stable(feature = "anonymous_pipe", since = "1.87.0")]
533#[cfg(not(target_os = "trusty"))]
534impl From<io::PipeWriter> for OwnedFd {
535 fn from(pipe: io::PipeWriter) -> Self {
536 pipe.0.into_inner()
537 }
538}
539
540#[stable(feature = "anonymous_pipe", since = "1.87.0")]
541#[cfg(not(target_os = "trusty"))]
542impl From<OwnedFd> for io::PipeReader {
543 fn from(owned_fd: OwnedFd) -> Self {
544 Self(FromInner::from_inner(owned_fd))
545 }
546}
547
548#[stable(feature = "anonymous_pipe", since = "1.87.0")]
549#[cfg(not(target_os = "trusty"))]
550impl From<OwnedFd> for io::PipeWriter {
551 fn from(owned_fd: OwnedFd) -> Self {
552 Self(FromInner::from_inner(owned_fd))
553 }
554}