Coverage Report

Created: 2026-11-03 08:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/hyper-1.9.0/src/rt/io.rs
Line
Count
Source
1
use std::fmt;
2
use std::mem::MaybeUninit;
3
use std::ops::DerefMut;
4
use std::pin::Pin;
5
use std::task::{Context, Poll};
6
7
// New IO traits? What?! Why, are you bonkers?
8
//
9
// I mean, yes, probably. But, here's the goals:
10
//
11
// 1. Supports poll-based IO operations.
12
// 2. Opt-in vectored IO.
13
// 3. Can use an optional buffer pool.
14
// 4. Able to add completion-based (uring) IO eventually.
15
//
16
// Frankly, the last point is the entire reason we're doing this. We want to
17
// have forwards-compatibility with an eventually stable io-uring runtime. We
18
// don't need that to work right away. But it must be possible to add in here
19
// without breaking hyper 1.0.
20
//
21
// While in here, if there's small tweaks to poll_read or poll_write that would
22
// allow even the "slow" path to be faster, such as if someone didn't remember
23
// to forward along an `is_completion` call.
24
25
/// Reads bytes from a source.
26
///
27
/// This trait is similar to `std::io::Read`, but supports asynchronous reads.
28
///
29
/// # Implementing `Read`
30
///
31
/// Implementations should read data into the provided [`ReadBufCursor`] and
32
/// advance the cursor to indicate how many bytes were written. The simplest
33
/// and safest approach is to use [`ReadBufCursor::put_slice`]:
34
///
35
/// ```
36
/// use hyper::rt::{Read, ReadBufCursor};
37
/// use std::pin::Pin;
38
/// use std::task::{Context, Poll};
39
/// use std::io;
40
///
41
/// struct MyReader {
42
///     data: Vec<u8>,
43
///     position: usize,
44
/// }
45
///
46
/// impl Read for MyReader {
47
///     fn poll_read(
48
///         mut self: Pin<&mut Self>,
49
///         _cx: &mut Context<'_>,
50
///         mut buf: ReadBufCursor<'_>,
51
///     ) -> Poll<Result<(), io::Error>> {
52
///         let remaining_data = &self.data[self.position..];
53
///         if remaining_data.is_empty() {
54
///             // No more data to read, signal EOF by returning Ok without
55
///             // advancing the buffer
56
///             return Poll::Ready(Ok(()));
57
///         }
58
///
59
///         // Calculate how many bytes we can write
60
///         let to_copy = remaining_data.len().min(buf.remaining());
61
///         // Use put_slice to safely copy data and advance the cursor
62
///         buf.put_slice(&remaining_data[..to_copy]);
63
///
64
///         self.position += to_copy;
65
///         Poll::Ready(Ok(()))
66
///     }
67
/// }
68
/// ```
69
///
70
/// For more advanced use cases where you need direct access to the buffer
71
/// (e.g., when interfacing with APIs that write directly to a pointer),
72
/// you can use the unsafe [`ReadBufCursor::as_mut`] and [`ReadBufCursor::advance`]
73
/// methods. See their documentation for safety requirements.
74
pub trait Read {
75
    /// Attempts to read bytes into the `buf`.
76
    ///
77
    /// On success, returns `Poll::Ready(Ok(()))` and places data in the
78
    /// unfilled portion of `buf`. If no data was read (`buf.remaining()` is
79
    /// unchanged), it implies that EOF has been reached.
80
    ///
81
    /// If no data is available for reading, the method returns `Poll::Pending`
82
    /// and arranges for the current task (via `cx.waker()`) to receive a
83
    /// notification when the object becomes readable or is closed.
84
    fn poll_read(
85
        self: Pin<&mut Self>,
86
        cx: &mut Context<'_>,
87
        buf: ReadBufCursor<'_>,
88
    ) -> Poll<Result<(), std::io::Error>>;
89
}
90
91
/// Write bytes asynchronously.
92
///
93
/// This trait is similar to `std::io::Write`, but for asynchronous writes.
94
pub trait Write {
95
    /// Attempt to write bytes from `buf` into the destination.
96
    ///
97
    /// On success, returns `Poll::Ready(Ok(num_bytes_written)))`. If
98
    /// successful, it must be guaranteed that `n <= buf.len()`. A return value
99
    /// of `0` means that the underlying object is no longer able to accept
100
    /// bytes, or that the provided buffer is empty.
101
    ///
102
    /// If the object is not ready for writing, the method returns
103
    /// `Poll::Pending` and arranges for the current task (via `cx.waker()`) to
104
    /// receive a notification when the object becomes writable or is closed.
105
    fn poll_write(
106
        self: Pin<&mut Self>,
107
        cx: &mut Context<'_>,
108
        buf: &[u8],
109
    ) -> Poll<Result<usize, std::io::Error>>;
110
111
    /// Attempts to flush the object.
112
    ///
113
    /// On success, returns `Poll::Ready(Ok(()))`.
114
    ///
115
    /// If flushing cannot immediately complete, this method returns
116
    /// `Poll::Pending` and arranges for the current task (via `cx.waker()`) to
117
    /// receive a notification when the object can make progress.
118
    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), std::io::Error>>;
