Use static lua lifetime

This commit is contained in:
Filip Tibell 2023-02-11 12:39:39 +01:00
parent 709a69aa82
commit 6c49ef7e4a
No known key found for this signature in database
11 changed files with 74 additions and 79 deletions

View file

@ -5,7 +5,7 @@ use tokio::fs;
use crate::utils::table::TableBuilder; use crate::utils::table::TableBuilder;
pub fn create(lua: &Lua) -> LuaResult<LuaTable> { pub fn create(lua: &'static Lua) -> LuaResult<LuaTable> {
TableBuilder::new(lua)? TableBuilder::new(lua)?
.with_async_function("readFile", fs_read_file)? .with_async_function("readFile", fs_read_file)?
.with_async_function("readDir", fs_read_dir)? .with_async_function("readDir", fs_read_dir)?
@ -18,11 +18,11 @@ pub fn create(lua: &Lua) -> LuaResult<LuaTable> {
.build_readonly() .build_readonly()
} }
async fn fs_read_file(_: &Lua, path: String) -> LuaResult<String> { async fn fs_read_file(_: &'static Lua, path: String) -> LuaResult<String> {
fs::read_to_string(&path).await.map_err(LuaError::external) fs::read_to_string(&path).await.map_err(LuaError::external)
} }
async fn fs_read_dir(_: &Lua, path: String) -> LuaResult<Vec<String>> { async fn fs_read_dir(_: &'static Lua, path: String) -> LuaResult<Vec<String>> {
let mut dir_strings = Vec::new(); let mut dir_strings = Vec::new();
let mut dir = fs::read_dir(&path).await.map_err(LuaError::external)?; let mut dir = fs::read_dir(&path).await.map_err(LuaError::external)?;
while let Some(dir_entry) = dir.next_entry().await.map_err(LuaError::external)? { while let Some(dir_entry) = dir.next_entry().await.map_err(LuaError::external)? {
@ -52,25 +52,25 @@ async fn fs_read_dir(_: &Lua, path: String) -> LuaResult<Vec<String>> {
Ok(dir_strings_no_prefix) Ok(dir_strings_no_prefix)
} }
async fn fs_write_file(_: &Lua, (path, contents): (String, String)) -> LuaResult<()> { async fn fs_write_file(_: &'static Lua, (path, contents): (String, String)) -> LuaResult<()> {
fs::write(&path, &contents) fs::write(&path, &contents)
.await .await
.map_err(LuaError::external) .map_err(LuaError::external)
} }
async fn fs_write_dir(_: &Lua, path: String) -> LuaResult<()> { async fn fs_write_dir(_: &'static Lua, path: String) -> LuaResult<()> {
fs::create_dir_all(&path).await.map_err(LuaError::external) fs::create_dir_all(&path).await.map_err(LuaError::external)
} }
async fn fs_remove_file(_: &Lua, path: String) -> LuaResult<()> { async fn fs_remove_file(_: &'static Lua, path: String) -> LuaResult<()> {
fs::remove_file(&path).await.map_err(LuaError::external) fs::remove_file(&path).await.map_err(LuaError::external)
} }
async fn fs_remove_dir(_: &Lua, path: String) -> LuaResult<()> { async fn fs_remove_dir(_: &'static Lua, path: String) -> LuaResult<()> {
fs::remove_dir_all(&path).await.map_err(LuaError::external) fs::remove_dir_all(&path).await.map_err(LuaError::external)
} }
async fn fs_is_file(_: &Lua, path: String) -> LuaResult<bool> { async fn fs_is_file(_: &'static Lua, path: String) -> LuaResult<bool> {
let path = PathBuf::from(path); let path = PathBuf::from(path);
if path.exists() { if path.exists() {
Ok(fs::metadata(path) Ok(fs::metadata(path)
@ -82,7 +82,7 @@ async fn fs_is_file(_: &Lua, path: String) -> LuaResult<bool> {
} }
} }
async fn fs_is_dir(_: &Lua, path: String) -> LuaResult<bool> { async fn fs_is_dir(_: &'static Lua, path: String) -> LuaResult<bool> {
let path = PathBuf::from(path); let path = PathBuf::from(path);
if path.exists() { if path.exists() {
Ok(fs::metadata(path) Ok(fs::metadata(path)

View file

@ -78,7 +78,7 @@ impl LuneGlobal {
Note that proxy globals should be handled with special care and that [`LuneGlobal::inject()`] Note that proxy globals should be handled with special care and that [`LuneGlobal::inject()`]
should be preferred over manually creating and manipulating the value(s) of any Lune global. should be preferred over manually creating and manipulating the value(s) of any Lune global.
*/ */
pub fn value<'a>(&'a self, lua: &'a Lua) -> LuaResult<LuaTable> { pub fn value(&self, lua: &'static Lua) -> LuaResult<LuaTable> {
match self { match self {
LuneGlobal::Fs => fs::create(lua), LuneGlobal::Fs => fs::create(lua),
LuneGlobal::Net => net::create(lua), LuneGlobal::Net => net::create(lua),
@ -98,7 +98,7 @@ impl LuneGlobal {
Refer to [`LuneGlobal::is_top_level()`] for more info on proxy globals. Refer to [`LuneGlobal::is_top_level()`] for more info on proxy globals.
*/ */
pub fn inject(self, lua: &Lua) -> LuaResult<()> { pub fn inject(self, lua: &'static Lua) -> LuaResult<()> {
let globals = lua.globals(); let globals = lua.globals();
let table = self.value(lua)?; let table = self.value(lua)?;
// NOTE: Top level globals are special, the values // NOTE: Top level globals are special, the values

View file

@ -19,7 +19,7 @@ use crate::utils::{
table::TableBuilder, table::TableBuilder,
}; };
pub fn create(lua: &Lua) -> LuaResult<LuaTable> { pub fn create(lua: &'static Lua) -> LuaResult<LuaTable> {
// Create a reusable client for performing our // Create a reusable client for performing our
// web requests and store it in the lua registry // web requests and store it in the lua registry
let mut default_headers = HeaderMap::new(); let mut default_headers = HeaderMap::new();
@ -43,7 +43,7 @@ pub fn create(lua: &Lua) -> LuaResult<LuaTable> {
.build_readonly() .build_readonly()
} }
fn net_json_encode(_: &Lua, (val, pretty): (LuaValue, Option<bool>)) -> LuaResult<String> { fn net_json_encode(_: &'static Lua, (val, pretty): (LuaValue, Option<bool>)) -> LuaResult<String> {
if let Some(true) = pretty { if let Some(true) = pretty {
serde_json::to_string_pretty(&val).map_err(LuaError::external) serde_json::to_string_pretty(&val).map_err(LuaError::external)
} else { } else {
@ -51,12 +51,12 @@ fn net_json_encode(_: &Lua, (val, pretty): (LuaValue, Option<bool>)) -> LuaResul
} }
} }
fn net_json_decode(lua: &Lua, json: String) -> LuaResult<LuaValue> { fn net_json_decode(lua: &'static Lua, json: String) -> LuaResult<LuaValue> {
let json: serde_json::Value = serde_json::from_str(&json).map_err(LuaError::external)?; let json: serde_json::Value = serde_json::from_str(&json).map_err(LuaError::external)?;
lua.to_value(&json) lua.to_value(&json)
} }
async fn net_request<'lua>(lua: &'lua Lua, config: LuaValue<'lua>) -> LuaResult<LuaTable<'lua>> { async fn net_request<'a>(lua: &'static Lua, config: LuaValue<'a>) -> LuaResult<LuaTable<'a>> {
let client: NetClient = lua.named_registry_value("NetClient")?; let client: NetClient = lua.named_registry_value("NetClient")?;
// Extract stuff from config and make sure its all valid // Extract stuff from config and make sure its all valid
let (url, method, headers, body) = match config { let (url, method, headers, body) = match config {
@ -147,20 +147,16 @@ async fn net_request<'lua>(lua: &'lua Lua, config: LuaValue<'lua>) -> LuaResult<
.build_readonly() .build_readonly()
} }
async fn net_serve<'lua>( async fn net_serve(lua: &'static Lua, (port, callback): (u16, LuaFunction<'_>)) -> LuaResult<()> {
lua: &'lua Lua,
(port, callback): (u16, LuaFunction<'lua>),
) -> LuaResult<()> {
let server_lua = lua.app_data_ref::<Weak<Lua>>().unwrap().upgrade().unwrap();
let server_sender = lua let server_sender = lua
.app_data_ref::<Weak<Sender<LuneMessage>>>() .app_data_ref::<Weak<Sender<LuneMessage>>>()
.unwrap() .unwrap()
.upgrade() .upgrade()
.unwrap(); .unwrap();
let server_callback = server_lua.create_registry_value(callback)?; let server_callback = lua.create_registry_value(callback)?;
let server = Server::bind(&([127, 0, 0, 1], port).into()) let server = Server::bind(&([127, 0, 0, 1], port).into())
.executor(LocalExec) .executor(LocalExec)
.serve(MakeNetService(server_lua, server_callback.into())); .serve(MakeNetService(lua, server_callback.into()));
if let Err(err) = server.await.map_err(LuaError::external) { if let Err(err) = server.await.map_err(LuaError::external) {
server_sender server_sender
.send(LuneMessage::LuaError(err)) .send(LuneMessage::LuaError(err))
@ -173,7 +169,7 @@ async fn net_serve<'lua>(
// Hyper service implementation for net, lots of boilerplate here // Hyper service implementation for net, lots of boilerplate here
// but make_svc and make_svc_function do not work for what we need // but make_svc and make_svc_function do not work for what we need
pub struct NetService(Arc<Lua>, Arc<LuaRegistryKey>); pub struct NetService(&'static Lua, Arc<LuaRegistryKey>);
impl Service<Request<Body>> for NetService { impl Service<Request<Body>> for NetService {
type Response = Response<Body>; type Response = Response<Body>;
@ -185,7 +181,7 @@ impl Service<Request<Body>> for NetService {
} }
fn call(&mut self, req: Request<Body>) -> Self::Future { fn call(&mut self, req: Request<Body>) -> Self::Future {
let lua = self.0.clone(); let lua = self.0;
let key = self.1.clone(); let key = self.1.clone();
let (parts, body) = req.into_parts(); let (parts, body) = req.into_parts();
Box::pin(async move { Box::pin(async move {
@ -199,7 +195,7 @@ impl Service<Request<Body>> for NetService {
.upgrade() .upgrade()
.unwrap(); .unwrap();
// Create a readonly table for the request query params // Create a readonly table for the request query params
let query_params = TableBuilder::new(&lua)? let query_params = TableBuilder::new(lua)?
.with_values( .with_values(
parts parts
.uri .uri
@ -211,7 +207,7 @@ impl Service<Request<Body>> for NetService {
)? )?
.build_readonly()?; .build_readonly()?;
// Do the same for headers // Do the same for headers
let header_map = TableBuilder::new(&lua)? let header_map = TableBuilder::new(lua)?
.with_values( .with_values(
parts parts
.headers .headers
@ -223,7 +219,7 @@ impl Service<Request<Body>> for NetService {
)? )?
.build_readonly()?; .build_readonly()?;
// Create a readonly table with request info to pass to the handler // Create a readonly table with request info to pass to the handler
let request = TableBuilder::new(&lua)? let request = TableBuilder::new(lua)?
.with_value("path", parts.uri.path())? .with_value("path", parts.uri.path())?
.with_value("query", query_params)? .with_value("query", query_params)?
.with_value("method", parts.method.as_str())? .with_value("method", parts.method.as_str())?
@ -287,7 +283,7 @@ impl Service<Request<Body>> for NetService {
} }
} }
struct MakeNetService(Arc<Lua>, Arc<LuaRegistryKey>); struct MakeNetService(&'static Lua, Arc<LuaRegistryKey>);
impl Service<&AddrStream> for MakeNetService { impl Service<&AddrStream> for MakeNetService {
type Response = NetService; type Response = NetService;
@ -299,7 +295,7 @@ impl Service<&AddrStream> for MakeNetService {
} }
fn call(&mut self, _: &AddrStream) -> Self::Future { fn call(&mut self, _: &AddrStream) -> Self::Future {
let lua = self.0.clone(); let lua = self.0;
let key = self.1.clone(); let key = self.1.clone();
Box::pin(async move { Ok(NetService(lua, key)) }) Box::pin(async move { Ok(NetService(lua, key)) })
} }

View file

@ -10,7 +10,7 @@ use crate::utils::{
table::TableBuilder, table::TableBuilder,
}; };
pub fn create(lua: &Lua, args_vec: Vec<String>) -> LuaResult<LuaTable> { pub fn create(lua: &'static Lua, args_vec: Vec<String>) -> LuaResult<LuaTable> {
let cwd = env::current_dir()?.canonicalize()?; let cwd = env::current_dir()?.canonicalize()?;
let mut cwd_str = cwd.to_string_lossy().to_string(); let mut cwd_str = cwd.to_string_lossy().to_string();
if !cwd_str.ends_with('/') { if !cwd_str.ends_with('/') {
@ -40,10 +40,10 @@ pub fn create(lua: &Lua, args_vec: Vec<String>) -> LuaResult<LuaTable> {
.build_readonly() .build_readonly()
} }
fn process_env_get<'lua>( fn process_env_get<'a>(
lua: &'lua Lua, lua: &'static Lua,
(_, key): (LuaValue<'lua>, String), (_, key): (LuaValue<'a>, String),
) -> LuaResult<LuaValue<'lua>> { ) -> LuaResult<LuaValue<'a>> {
match env::var_os(key) { match env::var_os(key) {
Some(value) => { Some(value) => {
let raw_value = RawOsString::new(value); let raw_value = RawOsString::new(value);
@ -55,7 +55,10 @@ fn process_env_get<'lua>(
} }
} }
fn process_env_set(_: &Lua, (_, key, value): (LuaValue, String, Option<String>)) -> LuaResult<()> { fn process_env_set(
_: &'static Lua,
(_, key, value): (LuaValue, String, Option<String>),
) -> LuaResult<()> {
// Make sure key is valid, otherwise set_var will panic // Make sure key is valid, otherwise set_var will panic
if key.is_empty() { if key.is_empty() {
Err(LuaError::RuntimeError("Key must not be empty".to_string())) Err(LuaError::RuntimeError("Key must not be empty".to_string()))
@ -106,12 +109,12 @@ fn process_env_iter<'lua>(
}) })
} }
async fn process_exit(lua: &Lua, exit_code: Option<u8>) -> LuaResult<()> { async fn process_exit(lua: &'static Lua, exit_code: Option<u8>) -> LuaResult<()> {
exit_and_yield_forever(lua, exit_code).await exit_and_yield_forever(lua, exit_code).await
} }
async fn process_spawn<'a>( async fn process_spawn<'a>(
lua: &'a Lua, lua: &'static Lua,
(mut program, args, options): (String, Option<Vec<String>>, Option<LuaTable<'a>>), (mut program, args, options): (String, Option<Vec<String>>, Option<LuaTable<'a>>),
) -> LuaResult<LuaTable<'a>> { ) -> LuaResult<LuaTable<'a>> {
// Parse any given options or create defaults // Parse any given options or create defaults

View file

@ -9,7 +9,7 @@ use os_str_bytes::{OsStrBytes, RawOsStr};
use crate::utils::table::TableBuilder; use crate::utils::table::TableBuilder;
pub fn create(lua: &Lua) -> LuaResult<LuaTable> { pub fn create(lua: &'static Lua) -> LuaResult<LuaTable> {
let require: LuaFunction = lua.globals().raw_get("require")?; let require: LuaFunction = lua.globals().raw_get("require")?;
// Preserve original require behavior if we have a special env var set // Preserve original require behavior if we have a special env var set
if env::var_os("LUAU_PWD_REQUIRE").is_some() { if env::var_os("LUAU_PWD_REQUIRE").is_some() {

View file

@ -8,7 +8,7 @@ use crate::utils::{
table::TableBuilder, table::TableBuilder,
}; };
pub fn create(lua: &Lua) -> LuaResult<LuaTable> { pub fn create(lua: &'static Lua) -> LuaResult<LuaTable> {
TableBuilder::new(lua)? TableBuilder::new(lua)?
.with_function("color", |_, color: String| { .with_function("color", |_, color: String| {
let ansi_string = format_style(style_from_color_str(&color)?); let ansi_string = format_style(style_from_color_str(&color)?);
@ -38,7 +38,7 @@ fn prompt_theme() -> ColorfulTheme {
} }
fn prompt<'a>( fn prompt<'a>(
lua: &'a Lua, lua: &'static Lua,
(kind, message, options): (Option<String>, Option<String>, LuaValue<'a>), (kind, message, options): (Option<String>, Option<String>, LuaValue<'a>),
) -> LuaResult<LuaValue<'a>> { ) -> LuaResult<LuaValue<'a>> {
match kind.map(|k| k.trim().to_ascii_lowercase()).as_deref() { match kind.map(|k| k.trim().to_ascii_lowercase()).as_deref() {

View file

@ -1,7 +1,4 @@
use std::{ use std::time::{Duration, Instant};
sync::Weak,
time::{Duration, Instant},
};
use mlua::prelude::*; use mlua::prelude::*;
use tokio::time; use tokio::time;
@ -13,7 +10,7 @@ use crate::utils::{
const MINIMUM_WAIT_OR_DELAY_DURATION: f32 = 10.0 / 1_000.0; // 10ms const MINIMUM_WAIT_OR_DELAY_DURATION: f32 = 10.0 / 1_000.0; // 10ms
pub fn create(lua: &Lua) -> LuaResult<LuaTable> { pub fn create(lua: &'static Lua) -> LuaResult<LuaTable> {
// HACK: There is no way to call coroutine.close directly from the mlua // HACK: There is no way to call coroutine.close directly from the mlua
// crate, so we need to fetch the function and store it in the registry // crate, so we need to fetch the function and store it in the registry
let coroutine: LuaTable = lua.globals().raw_get("coroutine")?; let coroutine: LuaTable = lua.globals().raw_get("coroutine")?;
@ -33,8 +30,11 @@ pub fn create(lua: &Lua) -> LuaResult<LuaTable> {
.build_readonly() .build_readonly()
} }
fn tof_to_thread<'a>(lua: &'a Lua, tof: LuaValue<'a>) -> LuaResult<LuaThread<'a>> { fn tof_to_thread<'a>(
match tof { lua: &'static Lua,
thread_or_function: LuaValue<'a>,
) -> LuaResult<LuaThread<'a>> {
match thread_or_function {
LuaValue::Thread(t) => Ok(t), LuaValue::Thread(t) => Ok(t),
LuaValue::Function(f) => Ok(lua.create_thread(f)?), LuaValue::Function(f) => Ok(lua.create_thread(f)?),
value => Err(LuaError::RuntimeError(format!( value => Err(LuaError::RuntimeError(format!(
@ -44,31 +44,29 @@ fn tof_to_thread<'a>(lua: &'a Lua, tof: LuaValue<'a>) -> LuaResult<LuaThread<'a>
} }
} }
async fn task_cancel<'a>(lua: &'a Lua, thread: LuaThread<'a>) -> LuaResult<()> { async fn task_cancel<'a>(lua: &'static Lua, thread: LuaThread<'a>) -> LuaResult<()> {
let close: LuaFunction = lua.named_registry_value("coroutine.close")?; let close: LuaFunction = lua.named_registry_value("coroutine.close")?;
close.call_async::<_, LuaMultiValue>(thread).await?; close.call_async::<_, LuaMultiValue>(thread).await?;
Ok(()) Ok(())
} }
async fn task_defer<'a>( async fn task_defer<'a>(
lua: &'a Lua, lua: &'static Lua,
(tof, args): (LuaValue<'a>, LuaMultiValue<'a>), (tof, args): (LuaValue<'a>, LuaMultiValue<'a>),
) -> LuaResult<LuaThread<'a>> { ) -> LuaResult<LuaThread<'a>> {
// Spawn a new detached task using a lua reference that we can use inside of our task
let task_lua = lua.app_data_ref::<Weak<Lua>>().unwrap().upgrade().unwrap();
let task_thread = tof_to_thread(lua, tof)?; let task_thread = tof_to_thread(lua, tof)?;
let task_thread_key = lua.create_registry_value(task_thread)?; let task_thread_key = lua.create_registry_value(task_thread)?;
let task_args_key = lua.create_registry_value(args.into_vec())?; let task_args_key = lua.create_registry_value(args.into_vec())?;
let lua_thread_to_return = lua.registry_value(&task_thread_key)?; let lua_thread_to_return = lua.registry_value(&task_thread_key)?;
run_registered_task(lua, TaskRunMode::Deferred, async move { run_registered_task(lua, TaskRunMode::Deferred, async move {
let thread: LuaThread = task_lua.registry_value(&task_thread_key)?; let thread: LuaThread = lua.registry_value(&task_thread_key)?;
let argsv: Vec<LuaValue> = task_lua.registry_value(&task_args_key)?; let argsv: Vec<LuaValue> = lua.registry_value(&task_args_key)?;
let args = LuaMultiValue::from_vec(argsv); let args = LuaMultiValue::from_vec(argsv);
if thread.status() == LuaThreadStatus::Resumable { if thread.status() == LuaThreadStatus::Resumable {
let _: LuaMultiValue = thread.into_async(args).await?; let _: LuaMultiValue = thread.into_async(args).await?;
} }
task_lua.remove_registry_value(task_thread_key)?; lua.remove_registry_value(task_thread_key)?;
task_lua.remove_registry_value(task_args_key)?; lua.remove_registry_value(task_args_key)?;
Ok(()) Ok(())
}) })
.await?; .await?;
@ -76,25 +74,23 @@ async fn task_defer<'a>(
} }
async fn task_delay<'a>( async fn task_delay<'a>(
lua: &'a Lua, lua: &'static Lua,
(duration, tof, args): (Option<f32>, LuaValue<'a>, LuaMultiValue<'a>), (duration, tof, args): (Option<f32>, LuaValue<'a>, LuaMultiValue<'a>),
) -> LuaResult<LuaThread<'a>> { ) -> LuaResult<LuaThread<'a>> {
// Spawn a new detached task using a lua reference that we can use inside of our task
let task_lua = lua.app_data_ref::<Weak<Lua>>().unwrap().upgrade().unwrap();
let task_thread = tof_to_thread(lua, tof)?; let task_thread = tof_to_thread(lua, tof)?;
let task_thread_key = lua.create_registry_value(task_thread)?; let task_thread_key = lua.create_registry_value(task_thread)?;
let task_args_key = lua.create_registry_value(args.into_vec())?; let task_args_key = lua.create_registry_value(args.into_vec())?;
let lua_thread_to_return = lua.registry_value(&task_thread_key)?; let lua_thread_to_return = lua.registry_value(&task_thread_key)?;
run_registered_task(lua, TaskRunMode::Deferred, async move { run_registered_task(lua, TaskRunMode::Deferred, async move {
task_wait(&task_lua, duration).await?; task_wait(lua, duration).await?;
let thread: LuaThread = task_lua.registry_value(&task_thread_key)?; let thread: LuaThread = lua.registry_value(&task_thread_key)?;
let argsv: Vec<LuaValue> = task_lua.registry_value(&task_args_key)?; let argsv: Vec<LuaValue> = lua.registry_value(&task_args_key)?;
let args = LuaMultiValue::from_vec(argsv); let args = LuaMultiValue::from_vec(argsv);
if thread.status() == LuaThreadStatus::Resumable { if thread.status() == LuaThreadStatus::Resumable {
let _: LuaMultiValue = thread.into_async(args).await?; let _: LuaMultiValue = thread.into_async(args).await?;
} }
task_lua.remove_registry_value(task_thread_key)?; lua.remove_registry_value(task_thread_key)?;
task_lua.remove_registry_value(task_args_key)?; lua.remove_registry_value(task_args_key)?;
Ok(()) Ok(())
}) })
.await?; .await?;
@ -102,31 +98,29 @@ async fn task_delay<'a>(
} }
async fn task_spawn<'a>( async fn task_spawn<'a>(
lua: &'a Lua, lua: &'static Lua,
(tof, args): (LuaValue<'a>, LuaMultiValue<'a>), (tof, args): (LuaValue<'a>, LuaMultiValue<'a>),
) -> LuaResult<LuaThread<'a>> { ) -> LuaResult<LuaThread<'a>> {
// Spawn a new detached task using a lua reference that we can use inside of our task
let task_lua = lua.app_data_ref::<Weak<Lua>>().unwrap().upgrade().unwrap();
let task_thread = tof_to_thread(lua, tof)?; let task_thread = tof_to_thread(lua, tof)?;
let task_thread_key = lua.create_registry_value(task_thread)?; let task_thread_key = lua.create_registry_value(task_thread)?;
let task_args_key = lua.create_registry_value(args.into_vec())?; let task_args_key = lua.create_registry_value(args.into_vec())?;
let lua_thread_to_return = lua.registry_value(&task_thread_key)?; let lua_thread_to_return = lua.registry_value(&task_thread_key)?;
run_registered_task(lua, TaskRunMode::Instant, async move { run_registered_task(lua, TaskRunMode::Instant, async move {
let thread: LuaThread = task_lua.registry_value(&task_thread_key)?; let thread: LuaThread = lua.registry_value(&task_thread_key)?;
let argsv: Vec<LuaValue> = task_lua.registry_value(&task_args_key)?; let argsv: Vec<LuaValue> = lua.registry_value(&task_args_key)?;
let args = LuaMultiValue::from_vec(argsv); let args = LuaMultiValue::from_vec(argsv);
if thread.status() == LuaThreadStatus::Resumable { if thread.status() == LuaThreadStatus::Resumable {
let _: LuaMultiValue = thread.into_async(args).await?; let _: LuaMultiValue = thread.into_async(args).await?;
} }
task_lua.remove_registry_value(task_thread_key)?; lua.remove_registry_value(task_thread_key)?;
task_lua.remove_registry_value(task_args_key)?; lua.remove_registry_value(task_args_key)?;
Ok(()) Ok(())
}) })
.await?; .await?;
Ok(lua_thread_to_return) Ok(lua_thread_to_return)
} }
async fn task_wait(lua: &Lua, duration: Option<f32>) -> LuaResult<f32> { async fn task_wait(lua: &'static Lua, duration: Option<f32>) -> LuaResult<f32> {
let start = Instant::now(); let start = Instant::now();
run_registered_task(lua, TaskRunMode::Blocking, async move { run_registered_task(lua, TaskRunMode::Blocking, async move {
time::sleep(Duration::from_secs_f32( time::sleep(Duration::from_secs_f32(

View file

@ -5,7 +5,7 @@ use crate::utils::{
table::TableBuilder, table::TableBuilder,
}; };
pub fn create(lua: &Lua) -> LuaResult<LuaTable> { pub fn create(lua: &'static Lua) -> LuaResult<LuaTable> {
let globals = lua.globals(); let globals = lua.globals();
// HACK: We need to preserve the default behavior of the // HACK: We need to preserve the default behavior of the
// print and error functions, for pcall and such, which // print and error functions, for pcall and such, which

View file

@ -76,6 +76,10 @@ impl Lune {
Some Lune globals such as [`LuneGlobal::Process`] may spawn Some Lune globals such as [`LuneGlobal::Process`] may spawn
separate tokio tasks on other threads, but the Luau environment separate tokio tasks on other threads, but the Luau environment
itself is guaranteed to run on a single thread in the local set. itself is guaranteed to run on a single thread in the local set.
Note that this will create a static Lua instance that will live
for the remainer of the program, and that this leaks memory using
[`Box::leak`] that will then get deallocated when the program exits.
*/ */
pub async fn run( pub async fn run(
&self, &self,
@ -84,18 +88,16 @@ impl Lune {
) -> Result<ExitCode, LuaError> { ) -> Result<ExitCode, LuaError> {
let task_set = task::LocalSet::new(); let task_set = task::LocalSet::new();
let (sender, mut receiver) = mpsc::channel::<LuneMessage>(64); let (sender, mut receiver) = mpsc::channel::<LuneMessage>(64);
let lua = Arc::new(mlua::Lua::new()); let lua = Lua::new().into_static();
let snd = Arc::new(sender); let snd = Arc::new(sender);
lua.set_app_data(Arc::downgrade(&lua));
lua.set_app_data(Arc::downgrade(&snd)); lua.set_app_data(Arc::downgrade(&snd));
// Add in wanted lune globals // Add in wanted lune globals
for global in self.includes.clone() { for global in self.includes.clone() {
if !self.excludes.contains(&global) { if !self.excludes.contains(&global) {
global.inject(&lua)?; global.inject(lua)?;
} }
} }
// Spawn the main thread from our entrypoint script // Spawn the main thread from our entrypoint script
let script_lua = lua.clone();
let script_name = script_name.to_string(); let script_name = script_name.to_string();
let script_chunk = script_contents.to_string(); let script_chunk = script_contents.to_string();
let script_sender = snd.clone(); let script_sender = snd.clone();
@ -104,7 +106,7 @@ impl Lune {
.await .await
.map_err(LuaError::external)?; .map_err(LuaError::external)?;
task_set.spawn_local(async move { task_set.spawn_local(async move {
let result = script_lua let result = lua
.load(&script_chunk) .load(&script_chunk)
.set_name(&format!("={script_name}")) .set_name(&format!("={script_name}"))
.unwrap() .unwrap()

View file

@ -41,7 +41,7 @@ pub async fn pipe_and_inherit_child_process_stdio(
Ok::<_, LuaError>((status, stdout_buffer?, stderr_buffer?)) Ok::<_, LuaError>((status, stdout_buffer?, stderr_buffer?))
} }
pub async fn exit_and_yield_forever(lua: &Lua, exit_code: Option<u8>) -> LuaResult<()> { pub async fn exit_and_yield_forever(lua: &'static Lua, exit_code: Option<u8>) -> LuaResult<()> {
let sender = lua let sender = lua
.app_data_ref::<Weak<Sender<LuneMessage>>>() .app_data_ref::<Weak<Sender<LuneMessage>>>()
.unwrap() .unwrap()

View file

@ -26,7 +26,7 @@ impl fmt::Display for TaskRunMode {
} }
pub async fn run_registered_task<T>( pub async fn run_registered_task<T>(
lua: &Lua, lua: &'static Lua,
mode: TaskRunMode, mode: TaskRunMode,
to_run: impl Future<Output = LuaResult<T>> + 'static, to_run: impl Future<Output = LuaResult<T>> + 'static,
) -> LuaResult<()> { ) -> LuaResult<()> {