1 | //! Owned and borrowed Unix-like file descriptors. |
---|---|
2 | |
3 | #![stable(feature = "io_safety", since = "1.63.0")] |
4 | #![deny(unsafe_op_in_unsafe_fn)] |
5 | |
6 | use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; |
7 | #[cfg(not(target_os = "trusty"))] |
8 | use crate::fs; |
9 | use crate::marker::PhantomData; |
10 | use crate::mem::ManuallyDrop; |
11 | #[cfg(not(any( |
12 | target_arch = "wasm32", |
13 | target_env = "sgx", |
14 | target_os = "hermit", |
15 | target_os = "trusty" |
16 | )))] |
17 | use crate::sys::cvt; |
18 | #[cfg(not(target_os = "trusty"))] |
19 | use crate::sys_common::{AsInner, FromInner, IntoInner}; |
20 | use crate::{fmt, io}; |
21 | |
22 | type ValidRawFd = core::num::niche_types::NotAllOnes<RawFd>; |
23 | |
24 | /// A borrowed file descriptor. |
25 | /// |
26 | /// This has a lifetime parameter to tie it to the lifetime of something that owns the file |
27 | /// descriptor. For the duration of that lifetime, it is guaranteed that nobody will close the file |
28 | /// descriptor. |
29 | /// |
30 | /// This uses `repr(transparent)` and has the representation of a host file |
31 | /// descriptor, so it can be used in FFI in places where a file descriptor is |
32 | /// passed as an argument, it is not captured or consumed, and it never has the |
33 | /// value `-1`. |
34 | /// |
35 | /// This type does not have a [`ToOwned`][crate::borrow::ToOwned] |
36 | /// implementation. Calling `.to_owned()` on a variable of this type will call |
37 | /// it on `&BorrowedFd` and use `Clone::clone()` like `ToOwned` does for all |
38 | /// types implementing `Clone`. The result will be descriptor borrowed under |
39 | /// the same lifetime. |
40 | /// |
41 | /// To obtain an [`OwnedFd`], you can use [`BorrowedFd::try_clone_to_owned`] |
42 | /// instead, but this is not supported on all platforms. |
43 | #[derive(Copy, Clone)] |
44 | #[repr(transparent)] |
45 | #[rustc_nonnull_optimization_guaranteed] |
46 | #[stable(feature = "io_safety", since = "1.63.0")] |
47 | pub struct BorrowedFd<'fd> { |
48 | fd: ValidRawFd, |
49 | _phantom: PhantomData<&'fd OwnedFd>, |
50 | } |
51 | |
52 | /// An owned file descriptor. |
53 | /// |
54 | /// This closes the file descriptor on drop. It is guaranteed that nobody else will close the file |
55 | /// descriptor. |
56 | /// |
57 | /// This uses `repr(transparent)` and has the representation of a host file |
58 | /// descriptor, so it can be used in FFI in places where a file descriptor is |
59 | /// passed as a consumed argument or returned as an owned value, and it never |
60 | /// has the value `-1`. |
61 | /// |
62 | /// You can use [`AsFd::as_fd`] to obtain a [`BorrowedFd`]. |
63 | #[repr(transparent)] |
64 | #[rustc_nonnull_optimization_guaranteed] |
65 | #[stable(feature = "io_safety", since = "1.63.0")] |
66 | pub struct OwnedFd { |
67 | fd: ValidRawFd, |
68 | } |
69 | |
70 | impl BorrowedFd<'_> { |
71 | /// Returns a `BorrowedFd` holding the given raw file descriptor. |
72 | /// |
73 | /// # Safety |
74 | /// |
75 | /// The resource pointed to by `fd` must remain open for the duration of |
76 | /// the returned `BorrowedFd`, and it must not have the value `-1`. |
77 | #[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(msg:"fd != -1"), _phantom: PhantomData } |
83 | } |
84 | } |
85 | |
86 | impl OwnedFd { |
87 | /// Creates a new `OwnedFd` instance that shares the same underlying file |
88 | /// description as the existing `OwnedFd` instance. |
89 | #[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 | |
95 | impl BorrowedFd<'_> { |
96 | /// Creates a new `OwnedFd` instance that shares the same underlying file |
97 | /// description as the existing `BorrowedFd` instance. |
98 | #[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 | // We want to atomically duplicate this file descriptor and set the |
102 | // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This |
103 | // is a POSIX flag that was added to Linux in 2.6.24. |
104 | #[cfg(not(any(target_os = "espidf", target_os = "vita")))] |
105 | let cmd = libc::F_DUPFD_CLOEXEC; |
106 | |
107 | // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics |
108 | // will never be supported, as this is a bare metal framework with |
109 | // no capabilities for multi-process execution. While F_DUPFD is also |
110 | // not supported yet, it might be (currently it returns ENOSYS). |
111 | #[cfg(any(target_os = "espidf", target_os = "vita"))] |
112 | let cmd = libc::F_DUPFD; |
113 | |
114 | // Avoid using file descriptors below 3 as they are used for stdio |
115 | let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 3) })?; |
116 | Ok(unsafe { OwnedFd::from_raw_fd(fd) }) |
117 | } |
118 | |
119 | /// Creates a new `OwnedFd` instance that shares the same underlying file |
120 | /// description as the existing `BorrowedFd` instance. |
121 | #[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")] |
129 | impl 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")] |
137 | impl 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")] |
145 | impl 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")] |
153 | impl FromRawFd for OwnedFd { |
154 | /// Constructs a new instance of `Self` from the given raw file descriptor. |
155 | /// |
156 | /// # Safety |
157 | /// |
158 | /// The resource pointed to by `fd` must be open and suitable for assuming |
159 | /// [ownership][io-safety]. The resource must not require any cleanup other than `close`. |
160 | /// |
161 | /// [io-safety]: io#io-safety |
162 | #[inline] |
163 | #[track_caller] |
164 | unsafe fn from_raw_fd(fd: RawFd) -> Self { |
165 | Self { fd: ValidRawFd::new(fd).expect(msg:"fd != -1") } |
166 | } |
167 | } |
168 | |
169 | #[stable(feature = "io_safety", since = "1.63.0")] |
170 | impl Drop for OwnedFd { |
171 | #[inline] |
172 | fn drop(&mut self) { |
173 | unsafe { |
174 | // Note that errors are ignored when closing a file descriptor. According to POSIX 2024, |
175 | // we can and indeed should retry `close` on `EINTR` |
176 | // (https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/functions/close.html), |
177 | // but it is not clear yet how well widely-used implementations are conforming with this |
178 | // mandate since older versions of POSIX left the state of the FD after an `EINTR` |
179 | // unspecified. Ignoring errors is "fine" because some of the major Unices (in |
180 | // particular, Linux) do make sure to always close the FD, even when `close()` is |
181 | // interrupted, and the scenario is rare to begin with. If we retried on a |
182 | // not-POSIX-compliant implementation, the consequences could be really bad since we may |
183 | // close the wrong FD. Helpful link to an epic discussion by POSIX workgroup that led to |
184 | // the latest POSIX wording: http://austingroupbugs.net/view.php?id=529 |
185 | #[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")] |
199 | impl fmt::Debug for BorrowedFd<'_> { |
200 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
201 | f.debug_struct("BorrowedFd").field(name: "fd", &self.fd).finish() |
202 | } |
203 | } |
204 | |
205 | #[stable(feature = "io_safety", since = "1.63.0")] |
206 | impl fmt::Debug for OwnedFd { |
207 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
208 | f.debug_struct("OwnedFd").field(name: "fd", &self.fd).finish() |
209 | } |
210 | } |
211 | |
212 | macro_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 | |
227 | impl_is_terminal!(BorrowedFd<'_>, OwnedFd); |
228 | |
229 | /// A trait to borrow the file descriptor from an underlying object. |
230 | /// |
231 | /// This is only available on unix platforms and must be imported in order to |
232 | /// call the method. Windows platforms have a corresponding `AsHandle` and |
233 | /// `AsSocket` set of traits. |
234 | #[stable(feature = "io_safety", since = "1.63.0")] |
235 | pub trait AsFd { |
236 | /// Borrows the file descriptor. |
237 | /// |
238 | /// # Example |
239 | /// |
240 | /// ```rust,no_run |
241 | /// use std::fs::File; |
242 | /// # use std::io; |
243 | /// # #[cfg(any(unix, target_os = "wasi"))] |
244 | /// # use std::os::fd::{AsFd, BorrowedFd}; |
245 | /// |
246 | /// let mut f = File::open("foo.txt")?; |
247 | /// # #[cfg(any(unix, target_os = "wasi"))] |
248 | /// let borrowed_fd: BorrowedFd<'_> = f.as_fd(); |
249 | /// # Ok::<(), io::Error>(()) |
250 | /// ``` |
251 | #[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")] |
256 | impl<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")] |
264 | impl<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")] |
272 | impl 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")] |
280 | impl AsFd for OwnedFd { |
281 | #[inline] |
282 | fn as_fd(&self) -> BorrowedFd<'_> { |
283 | // Safety: `OwnedFd` and `BorrowedFd` have the same validity |
284 | // invariants, and the `BorrowedFd` is bounded by the lifetime |
285 | // of `&self`. |
286 | 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"))] |
292 | impl 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"))] |
301 | impl From<fs::File> for OwnedFd { |
302 | /// Takes ownership of a [`File`](fs::File)'s underlying file descriptor. |
303 | #[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"))] |
311 | impl From<OwnedFd> for fs::File { |
312 | /// Returns a [`File`](fs::File) that takes ownership of the given |
313 | /// file descriptor. |
314 | #[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"))] |
322 | impl 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"))] |
331 | impl From<crate::net::TcpStream> for OwnedFd { |
332 | /// Takes ownership of a [`TcpStream`](crate::net::TcpStream)'s socket file descriptor. |
333 | #[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"))] |
341 | impl 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"))] |
352 | impl 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"))] |
361 | impl From<crate::net::TcpListener> for OwnedFd { |
362 | /// Takes ownership of a [`TcpListener`](crate::net::TcpListener)'s socket file descriptor. |
363 | #[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"))] |
371 | impl 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"))] |
382 | impl 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"))] |
391 | impl From<crate::net::UdpSocket> for OwnedFd { |
392 | /// Takes ownership of a [`UdpSocket`](crate::net::UdpSocket)'s file descriptor. |
393 | #[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"))] |
401 | impl 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")] |
411 | /// This impl allows implementing traits that require `AsFd` on Arc. |
412 | /// ``` |
413 | /// # #[cfg(any(unix, target_os = "wasi"))] mod group_cfg { |
414 | /// # #[cfg(target_os = "wasi")] |
415 | /// # use std::os::wasi::io::AsFd; |
416 | /// # #[cfg(unix)] |
417 | /// # use std::os::unix::io::AsFd; |
418 | /// use std::net::UdpSocket; |
419 | /// use std::sync::Arc; |
420 | /// |
421 | /// trait MyTrait: AsFd {} |
422 | /// impl MyTrait for Arc<UdpSocket> {} |
423 | /// impl MyTrait for Box<UdpSocket> {} |
424 | /// # } |
425 | /// ``` |
426 | impl<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")] |
434 | impl<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")] |
442 | impl<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")] |
450 | impl<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")] |
458 | impl AsFd for io::Stdin { |
459 | #[inline] |
460 | fn as_fd(&self) -> BorrowedFd<'_> { |
461 | unsafe { BorrowedFd::borrow_raw(fd:0) } |
462 | } |
463 | } |
464 | |
465 | #[stable(feature = "io_safety", since = "1.63.0")] |
466 | impl<'a> AsFd for io::StdinLock<'a> { |
467 | #[inline] |
468 | fn as_fd(&self) -> BorrowedFd<'_> { |
469 | // SAFETY: user code should not close stdin out from under the standard library |
470 | unsafe { BorrowedFd::borrow_raw(fd:0) } |
471 | } |
472 | } |
473 | |
474 | #[stable(feature = "io_safety", since = "1.63.0")] |
475 | impl AsFd for io::Stdout { |
476 | #[inline] |
477 | fn as_fd(&self) -> BorrowedFd<'_> { |
478 | unsafe { BorrowedFd::borrow_raw(fd:1) } |
479 | } |
480 | } |
481 | |
482 | #[stable(feature = "io_safety", since = "1.63.0")] |
483 | impl<'a> AsFd for io::StdoutLock<'a> { |
484 | #[inline] |
485 | fn as_fd(&self) -> BorrowedFd<'_> { |
486 | // SAFETY: user code should not close stdout out from under the standard library |
487 | unsafe { BorrowedFd::borrow_raw(fd:1) } |
488 | } |
489 | } |
490 | |
491 | #[stable(feature = "io_safety", since = "1.63.0")] |
492 | impl AsFd for io::Stderr { |
493 | #[inline] |
494 | fn as_fd(&self) -> BorrowedFd<'_> { |
495 | unsafe { BorrowedFd::borrow_raw(fd:2) } |
496 | } |
497 | } |
498 | |
499 | #[stable(feature = "io_safety", since = "1.63.0")] |
500 | impl<'a> AsFd for io::StderrLock<'a> { |
501 | #[inline] |
502 | fn as_fd(&self) -> BorrowedFd<'_> { |
503 | // SAFETY: user code should not close stderr out from under the standard library |
504 | unsafe { BorrowedFd::borrow_raw(fd:2) } |
505 | } |
506 | } |
507 | |
508 | #[stable(feature = "anonymous_pipe", since = "1.87.0")] |
509 | #[cfg(not(target_os = "trusty"))] |
510 | impl 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"))] |
518 | impl 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"))] |
526 | impl 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"))] |
534 | impl 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"))] |
542 | impl 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"))] |
550 | impl From<OwnedFd> for io::PipeWriter { |
551 | fn from(owned_fd: OwnedFd) -> Self { |
552 | Self(FromInner::from_inner(owned_fd)) |
553 | } |
554 | } |
555 |
Definitions
Learn Rust with the experts
Find out more