119
120
    /// Attempts to shut down this writer.
121
    fn poll_shutdown(
122
        self: Pin<&mut Self>,
123
        cx: &mut Context<'_>,
124
    ) -> Poll<Result<(), std::io::Error>>;
125
126
    /// Returns whether this writer has an efficient `poll_write_vectored`
127
    /// implementation.
128
    ///
129
    /// The default implementation returns `false`.
130
0
    fn is_write_vectored(&self) -> bool {
131
0
        false
132
0
    }
Unexecuted instantiation: <hyper::proto::h2::upgrade::H2Upgraded as hyper::rt::io::Write>::is_write_vectored
Unexecuted instantiation: <_ as hyper::rt::io::Write>::is_write_vectored
133
134
    /// Like `poll_write`, except that it writes from a slice of buffers.
135
0
    fn poll_write_vectored(
136
0
        self: Pin<&mut Self>,
137
0
        cx: &mut Context<'_>,
138
0
        bufs: &[std::io::IoSlice<'_>],
139
0
    ) -> Poll<Result<usize, std::io::Error>> {
140
0
        let buf = bufs
141
0
            .iter()
142
0
            .find(|b| !b.is_empty())
Unexecuted instantiation: <hyper::proto::h2::upgrade::H2Upgraded as hyper::rt::io::Write>::poll_write_vectored::{closure#0}
Unexecuted instantiation: <_ as hyper::rt::io::Write>::poll_write_vectored::{closure#0}
143
0
            .map_or(&[][..], |b| &**b);
Unexecuted instantiation: <hyper::proto::h2::upgrade::H2Upgraded as hyper::rt::io::Write>::poll_write_vectored::{closure#1}
Unexecuted instantiation: <_ as hyper::rt::io::Write>::poll_write_vectored::{closure#1}
144
0
        self.poll_write(cx, buf)
145
0
    }
Unexecuted instantiation: <hyper::proto::h2::upgrade::H2Upgraded as hyper::rt::io::Write>::poll_write_vectored
Unexecuted instantiation: <_ as hyper::rt::io::Write>::poll_write_vectored
146
}
147
148
/// A wrapper around a byte buffer that is incrementally filled and initialized.
149
///
150
/// This type is a sort of "double cursor". It tracks three regions in the
151
/// buffer: a region at the beginning of the buffer that has been logically
152
/// filled with data, a region that has been initialized at some point but not
153
/// yet logically filled, and a region at the end that may be uninitialized.
154
/// The filled region is guaranteed to be a subset of the initialized region.
155
///
156
/// In summary, the contents of the buffer can be visualized as:
157
///
158
/// ```not_rust
159
/// [             capacity              ]
160
/// [ filled |         unfilled         ]
161
/// [    initialized    | uninitialized ]
162
/// ```
163
///
164
/// It is undefined behavior to de-initialize any bytes from the uninitialized
165
/// region, since it is merely unknown whether this region is uninitialized or
166
/// not, and if part of it turns out to be initialized, it must stay initialized.
167
pub struct ReadBuf<'a> {
168
    raw: &'a mut [MaybeUninit<u8>],
169
    filled: usize,
170
    init: usize,
171
}
172
173
/// The cursor part of a [`ReadBuf`], representing the unfilled portion.
174
///
175
/// This is created by calling [`ReadBuf::unfilled()`].
176
///
177
/// `ReadBufCursor` provides safe and unsafe methods for writing data into the
178
/// buffer:
179
///
180
/// - **Safe approach**: Use [`put_slice`](Self::put_slice) to copy data from
181
///   a slice. This handles initialization tracking and cursor advancement
182
///   automatically.
183
///
184
/// - **Unsafe approach**: For zero-copy scenarios or when interfacing with
185
///   low-level APIs, use [`as_mut`](Self::as_mut) to get a mutable slice
186
///   of `MaybeUninit<u8>`, then call [`advance`](Self::advance) after writing.
187
///   This is more efficient but requires careful attention to safety invariants.
188
///
189
/// # Example using safe methods
190
///
191
/// ```
192
/// use hyper::rt::ReadBuf;
193
///
194
/// let mut backing = [0u8; 64];
195
/// let mut read_buf = ReadBuf::new(&mut backing);
196
///
197
/// {
198
///     let mut cursor = read_buf.unfilled();
199
///     // put_slice handles everything safely
200
///     cursor.put_slice(b"hello");
201
/// }
202
///
203
/// assert_eq!(read_buf.filled(), b"hello");
204
/// ```
205
///
206
/// # Example using unsafe methods
207
///
208
/// ```
209
/// use hyper::rt::ReadBuf;
210
///
211
/// let mut backing = [0u8; 64];
212
/// let mut read_buf = ReadBuf::new(&mut backing);
213
///
214
/// {
215
///     let mut cursor = read_buf.unfilled();
216
///     // SAFETY: we will initialize exactly 5 bytes
217
///     let slice = unsafe { cursor.as_mut() };
218
///     slice[0].write(b'h');
219
///     slice[1].write(b'e');
220
///     slice[2].write(b'l');
221
///     slice[3].write(b'l');
222
///     slice[4].write(b'o');
223
///     // SAFETY: we have initialized 5 bytes
224
///     unsafe { cursor.advance(5) };
225
/// }
226
///
227
/// assert_eq!(read_buf.filled(), b"hello");
228
/// ```
229
#[derive(Debug)]
230
pub struct ReadBufCursor<'a> {
231
    buf: &'a mut ReadBuf<'a>,
232
}
233
234
impl<'data> ReadBuf<'data> {
235
    /// Create a new `ReadBuf` with a slice of initialized bytes.
236
    #[inline]
237
0
    pub fn new(raw: &'data mut [u8]) -> Self {
238
0
        let len = raw.len();
239
0
        Self {
240
0
            // SAFETY: We never de-init the bytes ourselves.
241
0
            raw: unsafe { &mut *(raw as *mut [u8] as *mut [MaybeUninit<u8>]) },
242
0
            filled: 0,
243
0
            init: len,
244
0
        }
245
0
    }
246
247
    /// Create a new `ReadBuf` with a slice of uninitialized bytes.
248
    #[inline]
249
0
    pub fn uninit(raw: &'data mut [MaybeUninit<u8>]) -> Self {
250
0
        Self {
251
0
            raw,
252
0
            filled: 0,
253
0
            init: 0,
254
0
        }
255
0
    }
Unexecuted instantiation: <hyper::rt::io::ReadBuf>::uninit
Unexecuted instantiation: <hyper::rt::io::ReadBuf>::uninit
256
257
    /// Get a slice of the buffer that has been filled in with bytes.
258
    #[inline]
259
0
    pub fn filled(&self) -> &[u8] {
260
        // SAFETY: We only slice the filled part of the buffer, which is always valid
261
0
        unsafe { &*(&self.raw[0..self.filled] as *const [MaybeUninit<u8>] as *const [u8]) }
262
0
    }
263
264
    /// Get a cursor to the unfilled portion of the buffer.
265
    #[inline]
266
0
    pub fn unfilled<'cursor>(&'cursor mut self) -> ReadBufCursor<'cursor> {
267
0
        ReadBufCursor {
268
0
            // SAFETY: self.buf is never re-assigned, so its safe to narrow
269
0
            // the lifetime.
270
0
            buf: unsafe {
271
0
                std::mem::transmute::<&'cursor mut ReadBuf<'data>, &'cursor mut ReadBuf<'cursor>>(
272
0
                    self,
273
0
                )
274
0
            },
275
0
        }
276
0
    }
Unexecuted instantiation: <hyper::rt::io::ReadBuf>::unfilled
Unexecuted instantiation: <hyper::rt::io::ReadBuf>::unfilled
277
278
    #[inline]
279
    #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))]
280
0
    pub(crate) unsafe fn set_init(&mut self, n: usize) {
281
0
        self.init = self.init.max(n);
282
0
    }
Unexecuted instantiation: <hyper::rt::io::ReadBuf>::set_init
Unexecuted instantiation: <hyper::rt::io::ReadBuf>::set_init
283
284
    #[inline]
285
    #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))]
286
0
    pub(crate) unsafe fn set_filled(&mut self, n: usize) {
287
0
        self.filled = self.filled.max(n);
288
0
    }
Unexecuted instantiation: <hyper::rt::io::ReadBuf>::set_filled
Unexecuted instantiation: <hyper::rt::io::ReadBuf>::set_filled
289
290
    #[inline]
291
    #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))]
292
0
    pub(crate) fn len(&self) -> usize {
293
0
        self.filled
294
0
    }
Unexecuted instantiation: <hyper::rt::io::ReadBuf>::len
Unexecuted instantiation: <hyper::rt::io::ReadBuf>::len
295
296
    #[inline]
297
    #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))]
298
0
    pub(crate) fn init_len(&self) -> usize {
299
0
        self.init
300
0
    }
Unexecuted instantiation: <hyper::rt::io::ReadBuf>::init_len
Unexecuted instantiation: <hyper::rt::io::ReadBuf>::init_len
301
302
    #[inline]
303
0
    fn remaining(&self) -> usize {
304
0
        self.capacity() - self.filled
305
0
    }
306
307
    #[inline]
308
0
    fn capacity(&self) -> usize {
309
0
        self.raw.len()
310
0
    }
311
}
312
313
impl fmt::Debug for ReadBuf<'_> {
314
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
315
0
        f.debug_struct("ReadBuf")
