qubit_clock/monotonic/manual_waiter_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//! Defines a future that observes manual waiter registration.
9
10use std::future::Future;
11use std::pin::Pin;
12use std::sync::Arc;
13use std::task::Context;
14use std::task::Poll;
15
16use crate::ManualMonotonicClock;
17
18/// A future that completes when a manual clock has enough registered waiters.
19///
20/// This is a deterministic synchronization primitive for tests. Its observer
21/// is registered when the future is created, before its first poll. Dropping
22/// an incomplete future unregisters the observer from the clock.
23#[derive(Debug)]
24pub struct ManualWaiterFuture {
25 /// The reference to the manual clock.
26 clock: Arc<ManualMonotonicClock>,
27 /// The identifier of the observer.
28 observer_id: Option<u64>,
29}
30
31impl ManualWaiterFuture {
32 /// Creates a waiter-count observer for `clock`.
33 ///
34 /// # Parameters
35 ///
36 /// * `clock` - Manual clock whose waiter count is observed.
37 /// * `expected_count` - Registration count that completes the future.
38 ///
39 /// # Returns
40 ///
41 /// A future whose observer is registered before this method returns.
42 ///
43 /// # Panics
44 ///
45 /// Panics when the observer identifier space is exhausted.
46 #[inline]
47 pub(crate) fn new(clock: Arc<ManualMonotonicClock>, expected_count: usize) -> Self {
48 let observer_id = clock.register_waiter_observer(expected_count);
49 Self { clock, observer_id }
50 }
51}
52
53impl Future for ManualWaiterFuture {
54 type Output = ();
55
56 /// Polls whether the requested waiter count has been reached.
57 ///
58 /// # Parameters
59 ///
60 /// * `context` - Task context whose waker replaces any prior registration.
61 ///
62 /// # Returns
63 ///
64 /// [`Poll::Ready`] after the requested count is reached, otherwise
65 /// [`Poll::Pending`].
66 ///
67 /// # Panics
68 ///
69 /// Panics if destroying a replaced custom task waker panics.
70 fn poll(mut self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Self::Output> {
71 let Some(observer_id) = self.observer_id else {
72 return Poll::Ready(());
73 };
74 let result = self.clock.poll_waiter_observer(observer_id, context);
75 if result.is_ready() {
76 self.observer_id = None;
77 }
78 result
79 }
80}
81
82impl Drop for ManualWaiterFuture {
83 /// Unregisters an incomplete waiter-count observer.
84 ///
85 /// # Panics
86 ///
87 /// Panics if destroying the observer's custom task waker panics.
88 #[inline]
89 fn drop(&mut self) {
90 if let Some(observer_id) = self.observer_id.take() {
91 self.clock.unregister_waiter_observer(observer_id);
92 }
93 }
94}