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