Skip to main content

conc_util/event/
onceevent.rs

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