Coverage Report

Created: 2025-11-11 06:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/io-lifetimes-2.0.4/src/views.rs
Line
Count
Source
1
//! Typed views using temporary objects.
2
//!
3
//! This module defines the return types for [`AsFilelike::as_filelike_view`]
4
//! and [`AsSocketlike::as_socketlike_view`].
5
//!
6
//! [`AsSocketlike::as_socketlike_view`]: crate::AsSocketlike::as_socketlike_view
7
8
use crate::raw::{
9
    AsRawFilelike, AsRawSocketlike, FromRawFilelike, FromRawSocketlike, IntoRawFilelike,
10
    IntoRawSocketlike, RawFilelike, RawSocketlike,
11
};
12
#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
13
use crate::OwnedFd;
14
use crate::{
15
    AsFilelike, AsSocketlike, FromFilelike, FromSocketlike, IntoFilelike, IntoSocketlike,
16
    OwnedFilelike, OwnedSocketlike,
17
};
18
#[cfg(windows)]
19
use crate::{OwnedHandle, OwnedSocket};
20
use std::fmt;
21
use std::marker::PhantomData;
22
use std::mem::ManuallyDrop;
23
use std::ops::Deref;
24
25
/// Declare that a type is safe to use in a [`FilelikeView`].
26
///
27
/// # Safety
28
///
29
/// Types implementing this trait declare that if they are constructed with
30
/// [`FromFilelike`] and consumed with [`IntoFilelike`], their `IntoFilelike`
31
/// will return the same `OwnedFd` value that was passed to their
32
/// `FromFilelike`.
33
pub unsafe trait FilelikeViewType: FromFilelike + IntoFilelike {}
34
35
/// Declare that a type is safe to use in a [`SocketlikeView`].
36
///
37
/// # Safety
38
///
39
/// Types implementing this trait declare that if they are constructed with
40
/// [`FromSocketlike`] and consumed with [`IntoSocketlike`], their
41
/// `IntoSocketlike` will return the same `OwnedFd` value that was passed to
42
/// their `FromSocketlike`.
43
pub unsafe trait SocketlikeViewType: FromSocketlike + IntoSocketlike {}
44
45
/// A non-owning view of a resource which dereferences to a `&Target` or
46
/// `&mut Target`. These are returned by [`AsFilelike::as_filelike_view`].
47
pub struct FilelikeView<'filelike, Target: FilelikeViewType> {
48
    /// The value to dereference to. This is a `ManuallyDrop` so that we can
49
    /// consume it in our `Drop` impl.
50
    target: ManuallyDrop<Target>,
51
52
    /// `FilelikeViewType` implementors guarantee that their `Into<OwnedFd>`
53
    /// returns the same fd as their `From<OwnedFd>` gave them. This field
54
    /// allows us to verify this.
55
    #[cfg(debug_assertions)]
56
    orig: RawFilelike,
57
58
    /// This field exists because we don't otherwise explicitly use
59
    /// `'filelike`.
60
    _phantom: PhantomData<&'filelike OwnedFilelike>,
61
}
62
63
/// A non-owning view of a resource which dereferences to a `&Target` or
64
/// `&mut Target`. These are returned by [`AsSocketlike::as_socketlike_view`].
65
pub struct SocketlikeView<'socketlike, Target: SocketlikeViewType> {
66
    /// The value to dereference to. This is a `ManuallyDrop` so that we can
67
    /// consume it in our `Drop` impl.
68
    target: ManuallyDrop<Target>,
69
70
    /// `SocketlikeViewType` implementors guarantee that their `Into<OwnedFd>`
71
    /// returns the same fd as their `From<OwnedFd>` gave them. This field
72
    /// allows us to verify this.
73
    #[cfg(debug_assertions)]
74
    orig: RawSocketlike,
75
76
    /// This field exists because we don't otherwise explicitly use
77
    /// `'socketlike`.
78
    _phantom: PhantomData<&'socketlike OwnedSocketlike>,
79
}
80
81
impl<Target: FilelikeViewType> FilelikeView<'_, Target> {
82
    /// Construct a temporary `Target` and wrap it in a `FilelikeView` object.
83
    #[inline]
84
0
    pub(crate) fn new<T: AsFilelike>(filelike: &T) -> Self {
85
        // Safety: The returned `FilelikeView` is scoped to the lifetime of
86
        // `filelike`, which we've borrowed here, so the view won't outlive
87
        // the object it's borrowed from.
88
0
        unsafe { Self::view_raw(filelike.as_filelike().as_raw_filelike()) }
89
0
    }
