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}