Skip to main content

qubit_io/async_io/
close_future.rs

1// =============================================================================
2//    Copyright (c) 2025 - 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5//
6//    Licensed under the Apache License, Version 2.0.
7// =============================================================================
8
9use std::future::Future;
10use std::io::Result;
11use std::pin::Pin;
12use std::task::Context;
13use std::task::Poll;
14
15use crate::AsyncClose;
16use crate::traits::normalize_async_error;
17
18/// Future that closes an [`AsyncClose`] output.
19///
20/// # Panics
21///
22/// [`Future::poll`] panics when called again after this future has returned
23/// [`Poll::Ready`].
24///
25/// # Type Parameters
26///
27/// - `'a`: Lifetime of the borrowed output.
28/// - `O`: Asynchronous output type.
29#[must_use = "futures do nothing unless polled"]
30pub struct CloseFuture<'a, O>
31where
32    O: AsyncClose + ?Sized,
33{
34    /// Output being closed.
35    output: Pin<&'a mut O>,
36    /// Whether the close operation has completed.
37    completed: bool,
38}
39
40impl<'a, O> CloseFuture<'a, O>
41where
42    O: AsyncClose + ?Sized,
43{
44    /// Creates a close future from a pinned output.
45    ///
46    /// # Parameters
47    ///
48    /// - `output`: Pinned asynchronous output.
49    ///
50    /// # Returns
51    ///
52    /// Returns a future representing the close operation.
53    #[inline(always)]
54    pub const fn new(output: Pin<&'a mut O>) -> Self {
55        Self {
56            output,
57            completed: false,
58        }
59    }
60}
61
62impl<O> Future for CloseFuture<'_, O>
63where
64    O: AsyncClose + ?Sized,
65{
66    /// Result produced when the close operation becomes ready.
67    type Output = Result<()>;
68
69    /// Polls the close operation.
70    ///
71    /// # Parameters
72    ///
73    /// - `cx`: Task context used to register a wake-up.
74    ///
75    /// # Returns
76    ///
77    /// Returns [`Poll::Pending`] while closing is incomplete. A ready result
78    /// indicates whether closing succeeded.
79    ///
80    /// # Errors
81    ///
82    /// Returns an I/O error reported by the output. Invalid asynchronous error
83    /// kinds are normalized to [`std::io::ErrorKind::InvalidData`].
84    ///
85    /// # Panics
86    ///
87    /// Panics when polled after returning [`Poll::Ready`].
88    #[inline]
89    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
90        let this = self.get_mut();
91        assert!(!this.completed, "CloseFuture polled after completion");
92        let result = this
93            .output
94            .as_mut()
95            .poll_close(cx)
96            .map(|result| result.map_err(normalize_async_error));
97        if result.is_ready() {
98            this.completed = true;
99        }
100        result
101    }
102}