Use plain tables instead of userdata for globals

This commit is contained in:
Filip Tibell 2023-01-21 15:30:22 -05:00
parent d5b3d3f94b
commit e6faa3f6be
No known key found for this signature in database
7 changed files with 105 additions and 170 deletions

View file

@ -1,35 +1,22 @@
use mlua::{Lua, MultiValue, Result, UserData, UserDataMethods}; use mlua::{Lua, MultiValue, Result, Table};
use crate::utils::formatting::{ use crate::utils::formatting::{
flush_stdout, pretty_format_multi_value, print_color, print_label, print_style, flush_stdout, pretty_format_multi_value, print_color, print_label, print_style,
}; };
pub struct Console(); pub fn new(lua: &Lua) -> Result<Table> {
let tab = lua.create_table()?;
impl Console { tab.raw_set("resetColor", lua.create_function(console_reset_color)?)?;
pub fn new() -> Self { tab.raw_set("setColor", lua.create_function(console_set_color)?)?;
Self() 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)?)?;
impl Default for Console { tab.raw_set("info", lua.create_function(console_info)?)?;
fn default() -> Self { tab.raw_set("warn", lua.create_function(console_warn)?)?;
Self::new() tab.raw_set("error", lua.create_function(console_error)?)?;
} tab.set_readonly(true);
} Ok(tab)
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);
}
} }
fn console_reset_color(_: &Lua, _: ()) -> Result<()> { fn console_reset_color(_: &Lua, _: ()) -> Result<()> {

View file

@ -1,33 +1,20 @@
use std::path::{PathBuf, MAIN_SEPARATOR}; use std::path::{PathBuf, MAIN_SEPARATOR};
use mlua::{Lua, Result, UserData, UserDataMethods}; use mlua::{Lua, Result, Table};
use tokio::fs; use tokio::fs;
pub struct Fs(); pub fn new(lua: &Lua) -> Result<Table> {
let tab = lua.create_table()?;
impl Fs { tab.raw_set("readFile", lua.create_async_function(fs_read_file)?)?;
pub fn new() -> Self { tab.raw_set("readDir", lua.create_async_function(fs_read_dir)?)?;
Self() 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)?)?;
impl Default for Fs { tab.raw_set("isFile", lua.create_async_function(fs_is_file)?)?;
fn default() -> Self { tab.raw_set("isDir", lua.create_async_function(fs_is_dir)?)?;
Self::new() tab.set_readonly(true);
} Ok(tab)
}
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);
}
} }
async fn fs_read_file(_: &Lua, path: String) -> Result<String> { async fn fs_read_file(_: &Lua, path: String) -> Result<String> {

View file

@ -4,8 +4,8 @@ mod net;
mod process; mod process;
mod task; mod task;
pub use console::Console as ConsoleGlobal; pub use console::new as new_console;
pub use fs::Fs as FsGlobal; pub use fs::new as new_fs;
pub use net::Net as NetGlobal; pub use net::new as new_net;
pub use process::Process as ProcessGlobal; pub use process::new as new_process;
pub use task::Task as TaskGlobal; pub use task::new as new_task;

View file

@ -1,6 +1,6 @@
use std::{collections::HashMap, str::FromStr}; 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::{ use reqwest::{
header::{HeaderMap, HeaderName, HeaderValue}, header::{HeaderMap, HeaderName, HeaderValue},
Method, Method,
@ -8,26 +8,13 @@ use reqwest::{
use crate::utils::net::get_request_user_agent_header; use crate::utils::net::get_request_user_agent_header;
pub struct Net(); pub fn new(lua: &Lua) -> Result<Table> {
let tab = lua.create_table()?;
impl Net { tab.raw_set("jsonEncode", lua.create_function(net_json_encode)?)?;
pub fn new() -> Self { tab.raw_set("jsonDecode", lua.create_function(net_json_decode)?)?;
Self() tab.raw_set("request", lua.create_async_function(net_request)?)?;
} tab.set_readonly(true);
} Ok(tab)
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);
}
} }
fn net_json_encode(_: &Lua, (val, pretty): (Value, Option<bool>)) -> Result<String> { fn net_json_encode(_: &Lua, (val, pretty): (Value, Option<bool>)) -> Result<String> {

View file

@ -3,66 +3,44 @@ use std::{
process::{exit, Stdio}, process::{exit, Stdio},
}; };
use mlua::{ use mlua::{Error, Function, Lua, MetaMethod, Result, Table, Value};
Error, Function, Lua, MetaMethod, Result, Table, UserData, UserDataFields, UserDataMethods,
Value,
};
use os_str_bytes::RawOsString; use os_str_bytes::RawOsString;
use tokio::process::Command; use tokio::process::Command;
pub struct Process { pub fn new(lua: &Lua, args_vec: Vec<String>) -> Result<Table> {
args: Vec<String>, // Create readonly args array
} let inner_args = lua.create_table()?;
for arg in &args_vec {
impl Default for Process { inner_args.push(arg.clone())?;
fn default() -> Self {
Self::new(vec![])
}
}
impl Process {
pub fn new(args: Vec<String>) -> 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);
} }
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<Value<'lua>> { fn process_env_get<'lua>(lua: &'lua Lua, (_, key): (Value<'lua>, String)) -> Result<Value<'lua>> {

View file

@ -1,36 +1,25 @@
use std::time::Duration; use std::time::Duration;
use mlua::{Function, UserData, UserDataMethods, Value, Variadic}; use mlua::{Function, Lua, Result, Table, Value, Variadic};
use tokio::time; use tokio::time;
const DEFAULT_SLEEP_DURATION: f32 = 1.0 / 60.0; const DEFAULT_SLEEP_DURATION: f32 = 1.0 / 60.0;
pub struct Task(); pub fn new(lua: &Lua) -> Result<Table> {
let tab = lua.create_table()?;
impl Task { tab.raw_set(
pub fn new() -> Self { "defer",
Self() lua.create_async_function(
}
}
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",
|lua, (func, args): (Function, Variadic<Value>)| async move { |lua, (func, args): (Function, Variadic<Value>)| async move {
let thread = lua.create_thread(func)?; let thread = lua.create_thread(func)?;
thread.into_async(args).await?; thread.into_async(args).await?;
Ok(()) Ok(())
}, },
); )?,
methods.add_async_function( )?;
"delay", tab.raw_set(
"delay",
lua.create_async_function(
|lua, (func, duration, args): (Function, Option<f32>, Variadic<Value>)| async move { |lua, (func, duration, args): (Function, Option<f32>, Variadic<Value>)| async move {
let secs = duration.unwrap_or(DEFAULT_SLEEP_DURATION); let secs = duration.unwrap_or(DEFAULT_SLEEP_DURATION);
time::sleep(Duration::from_secs_f32(secs)).await; time::sleep(Duration::from_secs_f32(secs)).await;
@ -38,19 +27,26 @@ impl UserData for Task {
thread.into_async(args).await?; thread.into_async(args).await?;
Ok(()) Ok(())
}, },
); )?,
methods.add_async_function( )?;
"spawn", tab.raw_set(
"spawn",
lua.create_async_function(
|lua, (func, args): (Function, Variadic<Value>)| async move { |lua, (func, args): (Function, Variadic<Value>)| async move {
let thread = lua.create_thread(func)?; let thread = lua.create_thread(func)?;
thread.into_async(args).await?; thread.into_async(args).await?;
Ok(()) Ok(())
}, },
); )?,
methods.add_async_function("wait", |_, duration: Option<f32>| async move { )?;
tab.raw_set(
"wait",
lua.create_async_function(|_, duration: Option<f32>| async move {
let secs = duration.unwrap_or(DEFAULT_SLEEP_DURATION); let secs = duration.unwrap_or(DEFAULT_SLEEP_DURATION);
time::sleep(Duration::from_secs_f32(secs)).await; time::sleep(Duration::from_secs_f32(secs)).await;
Ok(secs) Ok(secs)
}); })?,
} )?;
tab.set_readonly(true);
Ok(tab)
} }

View file

@ -5,7 +5,7 @@ pub mod globals;
pub mod utils; pub mod utils;
use crate::{ 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}, utils::formatting::{pretty_print_luau_error, print_label},
}; };
@ -29,11 +29,11 @@ impl Lune {
pub fn with_default_globals(self) -> Result<Self> { pub fn with_default_globals(self) -> Result<Self> {
{ {
let globals = self.lua.globals(); let globals = self.lua.globals();
globals.raw_set("console", ConsoleGlobal::new())?; globals.raw_set("console", new_console(&self.lua)?)?;
globals.raw_set("fs", FsGlobal::new())?; globals.raw_set("fs", new_fs(&self.lua)?)?;
globals.raw_set("net", NetGlobal::new())?; globals.raw_set("net", new_net(&self.lua)?)?;
globals.raw_set("process", ProcessGlobal::new(self.args.clone()))?; globals.raw_set("process", new_process(&self.lua, self.args.clone())?)?;
globals.raw_set("task", TaskGlobal::new())?; globals.raw_set("task", new_task(&self.lua)?)?;
globals.set_readonly(true); globals.set_readonly(true);
} }
Ok(self) Ok(self)