Unexecuted instantiation: <io_lifetimes::views::FilelikeView<std::fs::File>>::new::<std::fs::File>
Unexecuted instantiation: <io_lifetimes::views::FilelikeView<std::fs::File>>::new::<std::os::fd::owned::BorrowedFd>
90
91
    /// Construct a temporary `Target` from raw and wrap it in a `FilelikeView`
92
    /// object.
93
    ///
94
    /// # Safety
95
    ///
96
    /// `raw` must be a valid raw filelike referencing a resource that outlives
97
    /// the resulting view.
98
    #[inline]
99
0
    pub unsafe fn view_raw(raw: RawFilelike) -> Self {
100
0
        let owned = OwnedFilelike::from_raw_filelike(raw);
101
0
        Self {
102
0
            target: ManuallyDrop::new(Target::from_filelike(owned)),
103
0
            #[cfg(debug_assertions)]
104
0
            orig: raw,
105
0
            _phantom: PhantomData,
106
0
        }
107
0
    }
108
}
109
110
impl<Target: SocketlikeViewType> SocketlikeView<'_, Target> {
111
    /// Construct a temporary `Target` and wrap it in a `SocketlikeView`
112
    /// object.
113
    #[inline]
114
    pub(crate) fn new<T: AsSocketlike>(socketlike: &T) -> Self {
115
        // Safety: The returned `SocketlikeView` is scoped to the lifetime of
116
        // `socketlike`, which we've borrowed here, so the view won't outlive
117
        // the object it's borrowed from.
118
        unsafe { Self::view_raw(socketlike.as_socketlike().as_raw_socketlike()) }
119
    }
120
121
    /// Construct a temporary `Target` from raw and wrap it in a
122
    /// `SocketlikeView` object.
123
    ///
124
    /// # Safety
125
    ///
126
    /// `raw` must be a valid raw socketlike referencing a resource that
127
    /// outlives the resulting view.
128
    #[inline]
129
    pub unsafe fn view_raw(raw: RawSocketlike) -> Self {
130
        let owned = OwnedSocketlike::from_raw_socketlike(raw);
131
        Self {
132
            target: ManuallyDrop::new(Target::from_socketlike(owned)),
133
            #[cfg(debug_assertions)]
134
            orig: raw,
135
            _phantom: PhantomData,
136
        }
137
    }
138
}
139
140
impl<Target: FilelikeViewType> Deref for FilelikeView<'_, Target> {
141
    type Target = Target;
142
143
    #[inline]
144
0
    fn deref(&self) -> &Self::Target {
145
0
        &self.target
146
0
    }
147
}
148
149
impl<Target: SocketlikeViewType> Deref for SocketlikeView<'_, Target> {
150
    type Target = Target;
151
152
    #[inline]
153
    fn deref(&self) -> &Self::Target {
154
        &self.target
155
    }
156
}
157
158
impl<Target: FilelikeViewType> Drop for FilelikeView<'_, Target> {
159
    #[inline]
160
0
    fn drop(&mut self) {
161
        // Use `Into*` to consume `self.target` without freeing its resource.
162
        //
163
        // Safety: Using `ManuallyDrop::take` requires us to ensure that
164
        // `self.target` is not used again. We don't use it again here, and
165
        // this is the `drop` function, so we know it's not used afterward.
166
0
        let _raw = unsafe { ManuallyDrop::take(&mut self.target) }
167
0
            .into_filelike()
168
0
            .into_raw_filelike();
169
170
        #[cfg(debug_assertions)]
171
        debug_assert_eq!(self.orig, _raw);
172
0
    }
173
}
174
175
impl<Target: SocketlikeViewType> Drop for SocketlikeView<'_, Target> {
176
    #[inline]
177
    fn drop(&mut self) {
178
        // Use `Into*` to consume `self.target` without freeing its resource.
179
        //
180
        // Safety: Using `ManuallyDrop::take` requires us to ensure that
181
        // `self.target` is not used again. We don't use it again here, and
182
        // this is the `drop` function, so we know it's not used afterward.
183
        let _raw = unsafe { ManuallyDrop::take(&mut self.target) }
184
            .into_socketlike()
185
            .into_raw_socketlike();
186
187
        #[cfg(debug_assertions)]
188
        debug_assert_eq!(self.orig, _raw);
189
    }
190
}
191
192
impl<Target: FilelikeViewType> fmt::Debug for FilelikeView<'_, Target> {
193
    #[allow(clippy::missing_inline_in_public_items)]
