qubit_lock/monitor/monitor_guard.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10//! # Monitor Guard
11//!
12//! Provides the guard returned by [`Monitor::lock`](super::Monitor::lock).
13//! The guard wraps a parking_lot mutex guard and keeps a reference to the
14//! monitor that created it, so waiting operations can use the matching
15//! condition variable.
16//!
17
18use std::{
19 ops::{
20 Deref,
21 DerefMut,
22 },
23 time::Duration,
24};
25
26use parking_lot::MutexGuard;
27
28use super::{
29 monitor::Monitor,
30 wait_timeout_status::WaitTimeoutStatus,
31};
32
33/// Guard returned by [`Monitor::lock`](super::Monitor::lock).
34///
35/// `MonitorGuard` is the monitor-specific counterpart of
36/// [`parking_lot::MutexGuard`]. While it exists, the protected state is locked.
37/// Dropping the guard releases the lock. It implements [`Deref`] and
38/// [`DerefMut`], so callers can read and mutate the protected state as if they
39/// held `&T` or `&mut T`.
40///
41/// Unlike a raw `MutexGuard`, this guard also remembers the monitor that
42/// created it. That lets [`Self::wait`] and [`Self::wait_timeout`] release and
43/// reacquire the correct mutex with the correct condition variable.
44///
45/// # Type Parameters
46///
47/// * `T` - The state protected by the monitor.
48///
49/// # Example
50///
51/// ```rust
52/// use qubit_lock::lock::Monitor;
53///
54/// let monitor = Monitor::new(Vec::new());
55/// {
56/// let mut items = monitor.lock();
57/// items.push("first");
58/// }
59///
60/// assert_eq!(monitor.read(|items| items.len()), 1);
61/// ```
62pub struct MonitorGuard<'a, T> {
63 /// Monitor that owns the mutex and condition variable.
64 monitor: &'a Monitor<T>,
65 /// Parking-lot mutex guard protecting the monitor state.
66 inner: MutexGuard<'a, T>,
67}
68
69impl<'a, T> MonitorGuard<'a, T> {
70 /// Creates a guard from its owning monitor and parking_lot mutex guard.
71 ///
72 /// # Parameters
73 ///
74 /// * `monitor` - Monitor whose mutex produced `inner`.
75 /// * `inner` - Parking-lot mutex guard protecting the monitor state.
76 ///
77 /// # Returns
78 ///
79 /// A monitor guard that can access state and wait on the monitor's
80 /// condition variable.
81 #[inline]
82 pub(super) fn new(monitor: &'a Monitor<T>, inner: MutexGuard<'a, T>) -> Self {
83 Self { monitor, inner }
84 }
85
86 /// Waits for a notification while temporarily releasing the monitor lock.
87 ///
88 /// This method consumes the current guard, calls the underlying
89 /// [`parking_lot::Condvar::wait`], and returns the guard after the lock has
90 /// been reacquired. It is intended for explicit guarded-suspension loops
91 /// where the caller needs to inspect or update state before and after
92 /// waiting.
93 ///
94 /// The method may block indefinitely if no notification is sent. Callers
95 /// should still use it inside a loop that re-checks the protected state so
96 /// notifications that do not make progress are handled correctly.
97 ///
98 /// # Returns
99 ///
100 /// A new guard holding the monitor lock after the wait returns.
101 ///
102 /// # Example
103 ///
104 /// ```rust
105 /// use std::{
106 /// sync::Arc,
107 /// thread,
108 /// };
109 ///
110 /// use qubit_lock::lock::Monitor;
111 ///
112 /// let monitor = Arc::new(Monitor::new(false));
113 /// let waiter_monitor = Arc::clone(&monitor);
114 ///
115 /// let waiter = thread::spawn(move || {
116 /// let mut ready = waiter_monitor.lock();
117 /// while !*ready {
118 /// ready = ready.wait();
119 /// }
120 /// *ready = false;
121 /// });
122 ///
123 /// {
124 /// let mut ready = monitor.lock();
125 /// *ready = true;
126 /// }
127 /// monitor.notify_one();
128 ///
129 /// waiter.join().expect("waiter should finish");
130 /// assert!(!monitor.read(|ready| *ready));
131 /// ```
132 #[inline]
133 pub fn wait(mut self) -> Self {
134 self.monitor.changed.wait(&mut self.inner);
135 self
136 }
137
138 /// Waits for a notification or timeout while temporarily releasing the lock.
139 ///
140 /// This method consumes the current guard, calls the underlying
141 /// [`parking_lot::Condvar::wait_for`], and returns the guard after the
142 /// lock has been reacquired. The status reports whether the wait reached
143 /// the timeout boundary or returned earlier.
144 ///
145 /// A [`WaitTimeoutStatus::Woken`] result does not prove that another thread
146 /// changed the state. A [`WaitTimeoutStatus::TimedOut`] result also does
147 /// not remove the need to inspect the state, because another thread may
148 /// have changed it while this thread was reacquiring the lock.
149 ///
150 /// # Arguments
151 ///
152 /// * `timeout` - Maximum duration to wait before returning
153 /// [`WaitTimeoutStatus::TimedOut`].
154 ///
155 /// # Returns
156 ///
157 /// A tuple containing the reacquired guard and the timed-wait status.
158 ///
159 /// # Example
160 ///
161 /// ```rust
162 /// use std::time::Duration;
163 ///
164 /// use qubit_lock::lock::{Monitor, WaitTimeoutStatus};
165 ///
166 /// let monitor = Monitor::new(0);
167 /// let guard = monitor.lock();
168 /// let (guard, status) = guard.wait_timeout(Duration::from_millis(1));
169 ///
170 /// assert_eq!(*guard, 0);
171 /// assert_eq!(status, WaitTimeoutStatus::TimedOut);
172 /// ```
173 #[inline]
174 pub fn wait_timeout(mut self, timeout: Duration) -> (Self, WaitTimeoutStatus) {
175 let timeout_result = self.monitor.changed.wait_for(&mut self.inner, timeout);
176 let status = if timeout_result.timed_out() {
177 WaitTimeoutStatus::TimedOut
178 } else {
179 WaitTimeoutStatus::Woken
180 };
181 (self, status)
182 }
183}
184
185impl<T> Deref for MonitorGuard<'_, T> {
186 type Target = T;
187
188 /// Returns an immutable reference to the protected state.
189 #[inline]
190 fn deref(&self) -> &Self::Target {
191 &self.inner
192 }
193}
194
195impl<T> DerefMut for MonitorGuard<'_, T> {
196 /// Returns a mutable reference to the protected state.
197 #[inline]
198 fn deref_mut(&mut self) -> &mut Self::Target {
199 &mut self.inner
200 }
201}