316
0
            .field("filled", &self.filled)
317
0
            .field("init", &self.init)
318
0
            .field("capacity", &self.capacity())
319
0
            .finish()
320
0
    }
321
}
322
323
impl ReadBufCursor<'_> {
324
    /// Access the unfilled part of the buffer.
325
    ///
326
    /// # Safety
327
    ///
328
    /// The caller must not uninitialize any bytes that may have been
329
    /// initialized before.
330
    #[inline]
331
0
    pub unsafe fn as_mut(&mut self) -> &mut [MaybeUninit<u8>] {
332
0
        &mut self.buf.raw[self.buf.filled..]
333
0
    }
Unexecuted instantiation: <hyper::rt::io::ReadBufCursor>::as_mut
Unexecuted instantiation: <hyper::rt::io::ReadBufCursor>::as_mut
334
335
    /// Advance the `filled` cursor by `n` bytes.
336
    ///
337
    /// # Safety
338
    ///
339
    /// The caller must take care that `n` more bytes have been initialized.
340
    #[inline]
341
0
    pub unsafe fn advance(&mut self, n: usize) {
342
0
        self.buf.filled = self.buf.filled.checked_add(n).expect("overflow");
343
0
        self.buf.init = self.buf.filled.max(self.buf.init);
344
0
    }
