@@ -7,12 +7,11 @@ use std::rc::Rc;
77pub ( crate ) type Shared < T > = Rc < RefCell < T > > ;
88
99thread_local ! {
10- static SCHEDULER : Rc <Scheduler > =
11- Rc :: new( Scheduler :: new( ) ) ;
12- }
13-
14- pub ( crate ) fn scheduler ( ) -> Rc < Scheduler > {
15- SCHEDULER . with ( Rc :: clone)
10+ /// This is a global scheduler suitable to schedule and run any tasks.
11+ ///
12+ /// Exclusivity of mutable access is controlled by only accessing it through a set of public
13+ /// functions.
14+ static SCHEDULER : RefCell <Scheduler > = Default :: default ( ) ;
1615}
1716
1817/// A routine which could be run.
@@ -22,98 +21,95 @@ pub(crate) trait Runnable {
2221}
2322
2423/// This is a global scheduler suitable to schedule and run any tasks.
25- #[ derive( Clone ) ]
26- pub ( crate ) struct Scheduler {
27- /// This lock is used to prevent recursion in [Scheduler#start()](Scheduler#start())
28- lock : Rc < RefCell < ( ) > > ,
29- main : Shared < VecDeque < Box < dyn Runnable > > > ,
30- pub ( crate ) component : ComponentScheduler ,
31- }
24+ #[ derive( Default ) ]
25+ struct Scheduler {
26+ // Main queue
27+ main : VecDeque < Box < dyn Runnable > > ,
28+
29+ // Component queues
30+ destroy : VecDeque < Box < dyn Runnable > > ,
31+ create : VecDeque < Box < dyn Runnable > > ,
32+ update : VecDeque < Box < dyn Runnable > > ,
33+ render : VecDeque < Box < dyn Runnable > > ,
3234
33- pub ( crate ) enum ComponentRunnableType {
34- Create ,
35- Update ,
36- Render ,
37- Rendered ,
38- Destroy ,
35+ // Stack
36+ rendered : Vec < Box < dyn Runnable > > ,
3937}
4038
41- #[ derive( Clone ) ]
42- pub ( crate ) struct ComponentScheduler {
43- // Queues
44- destroy : Shared < VecDeque < Box < dyn Runnable > > > ,
45- create : Shared < VecDeque < Box < dyn Runnable > > > ,
46- update : Shared < VecDeque < Box < dyn Runnable > > > ,
47- render : Shared < VecDeque < Box < dyn Runnable > > > ,
39+ /// Execute closure with a mutable reference to the scheduler
40+ #[ inline]
41+ fn with ( f : impl FnOnce ( & mut Scheduler ) ) {
42+ SCHEDULER . with ( |s| f ( & mut * s. borrow_mut ( ) ) ) ;
43+ }
4844
49- // Stack
50- rendered : Shared < Vec < Box < dyn Runnable > > > ,
45+ /// Push a generic Runnable to be executed
46+ #[ inline]
47+ pub ( crate ) fn push ( runnable : Box < dyn Runnable > ) {
48+ with ( |s| s. main . push_back ( runnable) ) ;
5149}
5250
53- impl ComponentScheduler {
54- fn new ( ) -> Self {
55- ComponentScheduler {
56- destroy : Rc :: new ( RefCell :: new ( VecDeque :: new ( ) ) ) ,
57- create : Rc :: new ( RefCell :: new ( VecDeque :: new ( ) ) ) ,
58- update : Rc :: new ( RefCell :: new ( VecDeque :: new ( ) ) ) ,
59- render : Rc :: new ( RefCell :: new ( VecDeque :: new ( ) ) ) ,
60- rendered : Rc :: new ( RefCell :: new ( Vec :: new ( ) ) ) ,
61- }
62- }
51+ /// Push a component creation Runnable to be executed
52+ #[ inline]
53+ pub ( crate ) fn push_component_create ( runnable : Box < dyn Runnable > ) {
54+ with ( |s| s. create . push_back ( runnable) ) ;
55+ }
6356
64- pub ( crate ) fn push_update_batch ( & self , it : impl IntoIterator < Item = Box < dyn Runnable > > ) {
65- self . update . borrow_mut ( ) . extend ( it) ;
66- }
57+ /// Push a component destruction Runnable to be executed
58+ #[ inline]
59+ pub ( crate ) fn push_component_destroy ( runnable : Box < dyn Runnable > ) {
60+ with ( |s| s. destroy . push_back ( runnable) ) ;
61+ }
6762
68- pub ( crate ) fn push ( & self , run_type : ComponentRunnableType , runnable : Box < dyn Runnable > ) {
69- match run_type {
70- ComponentRunnableType :: Create => self . create . borrow_mut ( ) . push_back ( runnable) ,
71- ComponentRunnableType :: Update => self . update . borrow_mut ( ) . push_back ( runnable) ,
72- ComponentRunnableType :: Render => self . render . borrow_mut ( ) . push_back ( runnable) ,
73- ComponentRunnableType :: Rendered => self . rendered . borrow_mut ( ) . push ( runnable) ,
74- ComponentRunnableType :: Destroy => self . destroy . borrow_mut ( ) . push_back ( runnable) ,
75- } ;
76- }
63+ /// Push a component render Runnable to be executed
64+ #[ inline]
65+ pub ( crate ) fn push_component_render ( runnable : Box < dyn Runnable > ) {
66+ with ( |s| s. render . push_back ( runnable) ) ;
67+ }
7768
78- fn next_runnable ( & self ) -> Option < Box < dyn Runnable > > {
79- self . destroy
80- . borrow_mut ( )
81- . pop_front ( )
82- . or_else ( || self . create . borrow_mut ( ) . pop_front ( ) )
83- . or_else ( || self . update . borrow_mut ( ) . pop_front ( ) )
84- . or_else ( || self . render . borrow_mut ( ) . pop_front ( ) )
85- . or_else ( || self . rendered . borrow_mut ( ) . pop ( ) )
86- }
69+ /// Push a component Runnable to be executed after a component is rendered
70+ #[ inline]
71+ pub ( crate ) fn push_component_rendered ( runnable : Box < dyn Runnable > ) {
72+ with ( |s| s. rendered . push ( runnable) ) ;
8773}
8874
89- impl Scheduler {
90- fn new ( ) -> Self {
91- Scheduler {
92- lock : Rc :: new ( RefCell :: new ( ( ) ) ) ,
93- main : Rc :: new ( RefCell :: new ( VecDeque :: new ( ) ) ) ,
94- component : ComponentScheduler :: new ( ) ,
95- }
96- }
75+ /// Push a component update Runnable to be executed
76+ #[ inline]
77+ pub ( crate ) fn push_component_update ( runnable : Box < dyn Runnable > ) {
78+ with ( |s| s. update . push_back ( runnable) ) ;
79+ }
9780
98- pub ( crate ) fn push ( & self , runnable : Box < dyn Runnable > ) {
99- self . main . borrow_mut ( ) . push_back ( runnable) ;
100- self . start ( ) ;
101- }
81+ /// Push a batch of component updates to be executed
82+ #[ inline]
83+ pub ( crate ) fn push_component_updates ( it : impl IntoIterator < Item = Box < dyn Runnable > > ) {
84+ with ( |s| s. update . extend ( it) ) ;
85+ }
10286
103- fn next_runnable ( & self ) -> Option < Box < dyn Runnable > > {
104- self . component
105- . next_runnable ( )
106- . or_else ( || self . main . borrow_mut ( ) . pop_front ( ) )
87+ /// Execute any pending Runnables
88+ pub ( crate ) fn start ( ) {
89+ thread_local ! {
90+ // The lock is used to prevent recursion. If the lock cannot be acquired, it is because the
91+ // `start()` method is being called recursively as part of a `runnable.run()`.
92+ static LOCK : RefCell <( ) > = Default :: default ( ) ;
10793 }
10894
109- pub ( crate ) fn start ( & self ) {
110- // The lock is used to prevent recursion. If the lock
111- // cannot be acquired, it is because the `start()` method
112- // is being called recursively as part of a `runnable.run()`.
113- if let Ok ( _lock) = self . lock . try_borrow_mut ( ) {
114- while let Some ( runnable) = self . next_runnable ( ) {
95+ LOCK . with ( |l| {
96+ if let Ok ( _lock) = l. try_borrow_mut ( ) {
97+ while let Some ( runnable) = SCHEDULER . with ( |s| s. borrow_mut ( ) . next_runnable ( ) ) {
11598 runnable. run ( ) ;
11699 }
117100 }
101+ } ) ;
102+ }
103+
104+ impl Scheduler {
105+ /// Pop next Runnable to be executed according to Runnable type execution priority
106+ fn next_runnable ( & mut self ) -> Option < Box < dyn Runnable > > {
107+ self . destroy
108+ . pop_front ( )
109+ . or_else ( || self . create . pop_front ( ) )
110+ . or_else ( || self . update . pop_front ( ) )
111+ . or_else ( || self . render . pop_front ( ) )
112+ . or_else ( || self . rendered . pop ( ) )
113+ . or_else ( || self . main . pop_front ( ) )
118114 }
119115}
0 commit comments