diff --git a/src/scheduler.rs b/src/scheduler.rs index c5b890c..53170d1 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -61,45 +61,56 @@ pub fn scheduler_mut(lua:&mlua::Lua,mut f:impl FnMut(&mut crate::scheduler::S let mut scheduler=lua.app_data_mut::().ok_or(mlua::Error::runtime("Scheduler missing"))?; f(&mut *scheduler) } + +fn schedule_thread(lua:&mlua::Lua,dt:mlua::Value)->Result<(),mlua::Error>{ + let delay=match dt{ + mlua::Value::Integer(i)=>i.max(0) as u64*60, + mlua::Value::Number(f)=>{ + let delay=f.max(0.0)*60.0; + match delay.classify(){ + std::num::FpCategory::Nan=>Err(mlua::Error::runtime("NaN"))?, + // cases where the number is too large to schedule + std::num::FpCategory::Infinite=>return Ok(()), + std::num::FpCategory::Normal=>if (u64::MAX as f64)(), + } + delay as u64 + }, + mlua::Value::Nil=>0, + _=>Err(mlua::Error::runtime("Expected float"))?, + }; + scheduler_mut(lua,|scheduler|{ + scheduler.schedule_thread(delay.max(2),lua.current_thread()); + Ok(()) + }) +} + +// This is used to avoid calling coroutine.yield from the rust side. +const LUA_WAIT:&str= +"local coroutine_yield=coroutine.yield +local schedule_thread=schedule_thread +return function(dt) + schedule_thread(dt) + return coroutine_yield() +end"; + pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{ - let schedule_thread=lua.create_function(|lua,dt:mlua::Value|{ - let delay=match dt{ - mlua::Value::Integer(i)=>i.max(0) as u64*60, - mlua::Value::Number(f)=>{ - let delay=f.max(0.0)*60.0; - match delay.classify(){ - std::num::FpCategory::Nan=>Err(mlua::Error::runtime("NaN"))?, - // cases where the number is too large to schedule - std::num::FpCategory::Infinite=>return Ok(()), - std::num::FpCategory::Normal=>if (u64::MAX as f64)(), - } - delay as u64 - }, - mlua::Value::Nil=>0, - _=>Err(mlua::Error::runtime("Expected float"))?, - }; - scheduler_mut(lua,|scheduler|{ - scheduler.schedule_thread(delay.max(2),lua.current_thread()); - Ok(()) - }) - })?; + let coroutine_table=globals.get::("coroutine")?; + let schedule_thread=lua.create_function(schedule_thread)?; + + //create wait function environment let wait_env=lua.create_table()?; - wait_env.raw_set("coroutine",globals.get::("coroutine")?)?; + wait_env.raw_set("coroutine",coroutine_table)?; wait_env.raw_set("schedule_thread",schedule_thread)?; - let wait=lua.load(" - local coroutine_yield=coroutine.yield - local schedule_thread=schedule_thread - return function(dt) - schedule_thread(dt) - return coroutine_yield() - end - ") + + //construct wait function from Lua code + let wait=lua.load(LUA_WAIT) .set_name("wait") .set_environment(wait_env) .call::(())?; + globals.raw_set("wait",wait)?; Ok(())