Unexecuted instantiation: <hyper::rt::io::ReadBufCursor>::advance
Unexecuted instantiation: <hyper::rt::io::ReadBufCursor>::advance
345
346
    /// Returns the number of bytes that can be written from the current
347
    /// position until the end of the buffer is reached.
348
    ///
349
    /// This value is equal to the length of the slice returned by `as_mut()``.
350
    #[inline]
351
0
    pub fn remaining(&self) -> usize {
352
0
        self.buf.remaining()
353
0
    }
354
355
    /// Transfer bytes into `self` from `src` and advance the cursor
356
    /// by the number of bytes written.
357
    ///
358
    /// # Panics
359
    ///
360
    /// `self` must have enough remaining capacity to contain all of `src`.
361
    #[inline]
362
0
    pub fn put_slice(&mut self, src: &[u8]) {
363
0
        assert!(
364
0
            self.buf.remaining() >= src.len(),
365
            "src.len() must fit in remaining()"
366
        );
367
368
0
        let amt = src.len();
369
        // Cannot overflow, asserted above
370
0
        let end = self.buf.filled + amt;
371
372
        // Safety: the length is asserted above
373
0
        unsafe {
374
0
            self.buf.raw[self.buf.filled..end]
375
0
                .as_mut_ptr()
376
0
                .cast::<u8>()
377
0
                .copy_from_nonoverlapping(src.as_ptr(), amt);
378
0
        }
379
380
0
        if self.buf.init < end {
381
0
            self.buf.init = end;
382
0
        }
383
0
        self.buf.filled = end;
384
0
    }
