Compare commits

...

2 Commits

Author SHA1 Message Date
bc9724e9de Scheduler lives in Lua 2024-10-16 16:40:35 -07:00
19e1f80530 scheduler 2024-10-16 15:37:19 -07:00
3 changed files with 75 additions and 6 deletions

View File

@ -1,5 +1,6 @@
pub mod runner; pub mod runner;
pub mod context; pub mod context;
pub(crate) mod scheduler;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;

View File

@ -60,9 +60,10 @@ impl Runner{
} }
//this makes set_app_data shut up about the lifetime //this makes set_app_data shut up about the lifetime
self.lua.set_app_data::<&'static mut rbx_dom_weak::WeakDom>(unsafe{core::mem::transmute(&mut context.dom)}); self.lua.set_app_data::<&'static mut rbx_dom_weak::WeakDom>(unsafe{core::mem::transmute(&mut context.dom)});
self.lua.set_app_data::<crate::scheduler::Scheduler>(crate::scheduler::Scheduler::default());
Ok(Runnable{ Ok(Runnable{
lua:self.lua, lua:self.lua,
_lifetime:&std::marker::PhantomData _lifetime:&std::marker::PhantomData,
}) })
} }
} }
@ -70,20 +71,32 @@ impl Runner{
//Runnable is the same thing but has context set, which it holds the lifetime for. //Runnable is the same thing but has context set, which it holds the lifetime for.
pub struct Runnable<'a>{ pub struct Runnable<'a>{
lua:mlua::Lua, lua:mlua::Lua,
_lifetime:&'a std::marker::PhantomData<()> _lifetime:&'a std::marker::PhantomData<()>,
} }
impl Runnable<'_>{ impl Runnable<'_>{
pub fn drop_context(self)->Runner{ pub fn drop_context(self)->Runner{
self.lua.remove_app_data::<&'static mut rbx_dom_weak::WeakDom>(); self.lua.remove_app_data::<&'static mut rbx_dom_weak::WeakDom>();
self.lua.remove_app_data::<crate::scheduler::Scheduler>();
Runner{ Runner{
lua:self.lua, lua:self.lua,
} }
} }
pub fn run_script(&self,script:super::instance::Instance)->Result<(),Error>{ pub fn run_script(&self,script:super::instance::Instance)->Result<(),Error>{
let (name,source)=super::instance::get_name_source(&self.lua,script).map_err(Error::RustLua)?; let (name,source)=super::instance::get_name_source(&self.lua,script).map_err(Error::RustLua)?;
self.lua.globals().set("script",script).map_err(Error::RustLua)?; let fenv=self.lua.create_table().map_err(Error::RustLua)?;
self.lua.load(source.as_str()) //there's gotta be a more concise way to do this
.set_name(name) for pair in self.lua.globals().pairs::<mlua::Value,mlua::Value>(){
.exec().map_err(|error|Error::Lua{source,error}) let (k,v)=pair.map_err(Error::RustLua)?;
fenv.raw_set(k,v).map_err(Error::RustLua)?;
}
fenv.raw_set("script",script).map_err(Error::RustLua)?;
let f=self.lua.load(source.as_str())
.set_name(name).into_function().map_err(Error::RustLua)?;
f.set_environment(fenv).map_err(Error::RustLua)?;
let thread=self.lua.create_thread(f).map_err(Error::RustLua)?;
thread.resume::<mlua::MultiValue>(()).map_err(|error|Error::Lua{source,error})?;
// wait() is called from inside Lua and goes to a rust function that schedules the thread and then yields
// No need to schedule the thread here
Ok(())
} }
} }

55
src/scheduler.rs Normal file
View File

@ -0,0 +1,55 @@
pub use tick::Tick;
mod tick{
#[derive(Clone,Copy,Default,Hash,PartialEq,Eq,PartialOrd,Ord)]
pub struct Tick(u64);
impl Tick{
pub const fn new(value:u64)->Self{
Self(value)
}
pub const fn get(&self)->u64{
self.0
}
}
impl std::ops::Add<u64> for Tick{
type Output=Self;
fn add(self,rhs:u64)->Self::Output{
Self(self.0+rhs)
}
}
impl std::ops::Sub<u64> for Tick{
type Output=Self;
fn sub(self,rhs:u64)->Self::Output{
Self(self.0-rhs)
}
}
impl std::ops::AddAssign<u64> for Tick{
fn add_assign(&mut self,rhs:u64){
self.0+=rhs;
}
}
impl std::ops::SubAssign<u64> for Tick{
fn sub_assign(&mut self,rhs:u64){
self.0-=rhs;
}
}
}
#[derive(Default)]
pub struct Scheduler{
tick:Tick,
schedule:std::collections::HashMap<Tick,Vec<mlua::Thread>>,
}
impl Scheduler{
pub const fn tick(&self)->Tick{
self.tick
}
pub fn schedule_thread(&mut self,delay:u64,thread:mlua::Thread){
self.schedule.entry(self.tick+delay.min(1))
.or_insert(Vec::new())
.push(thread);
}
pub fn tick_threads(&mut self)->Option<Vec<mlua::Thread>>{
self.tick+=1;
self.schedule.remove(&self.tick)
}
}