1use core::fmt;
4use core::future::Future;
5use core::pin::Pin;
6use core::task::{Context, Poll};
7
8use super::event::{Event, EventWait};
9use super::internal::{AtomicUsize, Ordering};
10
11pub struct Latch {
23 count: AtomicUsize,
24 open: Event,
25}
26
27impl Latch {
28 loom_const_fn! {
29 pub fn new(count: usize) -> Self {
33 Self { count: AtomicUsize::new(count), open: Event::new_set(count == 0) }
34 }
35 }
36
37 pub fn count_down(&self) {
40 let mut count = self.count.load(Ordering::Relaxed);
41 while count != 0 {
42 match self.count.compare_exchange_weak(
43 count,
44 count - 1,
45 Ordering::AcqRel,
46 Ordering::Relaxed,
47 ) {
48 Ok(1) => return self.open.set(),
49 Ok(_) => return,
50 Err(actual) => count = actual,
51 }
52 }
53 }
54
55 pub fn count(&self) -> usize {
57 self.count.load(Ordering::Acquire)
58 }
59
60 pub fn is_set(&self) -> bool {
62 self.open.is_set()
63 }
64
65 pub fn wait(&self) -> LatchWait<'_> {
67 LatchWait(self.open.wait())
68 }
69}
70
71impl fmt::Debug for Latch {
72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 f.debug_struct("Latch")
74 .field("count", &self.count())
75 .finish()
76 }
77}
78
79#[must_use = "futures do nothing unless polled"]
81#[derive(Debug)]
82pub struct LatchWait<'a>(EventWait<'a>);
83
84impl Future for LatchWait<'_> {
85 type Output = ();
86
87 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
88 Pin::new(&mut self.get_mut().0).poll(cx)
89 }
90}
91
92#[cfg(all(test, not(loom)))]
93mod tests {
94 use super::*;
95 use crate::sync::test_support::Polled;
96
97 #[test]
98 fn the_latch_opens_at_zero_and_stays_open() {
99 let latch = Latch::new(2);
100 let mut waiting = Polled::new(latch.wait());
101 waiting.pending();
102 latch.count_down();
103 assert_eq!(waiting.wakes(), 0);
104 latch.count_down();
105 latch.count_down();
106 assert_eq!(latch.count(), 0);
107 waiting.ready();
108 Polled::new(latch.wait()).ready();
109 Polled::new(Latch::new(0).wait()).ready();
110 }
111}