oneapi_rs/
event.rs

1//
2// Copyright (C) 2026 Intel Corporation
3//
4// Under the MIT License or the Apache License v2.0.
5// See LICENSE-MIT and LICENSE-APACHE for license information.
6// SPDX-License-Identifier: MIT OR Apache-2.0
7//
8
9use std::{
10    pin::Pin,
11    sync::atomic::Ordering::Relaxed,
12    task::{Context, Poll},
13};
14
15use oneapi_rs_sys::{event::ffi, types::SharedWaker};
16
17use pin_project::pin_project;
18
19use crate::{info::InfoTarget, private::Sealed, queue::Queue};
20
21pub struct Event(pub(crate) cxx::UniquePtr<ffi::Event>);
22
23impl Event {
24    pub fn wait(&mut self) {
25        ffi::wait(&mut self.0);
26    }
27}
28
29impl Sealed for Event {}
30impl InfoTarget for Event {}
31
32impl From<cxx::UniquePtr<ffi::Event>> for Event {
33    fn from(value: cxx::UniquePtr<ffi::Event>) -> Self {
34        Self(value)
35    }
36}
37
38impl Clone for Event {
39    fn clone(&self) -> Self {
40        ffi::clone(&self.0).into()
41    }
42}
43
44#[pin_project]
45pub struct EventFuture {
46    event: Event,
47    shared: SharedWaker,
48    set_callback: bool,
49    queue: Option<Queue>,
50}
51
52impl Future for EventFuture {
53    type Output = ();
54
55    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
56        let this = self.project();
57
58        // Set the callback on first Future poll (Futures can't be active until polled)
59        if *this.set_callback == false {
60            *this.set_callback = true;
61            let mut queue = Queue::new_immediate();
62            this.shared.waker.register(cx.waker());
63            // Safety: the SharedWaker will always outlive the C++ host task.
64            // Safety: the Future which holds the SharedWaker is pinned - the pointer will remain valid.
65            unsafe { ffi::register_callback(&mut queue.0, &this.event.0, this.shared) };
66            this.queue.replace(queue);
67        } else {
68            // Quick check before registering to avoid wasting time
69            if this.shared.done.load(Relaxed) {
70                return Poll::Ready(());
71            }
72
73            this.shared.waker.register(cx.waker());
74        }
75
76        // Check the event again to avoid a race condition
77        // https://docs.rs/futures/latest/futures/task/struct.AtomicWaker.html#examples
78        if this.shared.done.load(Relaxed) {
79            Poll::Ready(())
80        } else {
81            Poll::Pending
82        }
83    }
84}
85
86impl IntoFuture for Event {
87    type Output = ();
88    type IntoFuture = EventFuture;
89
90    fn into_future(self) -> Self::IntoFuture {
91        EventFuture {
92            event: self,
93            shared: SharedWaker::new(),
94            set_callback: false,
95            queue: None,
96        }
97    }
98}