use core::{
any::Provider,
task::{RawWaker, RawWakerVTable, Waker},
};
#[derive(Copy, Clone)]
pub struct ProviderWaker<'a, 'b> {
waker: &'a Waker,
provider: &'b dyn Provider,
}
impl<'a, 'b> ProviderWaker<'a, 'b> {
pub fn new(waker: &'a Waker, provider: &'b dyn Provider) -> Self {
Self { waker, provider }
}
}
static VTABLE: RawWakerVTable = {
unsafe fn clone(waker: *const ()) -> RawWaker {
let inner = (*waker.cast::<ProviderWaker>()).waker.clone();
core::mem::transmute(inner)
}
unsafe fn wake_by_ref(waker: *const ()) {
(*waker.cast::<ProviderWaker>()).waker.wake_by_ref()
}
unsafe fn wake(_: *const ()) {
}
unsafe fn drop(_: *const ()) {
}
RawWakerVTable::new(clone, wake, wake_by_ref, drop)
};
impl<'a, 'b> ProviderWaker<'a, 'b> {
pub fn use_waker_with<R>(&self, f: impl for<'w> FnOnce(&'w Waker) -> R) -> R {
let ptr = (self as *const Self).cast();
let waker = unsafe { &Waker::from_raw(RawWaker::new(ptr, &VTABLE)) };
f(waker)
}
pub fn from_waker_ref(waker: &Waker) -> Option<&Self> {
if waker.as_raw().vtable() == &VTABLE {
Some(unsafe { &*waker.as_raw().data().cast::<Self>() })
} else {
None
}
}
}
impl Provider for ProviderWaker<'_, '_> {
fn provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) {
self.provider.provide(demand);
if let Some(cx) = Self::from_waker_ref(self.waker) {
cx.provide(demand)
}
}
}