Skip to main content

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}