BTZ5WJPNRJ4Y3JB77XZXQWDZV2SJ4WBMSYPITUYOWSR4GLRHU4GAC
ELBXLSZ3LKHEXX7T7FU2EE6UTZI2QXUTV4ZM66PGSKVLHSHXQVWAC
O5P6HCPWGMGJBFJEMC3SYQJ5OEW2AQV4KEJCMRVTTS3K6M45Z3BAC
OGNLZ5CUNFD7X43S4VTMCCEMJA2R76O35XACIR7AUBHPGME27E3AC
DZPGVVKGX6QS4HX5GVF3DR3UZAV2EOMMVRUDEGTR2OPJVDG3FNXQC
GKGOXYENXXG6XJXPLXVSWKOYWHZRKNT5JDTAAQ2XWWYGJTLFH5IAC
EEO6C4YSWFW3JOZ3JH6K7X4TKAUTVJD53CQNYZHI2QY6REGEXUCAC
L6RIUKGLJZLAOKFGUDTZKBPP4HUBPEZAKHJEQHO34WFF62AB2ZIQC
X5EMQBC4BFNJOOHS2QMF4UB4QH6JKSALK6RXLK6B7SP6MNYSAP6QC
KMU4E426CB2NDRJEK7B4GSL22P62CJPPZRK45X3JV5WP5NIBIGRQC
LJD76LBNKTWSAHLRGL7EXNMM5HYRSOD6VXWYQSX2XVK7TQROTZ6QC
SSJKQR6X6L2KUJI2YPLMBQU3PTR2RYAQQR6N35MDMOCOTV6ZDUEAC
7CBRRVV3GLVLBHNPQNRHSA2ZCLHIMCHFEMWMZNOICY2OZLB7DGPAC
Q6Z5IQJ3SUI7BUJCKT377EPIRO7UVZFI7UB74ZEEGTCTUKC7WGKQC
WQIQA2TNWNSNGKQC22XPTECAZEWG6PG5QWQECUVXDUQRSCV6RUZQC
GROTV3H2V6BHU5CA7WSLVYDCWAR7GHUP5JV2QOGPLJ6N3553T4MAC
DKGUNP6LG3DJ35VMHU42K3VJO5JJ5UVYI4PLM72HO5ZNAQ4P366AC
// Poor man's executor for winit's poor man's async
// taken from https://github.com/rust-windowing/winit/issues/1199#issuecomment-1685122253
type TaskId = usize;
#[derive(Debug)]
enum PollTask {
Task(TaskId),
}
type BoxedTaskFuture<E> = Box<dyn Future<Output = Result<(), E>>>;
struct WinitExecutor<E> {
// a better implementation should use a vec of options here.
tasks: HashMap<TaskId, Pin<BoxedTaskFuture<E>>>,
event_loop_proxy: EventLoopProxy<PollTask>,
}
impl<E> WinitExecutor<E> {
/// Create a new `WinitExecutor`, driven by the given event loop.
pub fn new(event_loop_proxy: EventLoopProxy<PollTask>) -> Self {
Self {
tasks: HashMap::new(),
event_loop_proxy,
}
}
fn next_task_id(&self) -> TaskId {
static NEXT_TASK_ID: std::sync::atomic::AtomicUsize =
std::sync::atomic::AtomicUsize::new(0);
NEXT_TASK_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
}
/// Spawn a task.
///
/// This immediately polls the task once, and then schedules it to be
/// polled again if needed, using a `UserEvent::PollTask` event.
pub fn spawn(&mut self, task: impl Future<Output = Result<(), E>> + 'static) -> Result<(), E> {
let task = Box::pin(task);
let task_id = self.next_task_id();
self.tasks.insert(task_id, task);
if let Some(res) = self.poll(task_id) {
res
} else {
self.event_loop_proxy
.send_event(PollTask::Task(task_id))
.unwrap();
Ok(())
}
}
/// Poll a task.
///
/// Should be called when the event loop receives a `UserEvent::PollTask`.
pub fn poll(&mut self, task_id: TaskId) -> Option<Result<(), E>> {
// this wake only need to work once, I believe, so we could use some type of "oneshot box"
// instead of a mutex?
let winit_proxy = Mutex::new(self.event_loop_proxy.clone());
let waker = waker_fn::waker_fn(move || {
let _ = winit_proxy
.lock()
.unwrap()
.send_event(PollTask::Task(task_id));
});
let task = self.tasks.get_mut(&task_id).unwrap().as_mut();
match task.poll(&mut Context::from_waker(&waker)) {
Poll::Ready(res) => {
_ = self.tasks.remove(&task_id);
Some(res)
}
Poll::Pending => None,
}
}
/// Retrieves the game lock
fn get_lock<'a, S>(&'a mut self, game: &'a AsyncMutex<Game<S>>) -> AsyncMutexGuard<Game<S>>
where
S: 'static,
{
let winit_proxy = Mutex::new(self.event_loop_proxy.clone());
let (tx, rx) = flume::bounded(1);
let waker = waker_fn::waker_fn(move || {
let id_to_poll = rx.recv().unwrap();
let _ = winit_proxy
.lock()
.unwrap()
.send_event(PollTask::Task(id_to_poll));
});
// self.lock_tasks.push_back(Box::pin(game.lock_arc()));
loop {
// Continuously try to get the lock until we succeed
let fut = game.lock();
let fut = pin!(fut);
let poll_status = fut.poll(&mut Context::from_waker(&waker));
if let Poll::Ready(res) = poll_status {
break res;
}
// Drive the task loop
if let Some(id) = self.tasks.keys().next().copied() {
tx.send(id).unwrap();
}
}
}
fn get_lock_owned<S>(&mut self, game: Arc<AsyncMutex<Game<S>>>) -> AsyncMutexGuardOwned<Game<S>>
where
S: 'static,
{
let winit_proxy = Mutex::new(self.event_loop_proxy.clone());
let (tx, rx) = flume::unbounded();
let waker = waker_fn::waker_fn(move || {
let id_to_poll = rx.recv().unwrap();
let _ = winit_proxy
.lock()
.unwrap()
.send_event(PollTask::Task(id_to_poll));
});
// self.lock_tasks.push_back(Box::pin(game.lock_arc()));
let mut fut = Box::pin(game.lock_arc());
loop {
let fut = pin!(fut.as_mut());
let poll_status = fut.poll(&mut Context::from_waker(&waker));
if let Poll::Ready(res) = poll_status {
break res;
}
// Drive the task loop
if let Some(id) = self.tasks.keys().next().copied() {
tx.send(id).unwrap();
}
}
}
}
let mut game = winit_executor.get_lock_owned(game.clone());
winit_executor
.spawn({
async move {
let future = game.create_surface();
future.await
}
})
.unwrap();
}
Event::UserEvent(poll_task) => {
match poll_task {
// a certain task needs polling
PollTask::Task(tid) => {
if let Some(res) = winit_executor.poll(tid) {
// the stuff here shouldn't fail
res.unwrap()
}
}
}
let game = game.clone();
let assets = assets.clone();
outer_cosync.queue(|_input: cosync::CosyncInput<()>| async move {
game.try_lock()
.unwrap()
.create_surface(&assets)
.await
.unwrap();
})
name = "poll-promise"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f6a58fecbf9da8965bcdb20ce4fd29788d1acee68ddbb64f0ba1b81bccdb7df"
dependencies = [
"document-features",
"static_assertions",
"wasm-bindgen",
"wasm-bindgen-futures",
]
[[package]]