@@ -15,14 +15,10 @@ use serde::{Deserialize, Serialize};
1515use thiserror:: Error ;
1616use uuid:: Uuid ;
1717
18- // macro_export puts it in the root,
19- // so we re-export here so you can use as either
20- // hyperware_process_lib::run_async
21- // or
22- // hyperware_process_lib::hyperapp::run_async
23- pub use crate :: run_async;
24-
2518thread_local ! {
19+ static SPAWN_QUEUE : RefCell <Vec <Pin <Box <dyn Future <Output = ( ) >>>>> = RefCell :: new( Vec :: new( ) ) ;
20+
21+
2622 pub static APP_CONTEXT : RefCell <AppContext > = RefCell :: new( AppContext {
2723 hidden_state: None ,
2824 executor: Executor :: new( ) ,
@@ -140,27 +136,46 @@ pub struct Executor {
140136 tasks : Vec < Pin < Box < dyn Future < Output = ( ) > > > > ,
141137}
142138
139+ pub fn spawn ( fut : impl Future < Output = ( ) > + ' static ) {
140+ SPAWN_QUEUE . with ( |queue| {
141+ queue. borrow_mut ( ) . push ( Box :: pin ( fut) ) ;
142+ } )
143+ }
144+
143145impl Executor {
144146 pub fn new ( ) -> Self {
145147 Self { tasks : Vec :: new ( ) }
146148 }
147149
148- pub fn spawn ( & mut self , fut : impl Future < Output = ( ) > + ' static ) {
149- self . tasks . push ( Box :: pin ( fut) ) ;
150- }
151-
152150 pub fn poll_all_tasks ( & mut self ) {
153- let mut ctx = Context :: from_waker ( noop_waker_ref ( ) ) ;
154- let mut completed = Vec :: new ( ) ;
151+ loop {
152+ // Drain any newly spawned tasks into our task list
153+ SPAWN_QUEUE . with ( |queue| {
154+ self . tasks . append ( & mut queue. borrow_mut ( ) ) ;
155+ } ) ;
156+
157+ // Poll all tasks, collecting completed ones
158+ let mut completed = Vec :: new ( ) ;
159+ let mut ctx = Context :: from_waker ( noop_waker_ref ( ) ) ;
160+
161+ for i in 0 ..self . tasks . len ( ) {
162+ if let Poll :: Ready ( ( ) ) = self . tasks [ i] . as_mut ( ) . poll ( & mut ctx) {
163+ completed. push ( i) ;
164+ }
165+ }
155166
156- for i in 0 .. self . tasks . len ( ) {
157- if let Poll :: Ready ( ( ) ) = self . tasks [ i ] . as_mut ( ) . poll ( & mut ctx ) {
158- completed . push ( i ) ;
167+ // Remove completed tasks immediately to prevent re-polling
168+ for idx in completed . into_iter ( ) . rev ( ) {
169+ let _ = self . tasks . remove ( idx ) ;
159170 }
160- }
161171
162- for idx in completed. into_iter ( ) . rev ( ) {
163- let _ = self . tasks . remove ( idx) ;
172+ // Check if there are new tasks spawned during polling
173+ let has_new_tasks = SPAWN_QUEUE . with ( |queue| !queue. borrow ( ) . is_empty ( ) ) ;
174+
175+ // Continue if new tasks were spawned, otherwise we're done
176+ if !has_new_tasks {
177+ break ;
178+ }
164179 }
165180 }
166181}
@@ -282,17 +297,6 @@ where
282297 return Err ( AppSendError :: SendError ( e) ) ;
283298}
284299
285- #[ macro_export]
286- macro_rules! run_async {
287- ( $( $code: tt) * ) => {
288- hyperware_process_lib:: hyperapp:: APP_CONTEXT . with( |ctx| {
289- ctx. borrow_mut( ) . executor. spawn( async move {
290- $( $code) *
291- } )
292- } )
293- } ;
294- }
295-
296300// Enum defining the state persistance behaviour
297301#[ derive( Clone ) ]
298302pub enum SaveOptions {
0 commit comments