194
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195
        f.debug_struct("FilelikeView")
196
            .field("target", &*self)
197
            .finish()
198
    }
199
}
200
201
impl<Target: SocketlikeViewType> fmt::Debug for SocketlikeView<'_, Target> {
202
    #[allow(clippy::missing_inline_in_public_items)]
203
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204
        f.debug_struct("SocketlikeView")
205
            .field("target", &*self)
206
            .finish()
207
    }
208
}
209
210
#[cfg(any(unix, target_os = "wasi", target_os = "hermit"))]
211
unsafe impl FilelikeViewType for OwnedFd {}
212
#[cfg(windows)]
213
unsafe impl FilelikeViewType for OwnedHandle {}
214
#[cfg(windows)]
215
unsafe impl SocketlikeViewType for OwnedSocket {}
216
unsafe impl FilelikeViewType for std::fs::File {}
217
unsafe impl SocketlikeViewType for std::net::TcpStream {}
218
unsafe impl SocketlikeViewType for std::net::TcpListener {}
219
unsafe impl SocketlikeViewType for std::net::UdpSocket {}
220
#[cfg(unix)]
221
unsafe impl SocketlikeViewType for std::os::unix::net::UnixStream {}
222
#[cfg(unix)]
223
unsafe impl SocketlikeViewType for std::os::unix::net::UnixListener {}
224
225
#[cfg(unix)]
226
unsafe impl SocketlikeViewType for std::os::unix::net::UnixDatagram {}
227
#[cfg(not(any(target_os = "wasi", target_os = "hermit")))]
228
#[cfg(feature = "os_pipe")]
229
unsafe impl FilelikeViewType for os_pipe::PipeWriter {}
230
#[cfg(not(any(target_os = "wasi", target_os = "hermit")))]
231
#[cfg(feature = "os_pipe")]
232
unsafe impl FilelikeViewType for os_pipe::PipeReader {}
233
234
#[cfg(not(any(target_os = "wasi", target_os = "hermit")))]
235
#[cfg(feature = "socket2")]
236
unsafe impl SocketlikeViewType for socket2::Socket {}
237
238
#[cfg(not(any(target_os = "wasi", target_os = "hermit")))]
239
#[cfg(feature = "async-std")]
240
unsafe impl SocketlikeViewType for async_std::net::TcpStream {}
241
#[cfg(not(any(target_os = "wasi", target_os = "hermit")))]
242
#[cfg(feature = "async-std")]
243
unsafe impl SocketlikeViewType for async_std::net::TcpListener {}
244
#[cfg(not(any(target_os = "wasi", target_os = "hermit")))]
245
#[cfg(feature = "async-std")]
246
unsafe impl SocketlikeViewType for async_std::net::UdpSocket {}
247
#[cfg(unix)]
248
#[cfg(feature = "async-std")]
249
unsafe impl SocketlikeViewType for async_std::os::unix::net::UnixStream {}
250
#[cfg(unix)]
251
#[cfg(feature = "async-std")]
252
unsafe impl SocketlikeViewType for async_std::os::unix::net::UnixListener {}
253
#[cfg(unix)]
254
#[cfg(feature = "async-std")]
255
unsafe impl SocketlikeViewType for async_std::os::unix::net::UnixDatagram {}
256
257
#[cfg(feature = "mio")]
258
unsafe impl SocketlikeViewType for mio::net::TcpStream {}
259
#[cfg(feature = "mio")]
260
unsafe impl SocketlikeViewType for mio::net::TcpListener {}
261
#[cfg(feature = "mio")]
262
unsafe impl SocketlikeViewType for mio::net::UdpSocket {}
263
#[cfg(unix)]
264
#[cfg(feature = "mio")]
265
unsafe impl SocketlikeViewType for mio::net::UnixDatagram {}
266
#[cfg(unix)]
267
#[cfg(feature = "mio")]
268
unsafe impl SocketlikeViewType for mio::net::UnixListener {}
269
#[cfg(unix)]
270
#[cfg(feature = "mio")]
271
unsafe impl SocketlikeViewType for mio::net::UnixStream {}
272
#[cfg(unix)]
273
#[cfg(feature = "mio")]
274
unsafe impl FilelikeViewType for mio::unix::pipe::Receiver {}
275
#[cfg(unix)]
276
#[cfg(feature = "mio")]
277
unsafe impl FilelikeViewType for mio::unix::pipe::Sender {}