use iris_core::HasState; use std::{ pin::Pin, sync::{ Arc, mpsc::{Receiver as SyncReceiver, Sender as SyncSender, channel as sync_channel}, }, }; use tokio::{ runtime::Runtime, sync::mpsc::{ UnboundedReceiver as AsyncReceiver, UnboundedSender as AsyncSender, unbounded_channel as async_channel, }, }; use winit::window::Window; pub type TaskMsgSender = SyncSender>>; pub type TaskMsgReceiver = SyncReceiver>>; pub trait TaskUpdate: FnOnce(&mut Rsc::State, &mut Rsc) + Send {} impl TaskUpdate for F {} pub struct Tasks { start: AsyncSender, window: Arc, msg_send: SyncSender>>, } pub struct TaskCtx { send: TaskMsgSender, } impl TaskCtx { pub fn update(&mut self, f: impl TaskUpdate + 'static) { let _ = self.send.send(Box::new(f)); } } impl TaskCtx { fn new(send: TaskMsgSender) -> Self { Self { send } } } type BoxTask = Pin + Send>>; impl Tasks { pub fn init(window: Arc) -> (Self, TaskMsgReceiver) { let (start, start_recv) = async_channel(); let (msgs, msgs_recv) = sync_channel(); std::thread::spawn(|| { let rt = Runtime::new().unwrap(); rt.block_on(listen(start_recv)) }); ( Self { start, msg_send: msgs, window, }, msgs_recv, ) } pub fn spawn) + 'static + std::marker::Send>(&mut self, task: F) where F::CallOnceFuture: Send, { let send = self.msg_send.clone(); let window = self.window.clone(); let _ = self.start.send(Box::pin(async move { task(TaskCtx::new(send)).await; window.request_redraw(); })); } } async fn listen(mut recv: AsyncReceiver) { while let Some(task) = recv.recv().await { tokio::spawn(task); } }