1#![stable(feature = "io_safety", since = "1.63.0")]
4#![deny(unsafe_op_in_unsafe_fn)]
5
6#[cfg(target_os = "motor")]
7use moto_rt::libc;
8
9use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
10use crate::alloc::Allocator;
11#[cfg(not(target_os = "trusty"))]
12use crate::fs;
13use crate::macros::rustdoc_skip_body;
14use crate::marker::PhantomData;
15use crate::mem::ManuallyDrop;
16#[cfg(not(any(
17 all(target_family = "wasm", not(target_os = "emscripten")),
18 target_env = "sgx",
19 target_os = "hermit",
20 target_os = "trusty",
21 target_os = "motor"
22)))]
23use crate::sys::cvt;
24#[cfg(not(target_os = "trusty"))]
25use crate::sys::{AsInner, FromInner, IntoInner};
26use crate::{fmt, io};
27
28type ValidRawFd = core::num::niche_types::NotAllOnes<RawFd>;
29
30#[derive(Copy, Clone)]
50#[repr(transparent)]
51#[rustc_nonnull_optimization_guaranteed]
52#[stable(feature = "io_safety", since = "1.63.0")]
53pub struct BorrowedFd<'fd> {
54 fd: ValidRawFd,
55 _phantom: PhantomData<&'fd OwnedFd>,
56}
57
58#[repr(transparent)]
70#[rustc_nonnull_optimization_guaranteed]
71#[stable(feature = "io_safety", since = "1.63.0")]
72pub struct OwnedFd {
73 fd: ValidRawFd,
74}
75
76impl BorrowedFd<'_> {
77 #[inline]
88 #[track_caller]
89 #[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
90 #[stable(feature = "io_safety", since = "1.63.0")]
91 pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
92 Self { fd: ValidRawFd::new(fd).expect("fd != -1"), _phantom: PhantomData }
93 }
94
95 #[cfg_attr(all(unix, not(miri)), doc = "```")]
98 #[cfg_attr(not(unix), doc = "```ignore (needs unix)")]
99 #[unstable(feature = "fd_view", issue = "160402")]
109 pub fn to_view<T>(&self) -> &T
110 where
111 Self: AsRef<T>,
112 {
113 self.as_ref()
114 }
115}
116
117impl OwnedFd {
118 #[stable(feature = "io_safety", since = "1.63.0")]
121 pub fn try_clone(&self) -> io::Result<Self> {
122 self.as_fd().try_clone_to_owned()
123 }
124}
125
126impl BorrowedFd<'_> {
127 #[cfg(not(any(
130 all(target_family = "wasm", not(target_os = "emscripten")),
131 target_os = "hermit",
132 target_os = "trusty",
133 target_os = "motor"
134 )))]
135 #[stable(feature = "io_safety", since = "1.63.0")]
136 #[rustdoc_skip_body]
137 pub fn try_clone_to_owned(&self) -> io::Result<OwnedFd> {
138 #[cfg(not(any(target_os = "espidf", target_os = "vita")))]
142 let cmd = libc::F_DUPFD_CLOEXEC;
143
144 #[cfg(any(target_os = "espidf", target_os = "vita"))]
149 let cmd = libc::F_DUPFD;
150
151 let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 3) })?;
153 Ok(unsafe { OwnedFd::from_raw_fd(fd) })
154 }
155
156 #[cfg(any(
159 all(target_family = "wasm", not(target_os = "emscripten")),
160 target_os = "hermit",
161 target_os = "trusty"
162 ))]
163 #[stable(feature = "io_safety", since = "1.63.0")]
164 pub fn try_clone_to_owned(&self) -> io::Result<OwnedFd> {
165 Err(io::Error::UNSUPPORTED_PLATFORM)
166 }
167
168 #[cfg(target_os = "motor")]
171 #[stable(feature = "io_safety", since = "1.63.0")]
172 pub fn try_clone_to_owned(&self) -> io::Result<OwnedFd> {
173 let fd = moto_rt::fs::duplicate(self.as_raw_fd()).map_err(crate::sys::map_motor_error)?;
174 Ok(unsafe { OwnedFd::from_raw_fd(fd) })
175 }
176}
177
178#[stable(feature = "io_safety", since = "1.63.0")]
179impl AsRawFd for BorrowedFd<'_> {
180 #[inline]
181 fn as_raw_fd(&self) -> RawFd {
182 self.fd.as_inner()
183 }
184}
185
186#[stable(feature = "io_safety", since = "1.63.0")]
187impl AsRawFd for OwnedFd {
188 #[inline]
189 fn as_raw_fd(&self) -> RawFd {
190 self.fd.as_inner()
191 }
192}
193
194#[stable(feature = "io_safety", since = "1.63.0")]
195impl IntoRawFd for OwnedFd {
196 #[inline]
197 fn into_raw_fd(self) -> RawFd {
198 ManuallyDrop::new(self).fd.as_inner()
199 }
200}
201
202#[stable(feature = "io_safety", since = "1.63.0")]
203impl FromRawFd for OwnedFd {
204 #[inline]
217 #[track_caller]
218 unsafe fn from_raw_fd(fd: RawFd) -> Self {
219 Self { fd: ValidRawFd::new(fd).expect("fd != -1") }
220 }
221}
222
223#[stable(feature = "io_safety", since = "1.63.0")]
224impl Drop for OwnedFd {
225 #[inline]
226 #[rustdoc_skip_body]
227 fn drop(&mut self) {
228 unsafe {
229 #[cfg(not(target_os = "hermit"))]
241 {
242 #[cfg(unix)]
243 crate::sys::fs::debug_assert_fd_is_open(self.fd.as_inner());
244
245 let _ = libc::close(self.fd.as_inner());
246 }
247 #[cfg(target_os = "hermit")]
248 let _ = hermit_abi::close(self.fd.as_inner());
249 }
250 }
251}
252
253#[stable(feature = "io_safety", since = "1.63.0")]
254impl fmt::Debug for BorrowedFd<'_> {
255 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256 f.debug_struct("BorrowedFd").field("fd", &self.fd).finish()
257 }
258}
259
260#[stable(feature = "io_safety", since = "1.63.0")]
261impl fmt::Debug for OwnedFd {
262 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
263 f.debug_struct("OwnedFd").field("fd", &self.fd).finish()
264 }
265}
266
267macro_rules! impl_is_terminal {
268 ($($t:ty),*$(,)?) => {$(
269 #[stable(feature = "is_terminal", since = "1.70.0")]
270 impl io::IsTerminal for $t {
271 #[inline]
272 fn is_terminal(&self) -> bool {
273 crate::sys::io::is_terminal(self)
274 }
275 }
276 )*}
277}
278
279impl_is_terminal!(BorrowedFd<'_>, OwnedFd);
280
281#[stable(feature = "io_safety", since = "1.63.0")]
287pub trait AsFd {
288 #[stable(feature = "io_safety", since = "1.63.0")]
304 fn as_fd(&self) -> BorrowedFd<'_>;
305}
306
307#[stable(feature = "io_safety", since = "1.63.0")]
308impl<T: AsFd + ?Sized> AsFd for &T {
309 #[inline]
310 fn as_fd(&self) -> BorrowedFd<'_> {
311 T::as_fd(self)
312 }
313}
314
315#[stable(feature = "io_safety", since = "1.63.0")]
316impl<T: AsFd + ?Sized> AsFd for &mut T {
317 #[inline]
318 fn as_fd(&self) -> BorrowedFd<'_> {
319 T::as_fd(self)
320 }
321}
322
323#[stable(feature = "io_safety", since = "1.63.0")]
324impl AsFd for BorrowedFd<'_> {
325 #[inline]
326 fn as_fd(&self) -> BorrowedFd<'_> {
327 *self
328 }
329}
330
331#[stable(feature = "io_safety", since = "1.63.0")]
332impl AsFd for OwnedFd {
333 #[inline]
334 fn as_fd(&self) -> BorrowedFd<'_> {
335 unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
339 }
340}
341
342#[stable(feature = "io_safety", since = "1.63.0")]
343#[cfg(not(target_os = "trusty"))]
344impl AsFd for fs::File {
345 #[inline]
346 #[rustdoc_skip_body]
347 fn as_fd(&self) -> BorrowedFd<'_> {
348 self.as_inner().as_fd()
349 }
350}
351
352#[stable(feature = "io_safety", since = "1.63.0")]
353#[cfg(not(target_os = "trusty"))]
354impl From<fs::File> for OwnedFd {
355 #[inline]
357 #[rustdoc_skip_body]
358 fn from(file: fs::File) -> OwnedFd {
359 file.into_inner().into_inner().into_inner()
360 }
361}
362
363#[stable(feature = "io_safety", since = "1.63.0")]
364#[cfg(not(target_os = "trusty"))]
365impl From<OwnedFd> for fs::File {
366 #[inline]
369 #[rustdoc_skip_body]
370 fn from(owned_fd: OwnedFd) -> Self {
371 Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd)))
372 }
373}
374
375#[stable(feature = "io_safety", since = "1.63.0")]
376#[cfg(not(target_os = "trusty"))]
377impl AsFd for crate::net::TcpStream {
378 #[inline]
379 #[rustdoc_skip_body]
380 fn as_fd(&self) -> BorrowedFd<'_> {
381 self.as_inner().socket().as_fd()
382 }
383}
384
385#[stable(feature = "io_safety", since = "1.63.0")]
386#[cfg(not(target_os = "trusty"))]
387impl From<crate::net::TcpStream> for OwnedFd {
388 #[inline]
390 #[rustdoc_skip_body]
391 fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd {
392 tcp_stream.into_inner().into_socket().into_inner().into_inner()
393 }
394}
395
396#[stable(feature = "io_safety", since = "1.63.0")]
397#[cfg(not(target_os = "trusty"))]
398impl From<OwnedFd> for crate::net::TcpStream {
399 #[inline]
400 #[rustdoc_skip_body]
401 fn from(owned_fd: OwnedFd) -> Self {
402 Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
403 owned_fd,
404 ))))
405 }
406}
407
408#[stable(feature = "io_safety", since = "1.63.0")]
409#[cfg(not(target_os = "trusty"))]
410impl AsFd for crate::net::TcpListener {
411 #[inline]
412 #[rustdoc_skip_body]
413 fn as_fd(&self) -> BorrowedFd<'_> {
414 self.as_inner().socket().as_fd()
415 }
416}
417
418#[stable(feature = "io_safety", since = "1.63.0")]
419#[cfg(not(target_os = "trusty"))]
420impl From<crate::net::TcpListener> for OwnedFd {
421 #[inline]
423 #[rustdoc_skip_body]
424 fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd {
425 tcp_listener.into_inner().into_socket().into_inner().into_inner()
426 }
427}
428
429#[stable(feature = "io_safety", since = "1.63.0")]
430#[cfg(not(target_os = "trusty"))]
431impl From<OwnedFd> for crate::net::TcpListener {
432 #[inline]
433 #[rustdoc_skip_body]
434 fn from(owned_fd: OwnedFd) -> Self {
435 Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
436 owned_fd,
437 ))))
438 }
439}
440
441#[stable(feature = "io_safety", since = "1.63.0")]
442#[cfg(not(target_os = "trusty"))]
443impl AsFd for crate::net::UdpSocket {
444 #[inline]
445 #[rustdoc_skip_body]
446 fn as_fd(&self) -> BorrowedFd<'_> {
447 self.as_inner().socket().as_fd()
448 }
449}
450
451#[stable(feature = "io_safety", since = "1.63.0")]
452#[cfg(not(target_os = "trusty"))]
453impl From<crate::net::UdpSocket> for OwnedFd {
454 #[inline]
456 #[rustdoc_skip_body]
457 fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd {
458 udp_socket.into_inner().into_socket().into_inner().into_inner()
459 }
460}
461
462#[stable(feature = "io_safety", since = "1.63.0")]
463#[cfg(not(target_os = "trusty"))]
464impl From<OwnedFd> for crate::net::UdpSocket {
465 #[inline]
466 #[rustdoc_skip_body]
467 fn from(owned_fd: OwnedFd) -> Self {
468 Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
469 owned_fd,
470 ))))
471 }
472}
473
474pub(crate) macro unsafe_impl_fd_asrefs {
490 ($($t:ty),*$(,)?) => {$(
491 #[unstable(feature = "fd_view", issue = "160402")]
492 #[unstable_feature_bound(fd_view)]
493 impl AsRef<$t> for BorrowedFd<'_> {
494 #[inline]
495 fn as_ref(&self) -> &$t {
496 use core::mem;
497
498 fn type_check<T: From<OwnedFd> + Into<OwnedFd> + AsFd>() {}
501
502 const {
504 assert!(mem::size_of::<RawFd>() == mem::size_of::<$t>());
505 assert!(mem::size_of::<RawFd>() == mem::size_of::<BorrowedFd<'_>>());
506 }
507 type_check::<$t>();
508 unsafe { mem::transmute::<&BorrowedFd<'_>, &$t>(self) }
510 }
511 }
512 )*}
513}
514
515#[cfg(not(target_os = "trusty"))]
516unsafe_impl_fd_asrefs!(
517 crate::fs::File,
518 crate::net::TcpStream,
519 crate::net::TcpListener,
520 crate::net::UdpSocket,
521);
522
523#[cfg(unix)]
524unsafe_impl_fd_asrefs!(io::PipeWriter, io::PipeReader);
525
526#[stable(feature = "asfd_ptrs", since = "1.64.0")]
527impl<T: AsFd + ?Sized> AsFd for crate::sync::Arc<T> {
543 #[inline]
544 fn as_fd(&self) -> BorrowedFd<'_> {
545 (**self).as_fd()
546 }
547}
548
549#[stable(feature = "asfd_rc", since = "1.69.0")]
550impl<T: AsFd + ?Sized> AsFd for crate::rc::Rc<T> {
551 #[inline]
552 fn as_fd(&self) -> BorrowedFd<'_> {
553 (**self).as_fd()
554 }
555}
556
557#[unstable(feature = "unique_rc_arc", issue = "112566")]
558impl<T: AsFd + ?Sized> AsFd for crate::rc::UniqueRc<T> {
559 #[inline]
560 fn as_fd(&self) -> BorrowedFd<'_> {
561 (**self).as_fd()
562 }
563}
564
565#[stable(feature = "asfd_ptrs", since = "1.64.0")]
566impl<T: AsFd + ?Sized, A: Allocator> AsFd for Box<T, A> {
567 #[inline]
568 fn as_fd(&self) -> BorrowedFd<'_> {
569 (**self).as_fd()
570 }
571}
572
573#[stable(feature = "io_safety", since = "1.63.0")]
574impl AsFd for io::Stdin {
575 #[inline]
576 fn as_fd(&self) -> BorrowedFd<'_> {
577 unsafe { BorrowedFd::borrow_raw(0) }
578 }
579}
580
581#[stable(feature = "io_safety", since = "1.63.0")]
582impl<'a> AsFd for io::StdinLock<'a> {
583 #[inline]
584 fn as_fd(&self) -> BorrowedFd<'_> {
585 unsafe { BorrowedFd::borrow_raw(0) }
587 }
588}
589
590#[stable(feature = "io_safety", since = "1.63.0")]
591impl AsFd for io::Stdout {
592 #[inline]
593 fn as_fd(&self) -> BorrowedFd<'_> {
594 unsafe { BorrowedFd::borrow_raw(1) }
595 }
596}
597
598#[stable(feature = "io_safety", since = "1.63.0")]
599impl<'a> AsFd for io::StdoutLock<'a> {
600 #[inline]
601 fn as_fd(&self) -> BorrowedFd<'_> {
602 unsafe { BorrowedFd::borrow_raw(1) }
604 }
605}
606
607#[stable(feature = "io_safety", since = "1.63.0")]
608impl AsFd for io::Stderr {
609 #[inline]
610 fn as_fd(&self) -> BorrowedFd<'_> {
611 unsafe { BorrowedFd::borrow_raw(2) }
612 }
613}
614
615#[stable(feature = "io_safety", since = "1.63.0")]
616impl<'a> AsFd for io::StderrLock<'a> {
617 #[inline]
618 fn as_fd(&self) -> BorrowedFd<'_> {
619 unsafe { BorrowedFd::borrow_raw(2) }
621 }
622}
623
624#[stable(feature = "anonymous_pipe", since = "1.87.0")]
625#[cfg(not(target_os = "trusty"))]
626impl AsFd for io::PipeReader {
627 #[rustdoc_skip_body]
628 fn as_fd(&self) -> BorrowedFd<'_> {
629 self.0.as_fd()
630 }
631}
632
633#[stable(feature = "anonymous_pipe", since = "1.87.0")]
634#[cfg(not(target_os = "trusty"))]
635impl From<io::PipeReader> for OwnedFd {
636 #[rustdoc_skip_body]
637 fn from(pipe: io::PipeReader) -> Self {
638 pipe.0.into_inner()
639 }
640}
641
642#[stable(feature = "anonymous_pipe", since = "1.87.0")]
643#[cfg(not(target_os = "trusty"))]
644impl AsFd for io::PipeWriter {
645 #[rustdoc_skip_body]
646 fn as_fd(&self) -> BorrowedFd<'_> {
647 self.0.as_fd()
648 }
649}
650
651#[stable(feature = "anonymous_pipe", since = "1.87.0")]
652#[cfg(not(target_os = "trusty"))]
653impl From<io::PipeWriter> for OwnedFd {
654 #[rustdoc_skip_body]
655 fn from(pipe: io::PipeWriter) -> Self {
656 pipe.0.into_inner()
657 }
658}
659
660#[stable(feature = "anonymous_pipe", since = "1.87.0")]
661#[cfg(not(target_os = "trusty"))]
662impl From<OwnedFd> for io::PipeReader {
663 fn from(owned_fd: OwnedFd) -> Self {
664 Self(FromInner::from_inner(owned_fd))
665 }
666}
667
668#[stable(feature = "anonymous_pipe", since = "1.87.0")]
669#[cfg(not(target_os = "trusty"))]
670impl From<OwnedFd> for io::PipeWriter {
671 fn from(owned_fd: OwnedFd) -> Self {
672 Self(FromInner::from_inner(owned_fd))
673 }
674}