use std::{
cell::RefCell,
future::{poll_fn, Future},
pin::{pin, Pin},
task::{Poll, Waker},
};
use async_ui_internal_utils::dummy_waker::dummy_waker;
pub struct DynamicSlot<F: Future> {
channel: RefCell<(Waker, Message<F>)>,
}
enum Message<F> {
Set(F),
Clear,
NoChange,
}
impl<F: Future> Default for DynamicSlot<F> {
fn default() -> Self {
Self::new()
}
}
impl<F: Future> DynamicSlot<F> {
pub fn new() -> Self {
Self {
channel: RefCell::new((dummy_waker(), Message::NoChange)),
}
}
pub async fn render(&self) {
let mut fut_slot: Pin<&mut Option<F>> = pin!(None);
poll_fn(|cx| {
{
let mut channel = self.channel.borrow_mut();
match std::mem::replace(&mut channel.1, Message::NoChange) {
Message::Set(new_fut) => fut_slot.set(Some(new_fut)),
Message::Clear => fut_slot.set(None),
Message::NoChange => {}
}
if !channel.0.will_wake(cx.waker()) {
channel.0 = cx.waker().to_owned();
}
}
if let Some(fut) = fut_slot.as_mut().as_pin_mut() {
let _ = fut.poll(cx);
}
Poll::Pending
})
.await
}
pub fn set_future(&self, fut: F) {
let mut channel = self.channel.borrow_mut();
channel.1 = Message::Set(fut);
channel.0.wake_by_ref();
}
pub fn clear_future(&self) {
let mut channel = self.channel.borrow_mut();
channel.1 = Message::Clear;
channel.0.wake_by_ref();
}
}