Coverage Report

Created: 2026-01-15 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/mea-0.6.0/src/condvar/mod.rs
Line
Count
Source
1
// Copyright 2024 tison <wander4096@gmail.com>
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
//! A condition variable that allows tasks to wait for a notification.
16
//!
17
//! # Examples
18
//!
19
//! ```
20
//! # #[tokio::main]
21
//! # async fn main() {
22
//! use std::sync::Arc;
23
//!
24
//! use mea::condvar::Condvar;
25
//! use mea::mutex::Mutex;
26
//!
27
//! let pair = Arc::new((Mutex::new(false), Condvar::new()));
28
//! let pair_clone = pair.clone();
29
//!
30
//! // Inside our lock, spawn a new thread, and then wait for it to start.
31
//! tokio::spawn(async move {
32
//!     let (lock, cvar) = &*pair_clone;
33
//!     let mut started = lock.lock().await;
34
//!     *started = true;
35
//!     // We notify the condvar that the value has changed.
36
//!     cvar.notify_one();
37
//! });
38
//!
39
//! // Wait for the thread to start up.
40
//! let (lock, cvar) = &*pair;
41
//! let mut started = lock.lock().await;
42
//! while !*started {
43
//!     started = cvar.wait(started).await;
44
//! }
45
//! # }
46
//! ```
47
48
use std::fmt;
49
use std::task::Waker;
50
51
use crate::internal;
52
use crate::mutex;
53
use crate::mutex::MutexGuard;
54
use crate::mutex::OwnedMutexGuard;
55
56
#[cfg(test)]
57
mod tests;
58
59
/// A condition variable that allows tasks to wait for a notification.
60
///
61
/// See the [module level documentation](self) for more.
62
pub struct Condvar {
63
    s: internal::Semaphore,
64
}
65
66
impl fmt::Debug for Condvar {
67
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68
0
        f.debug_struct("Condvar").finish_non_exhaustive()
69
0
    }
70
}
71
72
impl Default for Condvar {
73
0
    fn default() -> Self {
74
0
        Self::new()
75
0
    }
76
}
77
78
impl Condvar {
79
    /// Creates a new condition variable
80
    ///
81
    /// # Examples
82
    ///
83
    /// ```
84
    /// use mea::condvar::Condvar;
85
    ///
86
    /// let cvar = Condvar::new();
87
    /// ```
88
0
    pub const fn new() -> Condvar {
89
0
        Condvar {
90
0
            s: internal::Semaphore::new(0),
91
0
        }
92
0
    }
93
94
    /// Wakes up one blocked task on this condvar.
95
0
    pub fn notify_one(&self) {
96
0
        self.s.release(1);
97
0
    }
98
99
    /// Wakes up all blocked tasks on this condvar.
100
0
    pub fn notify_all(&self) {
101
0
        self.s.notify_all();
102
0
    }
103
104
    /// Yields the current task until this condition variable receives a notification.
105
    ///
106
    /// Unlike the std equivalent, this does not check that a single mutex is used at runtime.
107
    /// However, as a best practice avoid using with multiple mutexes.
108
0
    pub async fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> {
109
0
        let mutex = mutex::guard_lock(&guard);
110
111
        // register waiter while holding lock
112
0
        let mut acquire = self.s.poll_acquire(1);
113
0
        let _ = acquire.poll_once(Waker::noop());
114
0
        drop(guard);
115
116
        // await for notification, and then reacquire the lock
117
0
        acquire.await;
118
0
        mutex.lock().await
119
0
    }
120
121
    /// Yields the current task until this condition variable receives a notification.
122
    ///
123
    /// Unlike the std equivalent, this does not check that a single mutex is used at runtime.
124
    /// However, as a best practice avoid using with multiple mutexes.
125
0
    pub async fn wait_owned<T>(&self, guard: OwnedMutexGuard<T>) -> OwnedMutexGuard<T> {
126
0
        let mutex = mutex::owned_guard_lock(&guard);
127
128
        // register waiter while holding lock
129
0
        let mut acquire = self.s.poll_acquire(1);
130
0
        let _ = acquire.poll_once(Waker::noop());
131
0
        drop(guard);
132
133
        // await for notification, and then reacquire the lock
134
0
        acquire.await;
135
0
        mutex.lock_owned().await
136
0
    }
137
138
    /// Yields the current task until this condition variable receives a notification and the
139
    /// provided condition becomes false. Spurious wake-ups are ignored and this function will only
140
    /// return once the condition has been met.
141
    ///
142
    /// ```
143
    /// # #[tokio::main]
144
    /// # async fn main() {
145
    /// use std::sync::Arc;
146
    ///
147
    /// use mea::condvar::Condvar;
148
    /// use mea::mutex::Mutex;
149
    ///
150
    /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
151
    /// let pair_clone = pair.clone();
152
    ///
153
    /// tokio::spawn(async move {
154
    ///     let (lock, cvar) = &*pair_clone;
155
    ///     let mut started = lock.lock().await;
156
    ///     *started = true;
157
    ///     // We notify the condvar that the value has changed.
158
    ///     cvar.notify_one();
159
    /// });
160
    ///
161
    /// // Wait for the thread to start up.
162
    /// let (lock, cvar) = &*pair;
163
    /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
164
    /// let guard = cvar
165
    ///     .wait_while(lock.lock().await, |started| !*started)
166
    ///     .await;
167
    /// assert!(*guard);
168
    /// # }
169
    /// ```
170
0
    pub async fn wait_while<'a, T, F>(
171
0
        &self,
172
0
        mut guard: MutexGuard<'a, T>,
173
0
        mut condition: F,
174
0
    ) -> MutexGuard<'a, T>
175
0
    where
176
0
        F: FnMut(&mut T) -> bool,
177
0
    {
178
0
        while condition(&mut *guard) {
179
0
            guard = self.wait(guard).await;
180
        }
181
0
        guard
182
0
    }
183
184
    /// Yields the current task until this condition variable receives a notification and the
185
    /// provided condition becomes false. Spurious wake-ups are ignored and this function will only
186
    /// return once the condition has been met.
187
    ///
188
    /// ```
189
    /// # #[tokio::main]
190
    /// # async fn main() {
191
    /// use std::sync::Arc;
192
    ///
193
    /// use mea::condvar::Condvar;
194
    /// use mea::mutex::Mutex;
195
    ///
196
    /// let pair = (Arc::new(Mutex::new(false)), Arc::new(Condvar::new()));
197
    /// let pair_clone = pair.clone();
198
    ///
199
    /// tokio::spawn(async move {
200
    ///     let (lock, cvar) = pair_clone;
201
    ///     let mut started = lock.lock_owned().await;
202
    ///     *started = true;
203
    ///     // We notify the condvar that the value has changed.
204
    ///     cvar.notify_one();
205
    /// });
206
    ///
207
    /// // Wait for the thread to start up.
208
    /// let (lock, cvar) = pair;
209
    /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
210
    /// let guard = cvar
211
    ///     .wait_while_owned(lock.lock_owned().await, |started| !*started)
212
    ///     .await;
213
    /// assert!(*guard);
214
    /// # }
215
    /// ```
216
0
    pub async fn wait_while_owned<T, F>(
217
0
        &self,
218
0
        mut guard: OwnedMutexGuard<T>,
219
0
        mut condition: F,
220
0
    ) -> OwnedMutexGuard<T>
221
0
    where
222
0
        F: FnMut(&mut T) -> bool,
223
0
    {
224
0
        while condition(&mut *guard) {
225
0
            guard = self.wait_owned(guard).await;
226
        }
227
0
        guard
228
0
    }
229
}