Skip to main content

conc_util/event/
onceevent.rs

1#![cfg(feature = "alloc")]
2
3use core::{
4    mem::ManuallyDrop,
5    pin::Pin,
6    task::{self, Waker},
7};
8
9use alloc::vec::Vec;
10
11use crate::{event::Event, sync::{OnceFlag, SpinLock}};
12
13#[derive(Debug)]
14pub struct OnceEvent {
15    used: OnceFlag,
16    wakers: SpinLock<ManuallyDrop<Vec<Waker>>>,
17}
18
19impl OnceEvent {
20    pub fn new() -> Self {
21        Self {
22            used: OnceFlag::new(),
23            wakers: SpinLock::new(ManuallyDrop::new(Vec::new())),
24        }
25    }
26}
27
28impl Event for OnceEvent {
29    fn fire(&self) {
30        if self.used.fire() {
31            return;
32        }
33
34        let mut lock = self.wakers.lock();
35        // SAFETY:
36        // 1) Value is taken once - `used` is checked at the beginning
37        // 2) Value is never used again - `poll` checks the same `used`
38        let wakers = unsafe { ManuallyDrop::take(&mut lock) };
39        drop(lock);
40
41        for waker in wakers {
42            waker.wake();
43        }
44    }
45}
46
47impl Drop for OnceEvent {
48    fn drop(&mut self) {
49        if !self.used.fired_mut() {
50            // SAFETY: this is only dropped here and taken in `fire()`,
51            // but it also sets the `used` flag which is checked above.
52            unsafe { ManuallyDrop::drop(self.wakers.get()) };
53        }
54    }
55}
56
57impl Future for &OnceEvent {
58    type Output = ();
59
60    fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
61        if self.used.fired() {
62            return task::Poll::Ready(());
63        }
64
65        let mut wakers = self.wakers.lock();
66
67        if self.used.fired() {
68            return task::Poll::Ready(());
69        }
70
71        wakers.push(cx.waker().clone());
72        return task::Poll::Pending;
73    }
74}