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