385
}
386
387
macro_rules! deref_async_read {
388
    () => {
389
0
        fn poll_read(
390
0
            mut self: Pin<&mut Self>,
391
0
            cx: &mut Context<'_>,
392
0
            buf: ReadBufCursor<'_>,
393
0
        ) -> Poll<std::io::Result<()>> {
394
0
            Pin::new(&mut **self).poll_read(cx, buf)
395
0
        }
Unexecuted instantiation: <alloc::boxed::Box<dyn hyper::upgrade::Io + core::marker::Send> as hyper::rt::io::Read>::poll_read
Unexecuted instantiation: <&mut _ as hyper::rt::io::Read>::poll_read
396
    };
397
}
398
399
impl<T: ?Sized + Read + Unpin> Read for Box<T> {
400
    deref_async_read!();
401
}
402
403
impl<T: ?Sized + Read + Unpin> Read for &mut T {
404
    deref_async_read!();
405
}
406
407
impl<P> Read for Pin<P>
408
where
409
    P: DerefMut,
410
    P::Target: Read,
411
{
412
0
    fn poll_read(
413
0
        self: Pin<&mut Self>,
414
0
        cx: &mut Context<'_>,
415
0
        buf: ReadBufCursor<'_>,
416
0
    ) -> Poll<std::io::Result<()>> {
417
0
        pin_as_deref_mut(self).poll_read(cx, buf)
418
0
    }
Unexecuted instantiation: <core::pin::Pin<alloc::boxed::Box<dyn tonic::transport::channel::service::io::Io>> as hyper::rt::io::Read>::poll_read
Unexecuted instantiation: <core::pin::Pin<_> as hyper::rt::io::Read>::poll_read
419
}
420
421
macro_rules! deref_async_write {
422
    () => {
423
0
        fn poll_write(
424
0
            mut self: Pin<&mut Self>,
425
0
            cx: &mut Context<'_>,
426
0
            buf: &[u8],
427
0
        ) -> Poll<std::io::Result<usize>> {
428
0
            Pin::new(&mut **self).poll_write(cx, buf)
429
0
        }
Unexecuted instantiation: <alloc::boxed::Box<dyn hyper::upgrade::Io + core::marker::Send> as hyper::rt::io::Write>::poll_write
Unexecuted instantiation: <&mut _ as hyper::rt::io::Write>::poll_write
430
431
0
        fn poll_write_vectored(
432
0
            mut self: Pin<&mut Self>,
433
0
            cx: &mut Context<'_>,
434
0
            bufs: &[std::io::IoSlice<'_>],
435
0
        ) -> Poll<std::io::Result<usize>> {
436
0
            Pin::new(&mut **self).poll_write_vectored(cx, bufs)
437
0
        }
Unexecuted instantiation: <alloc::boxed::Box<dyn hyper::upgrade::Io + core::marker::Send> as hyper::rt::io::Write>::poll_write_vectored
Unexecuted instantiation: <&mut _ as hyper::rt::io::Write>::poll_write_vectored
438
439
0
        fn is_write_vectored(&self) -> bool {
440
0
            (**self).is_write_vectored()
441
0
        }
Unexecuted instantiation: <alloc::boxed::Box<dyn hyper::upgrade::Io + core::marker::Send> as hyper::rt::io::Write>::is_write_vectored
Unexecuted instantiation: <&mut _ as hyper::rt::io::Write>::is_write_vectored
442
443
0
        fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
444
0
            Pin::new(&mut **self).poll_flush(cx)
445
0
        }
Unexecuted instantiation: <alloc::boxed::Box<dyn hyper::upgrade::Io + core::marker::Send> as hyper::rt::io::Write>::poll_flush
Unexecuted instantiation: <&mut _ as hyper::rt::io::Write>::poll_flush
446
447
0
        fn poll_shutdown(
448
0
            mut self: Pin<&mut Self>,
449
0
            cx: &mut Context<'_>,
450
0
        ) -> Poll<std::io::Result<()>> {
451
0
            Pin::new(&mut **self).poll_shutdown(cx)
452
0
        }
Unexecuted instantiation: <alloc::boxed::Box<dyn hyper::upgrade::Io + core::marker::Send> as hyper::rt::io::Write>::poll_shutdown
Unexecuted instantiation: <&mut _ as hyper::rt::io::Write>::poll_shutdown
453
    };
454
}
455
456
impl<T: ?Sized + Write + Unpin> Write for Box<T> {
457
    deref_async_write!();
458
}
459
460
impl<T: ?Sized + Write + Unpin> Write for &mut T {
461
    deref_async_write!();
462
}
463
464
impl<P> Write for Pin<P>
465
where
466
    P: DerefMut,
