io_lifetimes/
portability.rs

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.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.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}