1//! Portability abstractions over `Owned*` and `Borrowed*`.
2//!
3//! On Unix, "everything is a file descriptor". On Windows, file/pipe/process
4//! handles are distinct from socket descriptors. This file provides a minimal
5//! layer of portability over this difference.
6
7use crate::views::{FilelikeView, FilelikeViewType, SocketlikeView, SocketlikeViewType};
8#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
9use crate::{AsFd, BorrowedFd, OwnedFd};
10#[cfg(windows)]
11use crate::{AsHandle, AsSocket, BorrowedHandle, BorrowedSocket, OwnedHandle, OwnedSocket};
12
13/// A reference to a filelike object.
14///
15/// This is a portability abstraction over Unix-like [`BorrowedFd`] and
16/// Windows' `BorrowedHandle`.
17#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
18pub type BorrowedFilelike<'filelike> = BorrowedFd<'filelike>;
19
20/// A reference to a filelike object.
21///
22/// This is a portability abstraction over Unix-like `BorrowedFd` and
23/// Windows' [`BorrowedHandle`].
24#[cfg(windows)]
25pub type BorrowedFilelike<'filelike> = BorrowedHandle<'filelike>;
26
27/// A reference to a socketlike object.
28///
29/// This is a portability abstraction over Unix-like [`BorrowedFd`] and
30/// Windows' `BorrowedSocket`.
31#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
32pub type BorrowedSocketlike<'socketlike> = BorrowedFd<'socketlike>;
33
34/// A reference to a socketlike object.
35///
36/// This is a portability abstraction over Unix-like `BorrowedFd` and
37/// Windows' [`BorrowedSocket`].
38#[cfg(windows)]
39pub type BorrowedSocketlike<'socketlike> = BorrowedSocket<'socketlike>;
40
41/// An owned filelike object.
42///
43/// This is a portability abstraction over Unix-like [`OwnedFd`] and
44/// Windows' `OwnedHandle`.
45#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
46pub type OwnedFilelike = OwnedFd;
47
48/// An owned filelike object.
49///
50/// This is a portability abstraction over Unix-like `OwnedFd` and
51/// Windows' [`OwnedHandle`].
52#[cfg(windows)]
53pub type OwnedFilelike = OwnedHandle;
54
55/// An owned socketlike object.
56///
57/// This is a portability abstraction over Unix-like [`OwnedFd`] and
58/// Windows' `OwnedSocket`.
59#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
60pub type OwnedSocketlike = OwnedFd;
61
62/// An owned socketlike object.
63///
64/// This is a portability abstraction over Unix-like `OwnedFd` and
65/// Windows' [`OwnedSocket`].
66#[cfg(windows)]
67pub type OwnedSocketlike = OwnedSocket;
68
69/// A portable trait to borrow a reference from an underlying filelike object.
70///
71/// This is a portability abstraction over Unix-like [`AsFd`] and Windows'
72/// `AsHandle`. It also provides the `as_filelike_view` convenience function
73/// providing typed views.
74#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
75pub trait AsFilelike: AsFd {
76 /// Borrows the reference.
77 ///
78 /// # Example
79 ///
80 /// ```rust,no_run
81 /// use std::fs::File;
82 /// # use std::io;
83 /// use io_lifetimes::{AsFilelike, BorrowedFilelike};
84 ///
85 /// let mut f = File::open("foo.txt")?;
86 /// let borrowed_filelike: BorrowedFilelike<'_> = f.as_filelike();
87 /// # Ok::<(), io::Error>(())
88 /// ```
89 fn as_filelike(&self) -> BorrowedFilelike<'_>;
90
91 /// Return a borrowing view of a resource which dereferences to a
92 /// `&Target`.
93 ///
94 /// Note that [`Read`] or [`Write`] require `&mut Target`, but in some
95 /// cases, such as [`File`], `Read` and `Write` are implemented for
96 /// `&Target` in addition to `Target`, and you can get a `&mut &Target`
97 /// by doing `&*` on the resuting view, like this:
98 ///
99 /// ```rust,ignore
100 /// let v = f.as_filelike_view::<std::fs::File>();
101 /// (&*v).read(&mut buf).unwrap();
102 /// ```
103 ///
104 /// [`File`]: std::fs::File
105 /// [`Read`]: std::io::Read
106 /// [`Write`]: std::io::Write
107 fn as_filelike_view<Target: FilelikeViewType>(&self) -> FilelikeView<'_, Target>;
108}
109
110#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
111impl<T: AsFd> AsFilelike for T {
112 #[inline]
113 fn as_filelike(&self) -> BorrowedFilelike<'_> {
114 self.as_fd()
115 }
116
117 #[inline]
118 fn as_filelike_view<Target: FilelikeViewType>(&self) -> FilelikeView<'_, Target> {
119 FilelikeView::new(self)
120 }
121}
122
123/// A portable trait to borrow a reference from an underlying filelike object.
124///
125/// This is a portability abstraction over Unix-like `AsFd` and Windows'
126/// [`AsHandle`]. It also provides the `as_filelike_view` convenience function
127/// providing typed views.
128#[cfg(windows)]
129pub trait AsFilelike: AsHandle {
130 /// Borrows the reference.
131 ///
132 /// # Example
133 ///
134 /// ```rust,no_run
135 /// use std::fs::File;
136 /// # use std::io;
137 /// use io_lifetimes::{AsFilelike, BorrowedFilelike};
138 ///
139 /// let mut f = File::open("foo.txt")?;
140 /// let borrowed_filelike: BorrowedFilelike<'_> = f.as_filelike();
141 /// # Ok::<(), io::Error>(())
142 /// ```
143 fn as_filelike(&self) -> BorrowedFilelike<'_>;
144
145 /// Return a borrowing view of a resource which dereferences to a
146 /// `&Target`.
147 ///
148 /// Note that [`Read`] or [`Write`] require `&mut Target`, but in some
149 /// cases, such as [`File`], `Read` and `Write` are implemented for
150 /// `&Target` in addition to `Target`, and you can get a `&mut &Target`
151 /// by doing `&*` on the resuting view, like this:
152 ///
153 /// ```rust,ignore
154 /// let v = f.as_filelike_view::<std::fs::File>();
155 /// (&*v).read(&mut buf).unwrap();
156 /// ```
157 ///
158 /// [`File`]: std::fs::File
159 /// [`Read`]: std::io::Read
160 /// [`Write`]: std::io::Write
161 fn as_filelike_view<Target: FilelikeViewType>(&self) -> FilelikeView<'_, Target>;
162}
163
164#[cfg(windows)]
165impl<T: AsHandle> AsFilelike for T {
166 #[inline]
167 fn as_filelike(&self) -> BorrowedFilelike<'_> {
168 self.as_handle()
169 }
170
171 #[inline]
172 fn as_filelike_view<Target: FilelikeViewType>(&self) -> FilelikeView<'_, Target> {
173 FilelikeView::new(self)
174 }
175}
176
177/// A portable trait to borrow a reference from an underlying socketlike
178/// object.
179///
180/// This is a portability abstraction over Unix-like [`AsFd`] and Windows'
181/// `AsSocket`. It also provides the `as_socketlike_view` convenience
182/// function providing typed views.
183#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
184pub trait AsSocketlike: AsFd {
185 /// Borrows the reference.
186 fn as_socketlike(&self) -> BorrowedSocketlike<'_>;
187
188 /// Return a borrowing view of a resource which dereferences to a
189 /// `&Target`.
190 ///
191 /// Note that [`Read`] or [`Write`] require `&mut Target`, but in some
192 /// cases, such as [`TcpStream`], `Read` and `Write` are implemented
193 /// for `&Target` in addition to `Target`, and you can get a `&mut
194 /// &Target` by doing `&*` on the resuting view, like this:
195 ///
196 /// ```rust,ignore
197 /// let v = s.as_socketlike_view::<std::net::TcpStream>();
198 /// (&*v).read(&mut buf).unwrap();
199 /// ```
200 ///
201 /// [`TcpStream`]: std::net::TcpStream
202 /// [`Read`]: std::io::Read
203 /// [`Write`]: std::io::Write
204 fn as_socketlike_view<Target: SocketlikeViewType>(&self) -> SocketlikeView<'_, Target>;
205}
206
207#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
208impl<T: AsFd> AsSocketlike for T {
209 #[inline]
210 fn as_socketlike(&self) -> BorrowedSocketlike<'_> {
211 self.as_fd()
212 }
213
214 #[inline]
215 fn as_socketlike_view<Target: SocketlikeViewType>(&self) -> SocketlikeView<'_, Target> {
216 SocketlikeView::new(self)
217 }
218}
219
220/// A portable trait to borrow a reference from an underlying socketlike
221/// object.
222///
223/// This is a portability abstraction over Unix-like `AsFd` and Windows'
224/// [`AsSocket`]. It also provides the `as_socketlike_view` convenience
225/// function providing typed views.
226#[cfg(windows)]
227pub trait AsSocketlike: AsSocket {
228 /// Borrows the reference.
229 fn as_socketlike(&self) -> BorrowedSocketlike;
230
231 /// Return a borrowing view of a resource which dereferences to a
232 /// `&Target`.
233 ///
234 /// Note that [`Read`] or [`Write`] require `&mut Target`, but in some
235 /// cases, such as [`TcpStream`], `Read` and `Write` are implemented
236 /// for `&Target` in addition to `Target`, and you can get a `&mut
237 /// &Target` by doing `&*` on the resuting view, like this:
238 ///
239 /// ```rust,ignore
240 /// let v = s.as_socketlike_view::<std::net::TcpStream>();
241 /// (&*v).read(&mut buf).unwrap();
242 /// ```
243 ///
244 /// [`TcpStream`]: std::net::TcpStream
245 fn as_socketlike_view<Target: SocketlikeViewType>(&self) -> SocketlikeView<'_, Target>;
246}
247
248#[cfg(windows)]
249impl<T: AsSocket> AsSocketlike for T {
250 #[inline]
251 fn as_socketlike(&self) -> BorrowedSocketlike<'_> {
252 self.as_socket()
253 }
254
255 #[inline]
256 fn as_socketlike_view<Target: SocketlikeViewType>(&self) -> SocketlikeView<'_, Target> {
257 SocketlikeView::new(self)
258 }
259}
260
261/// A portable trait to express the ability to consume an object and acquire
262/// ownership of its filelike object.
263///
264/// This is a portability abstraction over Unix-like [`Into<OwnedFd>`] and
265/// Windows' `Into<OwnedHandle>`.
266#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
267pub trait IntoFilelike: Into<OwnedFd> {
268 /// Consumes this object, returning the underlying filelike object.
269 ///
270 /// # Example
271 ///
272 /// ```rust,no_run
273 /// use std::fs::File;
274 /// # use std::io;
275 /// use io_lifetimes::{IntoFilelike, OwnedFilelike};
276 ///
277 /// let f = File::open("foo.txt")?;
278 /// let owned_filelike: OwnedFilelike = f.into_filelike();
279 /// # Ok::<(), io::Error>(())
280 /// ```
281 fn into_filelike(self) -> OwnedFilelike;
282}
283
284#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
285impl<T: Into<OwnedFd>> IntoFilelike for T {
286 #[inline]
287 fn into_filelike(self) -> OwnedFilelike {
288 self.into()
289 }
290}
291
292/// A portable trait to express the ability to consume an object and acquire
293/// ownership of its filelike object.
294///
295/// This is a portability abstraction over Unix-like `Into<OwnedFd>` and
296/// Windows' [`Into<OwnedHandle>`].
297#[cfg(windows)]
298pub trait IntoFilelike: Into<OwnedHandle> {
299 /// Consumes this object, returning the underlying filelike object.
300 fn into_filelike(self) -> OwnedFilelike;
301}
302
303#[cfg(windows)]
304impl<T: Into<OwnedHandle>> IntoFilelike for T {
305 #[inline]
306 fn into_filelike(self) -> OwnedFilelike {
307 self.into()
308 }
309}
310
311/// A portable trait to express the ability to consume an object and acquire
312/// ownership of its socketlike object.
313///
314/// This is a portability abstraction over Unix-like [`Into<OwnedFd>`] and
315/// Windows' `Into<OwnedSocket>`.
316#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
317pub trait IntoSocketlike: Into<OwnedFd> {
318 /// Consumes this object, returning the underlying socketlike object.
319 fn into_socketlike(self) -> OwnedSocketlike;
320}
321
322#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
323impl<T: Into<OwnedFd>> IntoSocketlike for T {
324 #[inline]
325 fn into_socketlike(self) -> OwnedSocketlike {
326 self.into()
327 }
328}
329
330/// A portable trait to express the ability to consume an object and acquire
331/// ownership of its socketlike object.
332///
333/// This is a portability abstraction over Unix-like `Into<OwnedFd>` and
334/// Windows' [`Into<OwnedSocket>`].
335#[cfg(windows)]
336pub trait IntoSocketlike: Into<OwnedSocket> {
337 /// Consumes this object, returning the underlying socketlike object.
338 ///
339 /// # Example
340 ///
341 /// ```rust,no_run
342 /// use std::fs::File;
343 /// # use std::io;
344 /// use io_lifetimes::{IntoFilelike, OwnedFilelike};
345 ///
346 /// let f = File::open("foo.txt")?;
347 /// let owned_filelike: OwnedFilelike = f.into_filelike();
348 /// # Ok::<(), io::Error>(())
349 /// ```
350 fn into_socketlike(self) -> OwnedSocketlike;
351}
352
353#[cfg(windows)]
354impl<T: Into<OwnedSocket>> IntoSocketlike for T {
355 #[inline]
356 fn into_socketlike(self) -> OwnedSocketlike {
357 self.into()
358 }
359}
360
361/// A portable trait to express the ability to construct an object from a
362/// filelike object.
363///
364/// This is a portability abstraction over Unix-like [`From<OwnedFd>`] and
365/// Windows' `From<OwnedHandle>`. It also provides the `from_into_filelike`
366/// convenience function providing simplified from+into conversions.
367#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
368pub trait FromFilelike: From<OwnedFd> {
369 /// Constructs a new instance of `Self` from the given filelike object.
370 ///
371 /// # Example
372 ///
373 /// ```rust,no_run
374 /// use std::fs::File;
375 /// # use std::io;
376 /// use io_lifetimes::{FromFilelike, IntoFilelike, OwnedFilelike};
377 ///
378 /// let f = File::open("foo.txt")?;
379 /// let owned_filelike: OwnedFilelike = f.into_filelike();
380 /// let f = File::from_filelike(owned_filelike);
381 /// # Ok::<(), io::Error>(())
382 /// ```
383 fn from_filelike(owned: OwnedFilelike) -> Self;
384
385 /// Constructs a new instance of `Self` from the given filelike object
386 /// converted from `into_owned`.
387 ///
388 /// # Example
389 ///
390 /// ```rust,no_run
391 /// use std::fs::File;
392 /// # use std::io;
393 /// use io_lifetimes::{FromFilelike, IntoFilelike};
394 ///
395 /// let f = File::open("foo.txt")?;
396 /// let f = File::from_into_filelike(f);
397 /// # Ok::<(), io::Error>(())
398 /// ```
399 fn from_into_filelike<Owned: IntoFilelike>(owned: Owned) -> Self;
400}
401
402#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
403impl<T: From<OwnedFd>> FromFilelike for T {
404 #[inline]
405 fn from_filelike(owned: OwnedFilelike) -> Self {
406 Self::from(owned)
407 }
408
409 #[inline]
410 fn from_into_filelike<Owned: IntoFilelike>(owned: Owned) -> Self {
411 Self::from_filelike(owned:owned.into_filelike())
412 }
413}
414
415/// A portable trait to express the ability to construct an object from a
416/// filelike object.
417///
418/// This is a portability abstraction over Unix-like `From<OwnedFd>` and
419/// Windows' [`From<OwnedHandle>`]. It also provides the `from_into_filelike`
420/// convenience function providing simplified from+into conversions.
421#[cfg(windows)]
422pub trait FromFilelike: From<OwnedHandle> {
423 /// Constructs a new instance of `Self` from the given filelike object.
424 ///
425 /// # Example
426 ///
427 /// ```rust,no_run
428 /// use std::fs::File;
429 /// # use std::io;
430 /// use io_lifetimes::{FromFilelike, IntoFilelike, OwnedFilelike};
431 ///
432 /// let f = File::open("foo.txt")?;
433 /// let owned_filelike: OwnedFilelike = f.into_filelike();
434 /// let f = File::from_filelike(owned_filelike);
435 /// # Ok::<(), io::Error>(())
436 /// ```
437 fn from_filelike(owned: OwnedFilelike) -> Self;
438
439 /// Constructs a new instance of `Self` from the given filelike object
440 /// converted from `into_owned`.
441 ///
442 /// # Example
443 ///
444 /// ```rust,no_run
445 /// use std::fs::File;
446 /// # use std::io;
447 /// use io_lifetimes::{FromFilelike, IntoFilelike};
448 ///
449 /// let f = File::open("foo.txt")?;
450 /// let f = File::from_into_filelike(f);
451 /// # Ok::<(), io::Error>(())
452 /// ```
453 fn from_into_filelike<Owned: IntoFilelike>(owned: Owned) -> Self;
454}
455
456#[cfg(windows)]
457impl<T: From<OwnedHandle>> FromFilelike for T {
458 #[inline]
459 fn from_filelike(owned: OwnedFilelike) -> Self {
460 Self::from(owned)
461 }
462
463 #[inline]
464 fn from_into_filelike<Owned: IntoFilelike>(owned: Owned) -> Self {
465 Self::from_filelike(owned.into_filelike())
466 }
467}
468
469/// A portable trait to express the ability to construct an object from a
470/// socketlike object.
471///
472/// This is a portability abstraction over Unix-like [`From<OwnedFd>`] and
473/// Windows' `From<OwnedSocketFrom<OwnedSocket>` It also provides the
474/// `from_into_socketlike` convenience function providing simplified from+into
475/// conversions.
476#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
477pub trait FromSocketlike: From<OwnedFd> {
478 /// Constructs a new instance of `Self` from the given socketlike object.
479 fn from_socketlike(owned: OwnedSocketlike) -> Self;
480
481 /// Constructs a new instance of `Self` from the given socketlike object
482 /// converted from `into_owned`.
483 fn from_into_socketlike<Owned: IntoSocketlike>(owned: Owned) -> Self;
484}
485
486#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
487impl<T: From<OwnedFd>> FromSocketlike for T {
488 #[inline]
489 fn from_socketlike(owned: OwnedSocketlike) -> Self {
490 Self::from(owned)
491 }
492
493 #[inline]
494 fn from_into_socketlike<Owned: IntoSocketlike>(owned: Owned) -> Self {
495 Self::from_socketlike(owned:owned.into_socketlike())
496 }
497}
498
499/// A portable trait to express the ability to construct an object from a
500/// socketlike object.
501///
502/// This is a portability abstraction over Unix-like `From<OwnedFd>` and
503/// Windows' [`From<OwnedSocket>`]. It also provides the `from_into_socketlike`
504/// convenience function providing simplified from+into conversions.
505#[cfg(windows)]
506pub trait FromSocketlike: From<OwnedSocket> {
507 /// Constructs a new instance of `Self` from the given socketlike object.
508 fn from_socketlike(owned: OwnedSocketlike) -> Self;
509
510 /// Constructs a new instance of `Self` from the given socketlike object
511 /// converted from `into_owned`.
512 fn from_into_socketlike<Owned: IntoSocketlike>(owned: Owned) -> Self;
513}
514
515#[cfg(windows)]
516impl<T: From<OwnedSocket>> FromSocketlike for T {
517 #[inline]
518 fn from_socketlike(owned: OwnedSocketlike) -> Self {
519 Self::from(owned)
520 }
521
522 #[inline]
523 fn from_into_socketlike<Owned: IntoSocketlike>(owned: Owned) -> Self {
524 Self::from_socketlike(owned.into_socketlike())
525 }
526}
527