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 Future for &OnceEvent {
27    type Output = ();
28
29    fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
30        if self.used.fired() {
31            return task::Poll::Ready(());
32        }
33
34        let mut wakers = self.wakers.lock();
35
36        if self.used.fired() {
37            return task::Poll::Ready(());
38        }
39
40        wakers.push(cx.waker().clone());
41        return task::Poll::Pending;
42    }
43}
44
45impl Event for &OnceEvent {
46    fn fire(self) {
47        if self.used.fire() {
48            return;
49        }
50
51        let mut lock = self.wakers.lock();
52        // SAFETY:
53        // 1) Value is taken once - `used` is checked at the beginning
54        // 2) Value is never used again - `poll` checks the same `used`
55        let wakers = unsafe { ManuallyDrop::take(&mut lock) };
56        drop(lock);
57
58        for waker in wakers {
59            waker.wake();
60        }
61    }
62}
63
64impl Drop for OnceEvent {
65    fn drop(&mut self) {
66        if !self.used.fired_mut() {
67            // SAFETY: this is only dropped here and taken in `fire()`,
68            // but it also sets the `used` flag which is checked above.
69            unsafe { ManuallyDrop::drop(self.wakers.get()) };
70        }
71    }
72}