467
    P::Target: Write,
468
{
469
0
    fn poll_write(
470
0
        self: Pin<&mut Self>,
471
0
        cx: &mut Context<'_>,
472
0
        buf: &[u8],
473
0
    ) -> Poll<std::io::Result<usize>> {
474
0
        pin_as_deref_mut(self).poll_write(cx, buf)
475
0
    }
Unexecuted instantiation: <core::pin::Pin<alloc::boxed::Box<dyn tonic::transport::channel::service::io::Io>> as hyper::rt::io::Write>::poll_write
Unexecuted instantiation: <core::pin::Pin<_> as hyper::rt::io::Write>::poll_write
476
477
0
    fn poll_write_vectored(
478
0
        self: Pin<&mut Self>,
479
0
        cx: &mut Context<'_>,
480
0
        bufs: &[std::io::IoSlice<'_>],
481
0
    ) -> Poll<std::io::Result<usize>> {
482
0
        pin_as_deref_mut(self).poll_write_vectored(cx, bufs)
483
0
    }
Unexecuted instantiation: <core::pin::Pin<alloc::boxed::Box<dyn tonic::transport::channel::service::io::Io>> as hyper::rt::io::Write>::poll_write_vectored
Unexecuted instantiation: <core::pin::Pin<_> as hyper::rt::io::Write>::poll_write_vectored
484
485
0
    fn is_write_vectored(&self) -> bool {
486
0
        (**self).is_write_vectored()
487
0
    }
Unexecuted instantiation: <core::pin::Pin<alloc::boxed::Box<dyn tonic::transport::channel::service::io::Io>> as hyper::rt::io::Write>::is_write_vectored
Unexecuted instantiation: <core::pin::Pin<_> as hyper::rt::io::Write>::is_write_vectored
488
489
0
    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
490
0
        pin_as_deref_mut(self).poll_flush(cx)
491
0
    }
Unexecuted instantiation: <core::pin::Pin<alloc::boxed::Box<dyn tonic::transport::channel::service::io::Io>> as hyper::rt::io::Write>::poll_flush
Unexecuted instantiation: <core::pin::Pin<_> as hyper::rt::io::Write>::poll_flush
492
493
0
    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
494
0
        pin_as_deref_mut(self).poll_shutdown(cx)
495
0
    }
Unexecuted instantiation: <core::pin::Pin<alloc::boxed::Box<dyn tonic::transport::channel::service::io::Io>> as hyper::rt::io::Write>::poll_shutdown
Unexecuted instantiation: <core::pin::Pin<_> as hyper::rt::io::Write>::poll_shutdown
496
}
497
498
/// Polyfill for Pin::as_deref_mut()
499
/// TODO: use Pin::as_deref_mut() instead once stabilized
500
0
fn pin_as_deref_mut<P: DerefMut>(pin: Pin<&mut Pin<P>>) -> Pin<&mut P::Target> {
501
    // SAFETY: we go directly from Pin<&mut Pin<P>> to Pin<&mut P::Target>, without moving or
502
    // giving out the &mut Pin<P> in the process. See Pin::as_deref_mut() for more detail.
503
0
    unsafe { pin.get_unchecked_mut() }.as_mut()
504
0
}
Unexecuted instantiation: hyper::rt::io::pin_as_deref_mut::<alloc::boxed::Box<dyn tonic::transport::channel::service::io::Io>>
Unexecuted instantiation: hyper::rt::io::pin_as_deref_mut::<_>