From e6faa3f6be27ac0f9dc7a5d0d019290e7676554b Mon Sep 17 00:00:00 2001 From: Filip Tibell Date: Sat, 21 Jan 2023 15:30:22 -0500 Subject: [PATCH] Use plain tables instead of userdata for globals --- src/lib/globals/console.rs | 41 ++++++----------- src/lib/globals/fs.rs | 39 ++++++----------- src/lib/globals/mod.rs | 10 ++--- src/lib/globals/net.rs | 29 ++++-------- src/lib/globals/process.rs | 90 ++++++++++++++------------------------ src/lib/globals/task.rs | 54 +++++++++++------------ src/lib/lib.rs | 12 ++--- 7 files changed, 105 insertions(+), 170 deletions(-) diff --git a/src/lib/globals/console.rs b/src/lib/globals/console.rs index 514d2ec..95176dd 100644 --- a/src/lib/globals/console.rs +++ b/src/lib/globals/console.rs @@ -1,35 +1,22 @@ -use mlua::{Lua, MultiValue, Result, UserData, UserDataMethods}; +use mlua::{Lua, MultiValue, Result, Table}; use crate::utils::formatting::{ flush_stdout, pretty_format_multi_value, print_color, print_label, print_style, }; -pub struct Console(); - -impl Console { - pub fn new() -> Self { - Self() - } -} - -impl Default for Console { - fn default() -> Self { - Self::new() - } -} - -impl UserData for Console { - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { - methods.add_function("resetColor", console_reset_color); - methods.add_function("setColor", console_set_color); - methods.add_function("resetStyle", console_reset_style); - methods.add_function("setStyle", console_set_style); - methods.add_function("format", console_format); - methods.add_function("log", console_log); - methods.add_function("info", console_info); - methods.add_function("warn", console_warn); - methods.add_function("error", console_error); - } +pub fn new(lua: &Lua) -> Result { + let tab = lua.create_table()?; + tab.raw_set("resetColor", lua.create_function(console_reset_color)?)?; + tab.raw_set("setColor", lua.create_function(console_set_color)?)?; + tab.raw_set("resetStyle", lua.create_function(console_reset_style)?)?; + tab.raw_set("setStyle", lua.create_function(console_set_style)?)?; + tab.raw_set("format", lua.create_function(console_format)?)?; + tab.raw_set("log", lua.create_function(console_log)?)?; + tab.raw_set("info", lua.create_function(console_info)?)?; + tab.raw_set("warn", lua.create_function(console_warn)?)?; + tab.raw_set("error", lua.create_function(console_error)?)?; + tab.set_readonly(true); + Ok(tab) } fn console_reset_color(_: &Lua, _: ()) -> Result<()> { diff --git a/src/lib/globals/fs.rs b/src/lib/globals/fs.rs index 930dbdf..063771c 100644 --- a/src/lib/globals/fs.rs +++ b/src/lib/globals/fs.rs @@ -1,33 +1,20 @@ use std::path::{PathBuf, MAIN_SEPARATOR}; -use mlua::{Lua, Result, UserData, UserDataMethods}; +use mlua::{Lua, Result, Table}; use tokio::fs; -pub struct Fs(); - -impl Fs { - pub fn new() -> Self { - Self() - } -} - -impl Default for Fs { - fn default() -> Self { - Self::new() - } -} - -impl UserData for Fs { - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { - methods.add_async_function("readFile", fs_read_file); - methods.add_async_function("readDir", fs_read_dir); - methods.add_async_function("writeFile", fs_write_file); - methods.add_async_function("writeDir", fs_write_dir); - methods.add_async_function("removeFile", fs_remove_file); - methods.add_async_function("removeDir", fs_remove_dir); - methods.add_async_function("isFile", fs_is_file); - methods.add_async_function("isDir", fs_is_dir); - } +pub fn new(lua: &Lua) -> Result
{ + let tab = lua.create_table()?; + tab.raw_set("readFile", lua.create_async_function(fs_read_file)?)?; + tab.raw_set("readDir", lua.create_async_function(fs_read_dir)?)?; + tab.raw_set("writeFile", lua.create_async_function(fs_write_file)?)?; + tab.raw_set("writeDir", lua.create_async_function(fs_write_dir)?)?; + tab.raw_set("removeFile", lua.create_async_function(fs_remove_file)?)?; + tab.raw_set("removeDir", lua.create_async_function(fs_remove_dir)?)?; + tab.raw_set("isFile", lua.create_async_function(fs_is_file)?)?; + tab.raw_set("isDir", lua.create_async_function(fs_is_dir)?)?; + tab.set_readonly(true); + Ok(tab) } async fn fs_read_file(_: &Lua, path: String) -> Result { diff --git a/src/lib/globals/mod.rs b/src/lib/globals/mod.rs index 9842355..4ecc1c5 100644 --- a/src/lib/globals/mod.rs +++ b/src/lib/globals/mod.rs @@ -4,8 +4,8 @@ mod net; mod process; mod task; -pub use console::Console as ConsoleGlobal; -pub use fs::Fs as FsGlobal; -pub use net::Net as NetGlobal; -pub use process::Process as ProcessGlobal; -pub use task::Task as TaskGlobal; +pub use console::new as new_console; +pub use fs::new as new_fs; +pub use net::new as new_net; +pub use process::new as new_process; +pub use task::new as new_task; diff --git a/src/lib/globals/net.rs b/src/lib/globals/net.rs index 7aaa385..5cbdc86 100644 --- a/src/lib/globals/net.rs +++ b/src/lib/globals/net.rs @@ -1,6 +1,6 @@ use std::{collections::HashMap, str::FromStr}; -use mlua::{Error, Lua, LuaSerdeExt, Result, UserData, UserDataMethods, Value}; +use mlua::{Error, Lua, LuaSerdeExt, Result, Table, Value}; use reqwest::{ header::{HeaderMap, HeaderName, HeaderValue}, Method, @@ -8,26 +8,13 @@ use reqwest::{ use crate::utils::net::get_request_user_agent_header; -pub struct Net(); - -impl Net { - pub fn new() -> Self { - Self() - } -} - -impl Default for Net { - fn default() -> Self { - Self::new() - } -} - -impl UserData for Net { - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { - methods.add_function("jsonEncode", net_json_encode); - methods.add_function("jsonDecode", net_json_decode); - methods.add_async_function("request", net_request); - } +pub fn new(lua: &Lua) -> Result
{ + let tab = lua.create_table()?; + tab.raw_set("jsonEncode", lua.create_function(net_json_encode)?)?; + tab.raw_set("jsonDecode", lua.create_function(net_json_decode)?)?; + tab.raw_set("request", lua.create_async_function(net_request)?)?; + tab.set_readonly(true); + Ok(tab) } fn net_json_encode(_: &Lua, (val, pretty): (Value, Option)) -> Result { diff --git a/src/lib/globals/process.rs b/src/lib/globals/process.rs index 4cffd26..5c10ca5 100644 --- a/src/lib/globals/process.rs +++ b/src/lib/globals/process.rs @@ -3,66 +3,44 @@ use std::{ process::{exit, Stdio}, }; -use mlua::{ - Error, Function, Lua, MetaMethod, Result, Table, UserData, UserDataFields, UserDataMethods, - Value, -}; +use mlua::{Error, Function, Lua, MetaMethod, Result, Table, Value}; use os_str_bytes::RawOsString; use tokio::process::Command; -pub struct Process { - args: Vec, -} - -impl Default for Process { - fn default() -> Self { - Self::new(vec![]) - } -} - -impl Process { - pub fn new(args: Vec) -> Self { - Self { args } - } -} - -impl UserData for Process { - fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("args", |lua, this| { - // TODO: Use the same strategy as env uses below to avoid - // copying each time args are accessed? is it worth it? - let tab = lua.create_table()?; - for arg in &this.args { - tab.push(arg.clone())?; - } - tab.set_readonly(true); - Ok(tab) - }); - fields.add_field_method_get("env", |lua, _| { - let meta = lua.create_table()?; - meta.raw_set( - MetaMethod::Index.name(), - lua.create_function(process_env_get)?, - )?; - meta.raw_set( - MetaMethod::NewIndex.name(), - lua.create_function(process_env_set)?, - )?; - meta.raw_set( - MetaMethod::Iter.name(), - lua.create_function(process_env_iter)?, - )?; - let tab = lua.create_table()?; - tab.set_metatable(Some(meta)); - tab.set_readonly(true); - Ok(tab) - }); - } - - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { - methods.add_function("exit", process_exit); - methods.add_async_function("spawn", process_spawn); +pub fn new(lua: &Lua, args_vec: Vec) -> Result
{ + // Create readonly args array + let inner_args = lua.create_table()?; + for arg in &args_vec { + inner_args.push(arg.clone())?; } + inner_args.set_readonly(true); + // Create proxied env metatable that gets & sets real env vars + let inner_env_meta = lua.create_table()?; + inner_env_meta.raw_set( + MetaMethod::Index.name(), + lua.create_function(process_env_get)?, + )?; + inner_env_meta.raw_set( + MetaMethod::NewIndex.name(), + lua.create_function(process_env_set)?, + )?; + inner_env_meta.raw_set( + MetaMethod::Iter.name(), + lua.create_function(process_env_iter)?, + )?; + inner_env_meta.set_readonly(true); + // Create blank table for env with the metatable + let inner_env = lua.create_table()?; + inner_env.set_metatable(Some(inner_env_meta)); + inner_env.set_readonly(true); + // Create the full process table + let tab = lua.create_table()?; + tab.raw_set("args", inner_args)?; + tab.raw_set("env", inner_env)?; + tab.raw_set("exit", lua.create_function(process_exit)?)?; + tab.raw_set("spawn", lua.create_async_function(process_spawn)?)?; + tab.set_readonly(true); + Ok(tab) } fn process_env_get<'lua>(lua: &'lua Lua, (_, key): (Value<'lua>, String)) -> Result> { diff --git a/src/lib/globals/task.rs b/src/lib/globals/task.rs index fae3111..9139738 100644 --- a/src/lib/globals/task.rs +++ b/src/lib/globals/task.rs @@ -1,36 +1,25 @@ use std::time::Duration; -use mlua::{Function, UserData, UserDataMethods, Value, Variadic}; +use mlua::{Function, Lua, Result, Table, Value, Variadic}; use tokio::time; const DEFAULT_SLEEP_DURATION: f32 = 1.0 / 60.0; -pub struct Task(); - -impl Task { - pub fn new() -> Self { - Self() - } -} - -impl Default for Task { - fn default() -> Self { - Self::new() - } -} - -impl UserData for Task { - fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { - methods.add_async_function( - "defer", +pub fn new(lua: &Lua) -> Result
{ + let tab = lua.create_table()?; + tab.raw_set( + "defer", + lua.create_async_function( |lua, (func, args): (Function, Variadic)| async move { let thread = lua.create_thread(func)?; thread.into_async(args).await?; Ok(()) }, - ); - methods.add_async_function( - "delay", + )?, + )?; + tab.raw_set( + "delay", + lua.create_async_function( |lua, (func, duration, args): (Function, Option, Variadic)| async move { let secs = duration.unwrap_or(DEFAULT_SLEEP_DURATION); time::sleep(Duration::from_secs_f32(secs)).await; @@ -38,19 +27,26 @@ impl UserData for Task { thread.into_async(args).await?; Ok(()) }, - ); - methods.add_async_function( - "spawn", + )?, + )?; + tab.raw_set( + "spawn", + lua.create_async_function( |lua, (func, args): (Function, Variadic)| async move { let thread = lua.create_thread(func)?; thread.into_async(args).await?; Ok(()) }, - ); - methods.add_async_function("wait", |_, duration: Option| async move { + )?, + )?; + tab.raw_set( + "wait", + lua.create_async_function(|_, duration: Option| async move { let secs = duration.unwrap_or(DEFAULT_SLEEP_DURATION); time::sleep(Duration::from_secs_f32(secs)).await; Ok(secs) - }); - } + })?, + )?; + tab.set_readonly(true); + Ok(tab) } diff --git a/src/lib/lib.rs b/src/lib/lib.rs index 9e5a5d1..b3d539d 100644 --- a/src/lib/lib.rs +++ b/src/lib/lib.rs @@ -5,7 +5,7 @@ pub mod globals; pub mod utils; use crate::{ - globals::{ConsoleGlobal, FsGlobal, NetGlobal, ProcessGlobal, TaskGlobal}, + globals::{new_console, new_fs, new_net, new_process, new_task}, utils::formatting::{pretty_print_luau_error, print_label}, }; @@ -29,11 +29,11 @@ impl Lune { pub fn with_default_globals(self) -> Result { { let globals = self.lua.globals(); - globals.raw_set("console", ConsoleGlobal::new())?; - globals.raw_set("fs", FsGlobal::new())?; - globals.raw_set("net", NetGlobal::new())?; - globals.raw_set("process", ProcessGlobal::new(self.args.clone()))?; - globals.raw_set("task", TaskGlobal::new())?; + globals.raw_set("console", new_console(&self.lua)?)?; + globals.raw_set("fs", new_fs(&self.lua)?)?; + globals.raw_set("net", new_net(&self.lua)?)?; + globals.raw_set("process", new_process(&self.lua, self.args.clone())?)?; + globals.raw_set("task", new_task(&self.lua)?)?; globals.set_readonly(true); } Ok(self)