Use mlua prelude instead of manual imports

This commit is contained in:
Filip Tibell 2023-01-22 21:31:55 -05:00
parent 09a7619995
commit d531cf3813
No known key found for this signature in database
8 changed files with 160 additions and 146 deletions

View file

@ -2,6 +2,7 @@ use std::fs::read_to_string;
use anyhow::Result; use anyhow::Result;
use clap::{CommandFactory, Parser}; use clap::{CommandFactory, Parser};
use mlua::prelude::*;
use lune::Lune; use lune::Lune;
@ -61,20 +62,20 @@ impl Cli {
let release = client let release = client
.fetch_release_for_this_version() .fetch_release_for_this_version()
.await .await
.map_err(mlua::Error::external)?; .map_err(LuaError::external)?;
if self.download_selene_types { if self.download_selene_types {
println!("Downloading Selene type definitions..."); println!("Downloading Selene type definitions...");
client client
.fetch_release_asset(&release, "lune.yml") .fetch_release_asset(&release, "lune.yml")
.await .await
.map_err(mlua::Error::external)?; .map_err(LuaError::external)?;
} }
if self.download_luau_types { if self.download_luau_types {
println!("Downloading Luau type definitions..."); println!("Downloading Luau type definitions...");
client client
.fetch_release_asset(&release, "luneTypes.d.luau") .fetch_release_asset(&release, "luneTypes.d.luau")
.await .await
.map_err(mlua::Error::external)?; .map_err(LuaError::external)?;
} }
} }
if self.script_path.is_none() { if self.script_path.is_none() {

View file

@ -1,12 +1,12 @@
use mlua::{Lua, MultiValue, Result}; use mlua::prelude::*;
use crate::utils::{ use crate::utils::{
formatting::{flush_stdout, pretty_format_multi_value, print_color, print_label, print_style}, formatting::{flush_stdout, pretty_format_multi_value, print_color, print_label, print_style},
table_builder::TableBuilder, table_builder::TableBuilder,
}; };
pub async fn create(lua: &Lua) -> Result<()> { pub async fn create(lua: &Lua) -> LuaResult<()> {
let print = |args: &MultiValue, throw: bool| -> Result<()> { let print = |args: &LuaMultiValue, throw: bool| -> LuaResult<()> {
let s = pretty_format_multi_value(args)?; let s = pretty_format_multi_value(args)?;
if throw { if throw {
eprintln!("{s}"); eprintln!("{s}");
@ -23,19 +23,19 @@ pub async fn create(lua: &Lua) -> Result<()> {
.with_function("setColor", |_, color: String| print_color(color))? .with_function("setColor", |_, color: String| print_color(color))?
.with_function("resetStyle", |_, _: ()| print_style("reset"))? .with_function("resetStyle", |_, _: ()| print_style("reset"))?
.with_function("setStyle", |_, style: String| print_style(style))? .with_function("setStyle", |_, style: String| print_style(style))?
.with_function("format", |_, args: MultiValue| { .with_function("format", |_, args: LuaMultiValue| {
pretty_format_multi_value(&args) pretty_format_multi_value(&args)
})? })?
.with_function("log", move |_, args: MultiValue| print(&args, false))? .with_function("log", move |_, args: LuaMultiValue| print(&args, false))?
.with_function("info", move |_, args: MultiValue| { .with_function("info", move |_, args: LuaMultiValue| {
print_label("info")?; print_label("info")?;
print(&args, false) print(&args, false)
})? })?
.with_function("warn", move |_, args: MultiValue| { .with_function("warn", move |_, args: LuaMultiValue| {
print_label("warn")?; print_label("warn")?;
print(&args, false) print(&args, false)
})? })?
.with_function("error", move |_, args: MultiValue| { .with_function("error", move |_, args: LuaMultiValue| {
print_label("error")?; print_label("error")?;
print(&args, true) print(&args, true)
})? })?

View file

@ -1,11 +1,11 @@
use std::path::{PathBuf, MAIN_SEPARATOR}; use std::path::{PathBuf, MAIN_SEPARATOR};
use mlua::{Lua, Result}; use mlua::prelude::*;
use smol::{fs, prelude::*}; use smol::{fs, prelude::*};
use crate::utils::table_builder::TableBuilder; use crate::utils::table_builder::TableBuilder;
pub async fn create(lua: &Lua) -> Result<()> { pub async fn create(lua: &Lua) -> LuaResult<()> {
lua.globals().raw_set( lua.globals().raw_set(
"fs", "fs",
TableBuilder::new(lua)? TableBuilder::new(lua)?
@ -21,20 +21,18 @@ pub async fn create(lua: &Lua) -> Result<()> {
) )
} }
async fn fs_read_file(_: &Lua, path: String) -> Result<String> { async fn fs_read_file(_: &Lua, path: String) -> LuaResult<String> {
fs::read_to_string(&path) fs::read_to_string(&path).await.map_err(LuaError::external)
.await
.map_err(mlua::Error::external)
} }
async fn fs_read_dir(_: &Lua, path: String) -> Result<Vec<String>> { async fn fs_read_dir(_: &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(mlua::Error::external)?; let mut dir = fs::read_dir(&path).await.map_err(LuaError::external)?;
while let Some(dir_entry) = dir.try_next().await.map_err(mlua::Error::external)? { while let Some(dir_entry) = dir.try_next().await.map_err(LuaError::external)? {
if let Some(dir_path_str) = dir_entry.path().to_str() { if let Some(dir_path_str) = dir_entry.path().to_str() {
dir_strings.push(dir_path_str.to_owned()); dir_strings.push(dir_path_str.to_owned());
} else { } else {
return Err(mlua::Error::RuntimeError(format!( return Err(LuaError::RuntimeError(format!(
"File path could not be converted into a string: '{}'", "File path could not be converted into a string: '{}'",
dir_entry.path().display() dir_entry.path().display()
))); )));
@ -57,46 +55,42 @@ async fn fs_read_dir(_: &Lua, path: String) -> Result<Vec<String>> {
Ok(dir_strings_no_prefix) Ok(dir_strings_no_prefix)
} }
async fn fs_write_file(_: &Lua, (path, contents): (String, String)) -> Result<()> { async fn fs_write_file(_: &Lua, (path, contents): (String, String)) -> LuaResult<()> {
fs::write(&path, &contents) fs::write(&path, &contents)
.await .await
.map_err(mlua::Error::external) .map_err(LuaError::external)
} }
async fn fs_write_dir(_: &Lua, path: String) -> Result<()> { async fn fs_write_dir(_: &Lua, path: String) -> LuaResult<()> {
fs::create_dir_all(&path) fs::create_dir_all(&path).await.map_err(LuaError::external)
.await
.map_err(mlua::Error::external)
} }
async fn fs_remove_file(_: &Lua, path: String) -> Result<()> { async fn fs_remove_file(_: &Lua, path: String) -> LuaResult<()> {
fs::remove_file(&path).await.map_err(mlua::Error::external) fs::remove_file(&path).await.map_err(LuaError::external)
} }
async fn fs_remove_dir(_: &Lua, path: String) -> Result<()> { async fn fs_remove_dir(_: &Lua, path: String) -> LuaResult<()> {
fs::remove_dir_all(&path) fs::remove_dir_all(&path).await.map_err(LuaError::external)
.await
.map_err(mlua::Error::external)
} }
async fn fs_is_file(_: &Lua, path: String) -> Result<bool> { async fn fs_is_file(_: &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)
.await .await
.map_err(mlua::Error::external)? .map_err(LuaError::external)?
.is_file()) .is_file())
} else { } else {
Ok(false) Ok(false)
} }
} }
async fn fs_is_dir(_: &Lua, path: String) -> Result<bool> { async fn fs_is_dir(_: &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)
.await .await
.map_err(mlua::Error::external)? .map_err(LuaError::external)?
.is_dir()) .is_dir())
} else { } else {
Ok(false) Ok(false)

View file

@ -1,10 +1,10 @@
use std::collections::HashMap; use std::collections::HashMap;
use mlua::{Error, Lua, LuaSerdeExt, Result, Table, Value}; use mlua::prelude::*;
use crate::utils::{net::get_request_user_agent_header, table_builder::TableBuilder}; use crate::utils::{net::get_request_user_agent_header, table_builder::TableBuilder};
pub async fn create(lua: &Lua) -> Result<()> { pub async fn create(lua: &Lua) -> LuaResult<()> {
lua.globals().raw_set( lua.globals().raw_set(
"net", "net",
TableBuilder::new(lua)? TableBuilder::new(lua)?
@ -15,45 +15,45 @@ pub async fn create(lua: &Lua) -> Result<()> {
) )
} }
fn net_json_encode(_: &Lua, (val, pretty): (Value, Option<bool>)) -> Result<String> { fn net_json_encode(_: &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(Error::external) serde_json::to_string_pretty(&val).map_err(LuaError::external)
} else { } else {
serde_json::to_string(&val).map_err(Error::external) serde_json::to_string(&val).map_err(LuaError::external)
} }
} }
fn net_json_decode(lua: &Lua, json: String) -> Result<Value> { fn net_json_decode(lua: &Lua, json: String) -> LuaResult<LuaValue> {
let json: serde_json::Value = serde_json::from_str(&json).map_err(Error::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: Value<'lua>) -> Result<Table<'lua>> { async fn net_request<'lua>(lua: &'lua Lua, config: LuaValue<'lua>) -> LuaResult<LuaTable<'lua>> {
// 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 {
Value::String(s) => { LuaValue::String(s) => {
let url = s.to_string_lossy().to_string(); let url = s.to_string_lossy().to_string();
let method = "GET".to_string(); let method = "GET".to_string();
Ok((url, method, HashMap::new(), None)) Ok((url, method, HashMap::new(), None))
} }
Value::Table(tab) => { LuaValue::Table(tab) => {
// Extract url // Extract url
let url = match tab.raw_get::<&str, mlua::String>("url") { let url = match tab.raw_get::<_, LuaString>("url") {
Ok(config_url) => Ok(config_url.to_string_lossy().to_string()), Ok(config_url) => Ok(config_url.to_string_lossy().to_string()),
Err(_) => Err(Error::RuntimeError( Err(_) => Err(LuaError::RuntimeError(
"Missing 'url' in request config".to_string(), "Missing 'url' in request config".to_string(),
)), )),
}?; }?;
// Extract method // Extract method
let method = match tab.raw_get::<&str, mlua::String>("method") { let method = match tab.raw_get::<_, LuaString>("method") {
Ok(config_method) => config_method.to_string_lossy().trim().to_ascii_uppercase(), Ok(config_method) => config_method.to_string_lossy().trim().to_ascii_uppercase(),
Err(_) => "GET".to_string(), Err(_) => "GET".to_string(),
}; };
// Extract headers // Extract headers
let headers = match tab.raw_get::<&str, mlua::Table>("headers") { let headers = match tab.raw_get::<_, LuaTable>("headers") {
Ok(config_headers) => { Ok(config_headers) => {
let mut lua_headers = HashMap::new(); let mut lua_headers = HashMap::new();
for pair in config_headers.pairs::<mlua::String, mlua::String>() { for pair in config_headers.pairs::<LuaString, LuaString>() {
let (key, value) = pair?.to_owned(); let (key, value) = pair?.to_owned();
lua_headers.insert(key, value); lua_headers.insert(key, value);
} }
@ -62,13 +62,13 @@ async fn net_request<'lua>(lua: &'lua Lua, config: Value<'lua>) -> Result<Table<
Err(_) => HashMap::new(), Err(_) => HashMap::new(),
}; };
// Extract body // Extract body
let body = match tab.raw_get::<&str, mlua::String>("body") { let body = match tab.raw_get::<_, LuaString>("body") {
Ok(config_body) => Some(config_body.as_bytes().to_owned()), Ok(config_body) => Some(config_body.as_bytes().to_owned()),
Err(_) => None, Err(_) => None,
}; };
Ok((url, method, headers, body)) Ok((url, method, headers, body))
} }
value => Err(Error::RuntimeError(format!( value => Err(LuaError::RuntimeError(format!(
"Invalid request config - expected string or table, got {}", "Invalid request config - expected string or table, got {}",
value.type_name() value.type_name()
))), ))),
@ -77,7 +77,7 @@ async fn net_request<'lua>(lua: &'lua Lua, config: Value<'lua>) -> Result<Table<
let method = method.trim().to_ascii_uppercase(); let method = method.trim().to_ascii_uppercase();
let method = match method.as_ref() { let method = match method.as_ref() {
"GET" | "POST" | "PUT" | "DELETE" | "HEAD" | "OPTIONS" | "PATCH" => Ok(&method), "GET" | "POST" | "PUT" | "DELETE" | "HEAD" | "OPTIONS" | "PATCH" => Ok(&method),
_ => Err(Error::RuntimeError(format!( _ => Err(LuaError::RuntimeError(format!(
"Invalid request config method '{}'", "Invalid request config method '{}'",
&method &method
))), ))),
@ -112,6 +112,6 @@ async fn net_request<'lua>(lua: &'lua Lua, config: Value<'lua>) -> Result<Table<
.with_value("body", lua.create_string(&res_bytes)?)? .with_value("body", lua.create_string(&res_bytes)?)?
.build_readonly() .build_readonly()
} }
Err(e) => Err(Error::external(e)), Err(e) => Err(LuaError::external(e)),
} }
} }

View file

@ -3,13 +3,13 @@ use std::{
process::{exit, Stdio}, process::{exit, Stdio},
}; };
use mlua::{Error, Function, Lua, MetaMethod, Result, Table, Value}; use mlua::prelude::*;
use os_str_bytes::RawOsString; use os_str_bytes::RawOsString;
use smol::process::Command; use smol::process::Command;
use crate::utils::table_builder::TableBuilder; use crate::utils::table_builder::TableBuilder;
pub async fn create(lua: &Lua, args_vec: Vec<String>) -> Result<()> { pub async fn create(lua: &Lua, args_vec: Vec<String>) -> LuaResult<()> {
// Create readonly args array // Create readonly args array
let args_tab = TableBuilder::new(lua)? let args_tab = TableBuilder::new(lua)?
.with_sequential_values(args_vec)? .with_sequential_values(args_vec)?
@ -18,9 +18,9 @@ pub async fn create(lua: &Lua, args_vec: Vec<String>) -> Result<()> {
let env_tab = TableBuilder::new(lua)? let env_tab = TableBuilder::new(lua)?
.with_metatable( .with_metatable(
TableBuilder::new(lua)? TableBuilder::new(lua)?
.with_function(MetaMethod::Index.name(), process_env_get)? .with_function(LuaMetaMethod::Index.name(), process_env_get)?
.with_function(MetaMethod::NewIndex.name(), process_env_set)? .with_function(LuaMetaMethod::NewIndex.name(), process_env_set)?
.with_function(MetaMethod::Iter.name(), process_env_iter)? .with_function(LuaMetaMethod::Iter.name(), process_env_iter)?
.build_readonly()?, .build_readonly()?,
)? )?
.build_readonly()?; .build_readonly()?;
@ -36,26 +36,31 @@ pub async fn create(lua: &Lua, args_vec: Vec<String>) -> Result<()> {
) )
} }
fn process_env_get<'lua>(lua: &'lua Lua, (_, key): (Value<'lua>, String)) -> Result<Value<'lua>> { fn process_env_get<'lua>(
lua: &'lua Lua,
(_, key): (LuaValue<'lua>, String),
) -> LuaResult<LuaValue<'lua>> {
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);
Ok(Value::String(lua.create_string(raw_value.as_raw_bytes())?)) Ok(LuaValue::String(
lua.create_string(raw_value.as_raw_bytes())?,
))
} }
None => Ok(Value::Nil), None => Ok(LuaValue::Nil),
} }
} }
fn process_env_set(_: &Lua, (_, key, value): (Value, String, Option<String>)) -> Result<()> { fn process_env_set(_: &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(Error::RuntimeError("Key must not be empty".to_string())) Err(LuaError::RuntimeError("Key must not be empty".to_string()))
} else if key.contains('=') { } else if key.contains('=') {
Err(Error::RuntimeError( Err(LuaError::RuntimeError(
"Key must not contain the equals character '='".to_string(), "Key must not contain the equals character '='".to_string(),
)) ))
} else if key.contains('\0') { } else if key.contains('\0') {
Err(Error::RuntimeError( Err(LuaError::RuntimeError(
"Key must not contain the NUL character".to_string(), "Key must not contain the NUL character".to_string(),
)) ))
} else { } else {
@ -63,7 +68,7 @@ fn process_env_set(_: &Lua, (_, key, value): (Value, String, Option<String>)) ->
Some(value) => { Some(value) => {
// Make sure value is valid, otherwise set_var will panic // Make sure value is valid, otherwise set_var will panic
if value.contains('\0') { if value.contains('\0') {
Err(Error::RuntimeError( Err(LuaError::RuntimeError(
"Value must not contain the NUL character".to_string(), "Value must not contain the NUL character".to_string(),
)) ))
} else { } else {
@ -79,22 +84,25 @@ fn process_env_set(_: &Lua, (_, key, value): (Value, String, Option<String>)) ->
} }
} }
fn process_env_iter<'lua>(lua: &'lua Lua, (_, _): (Value<'lua>, ())) -> Result<Function<'lua>> { fn process_env_iter<'lua>(
lua: &'lua Lua,
(_, _): (LuaValue<'lua>, ()),
) -> LuaResult<LuaFunction<'lua>> {
let mut vars = env::vars_os(); let mut vars = env::vars_os();
lua.create_function_mut(move |lua, _: ()| match vars.next() { lua.create_function_mut(move |lua, _: ()| match vars.next() {
Some((key, value)) => { Some((key, value)) => {
let raw_key = RawOsString::new(key); let raw_key = RawOsString::new(key);
let raw_value = RawOsString::new(value); let raw_value = RawOsString::new(value);
Ok(( Ok((
Value::String(lua.create_string(raw_key.as_raw_bytes())?), LuaValue::String(lua.create_string(raw_key.as_raw_bytes())?),
Value::String(lua.create_string(raw_value.as_raw_bytes())?), LuaValue::String(lua.create_string(raw_value.as_raw_bytes())?),
)) ))
} }
None => Ok((Value::Nil, Value::Nil)), None => Ok((LuaValue::Nil, LuaValue::Nil)),
}) })
} }
fn process_exit(_: &Lua, exit_code: Option<i32>) -> Result<()> { fn process_exit(_: &Lua, exit_code: Option<i32>) -> LuaResult<()> {
// TODO: Exit gracefully to the root with an Ok // TODO: Exit gracefully to the root with an Ok
// result instead of completely exiting the process // result instead of completely exiting the process
if let Some(code) = exit_code { if let Some(code) = exit_code {
@ -104,7 +112,10 @@ fn process_exit(_: &Lua, exit_code: Option<i32>) -> Result<()> {
} }
} }
async fn process_spawn(lua: &Lua, (program, args): (String, Option<Vec<String>>)) -> Result<Table> { async fn process_spawn(
lua: &Lua,
(program, args): (String, Option<Vec<String>>),
) -> LuaResult<LuaTable> {
// Create and spawn a child process, and // Create and spawn a child process, and
// wait for it to terminate with output // wait for it to terminate with output
let mut cmd = Command::new(program); let mut cmd = Command::new(program);
@ -112,13 +123,13 @@ async fn process_spawn(lua: &Lua, (program, args): (String, Option<Vec<String>>)
cmd.args(args); cmd.args(args);
} }
let child = cmd let child = cmd
.current_dir(env::current_dir().map_err(mlua::Error::external)?) .current_dir(env::current_dir().map_err(LuaError::external)?)
.stdin(Stdio::null()) .stdin(Stdio::null())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.stderr(Stdio::piped()) .stderr(Stdio::piped())
.spawn() .spawn()
.map_err(mlua::Error::external)?; .map_err(LuaError::external)?;
let output = child.output().await.map_err(mlua::Error::external)?; let output = child.output().await.map_err(LuaError::external)?;
// NOTE: If an exit code was not given by the child process, // NOTE: If an exit code was not given by the child process,
// we default to 1 if it yielded any error output, otherwise 0 // we default to 1 if it yielded any error output, otherwise 0
let code = output let code = output

View file

@ -1,13 +1,11 @@
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use mlua::{Error, Function, Lua, Result, Table, Thread, Value, Variadic}; use mlua::prelude::*;
use smol::Timer; use smol::Timer;
use crate::utils::table_builder::TableBuilder; use crate::utils::table_builder::TableBuilder;
type Vararg<'lua> = Variadic<Value<'lua>>; pub async fn create(lua: &Lua) -> LuaResult<()> {
pub async fn create(lua: &Lua) -> Result<()> {
lua.globals().raw_set( lua.globals().raw_set(
"task", "task",
TableBuilder::new(lua)? TableBuilder::new(lua)?
@ -20,20 +18,20 @@ pub async fn create(lua: &Lua) -> Result<()> {
) )
} }
fn get_or_create_thread_from_arg<'a>(lua: &'a Lua, arg: Value<'a>) -> Result<Thread<'a>> { fn get_or_create_thread_from_arg<'a>(lua: &'a Lua, arg: LuaValue<'a>) -> LuaResult<LuaThread<'a>> {
match arg { match arg {
Value::Thread(thread) => Ok(thread), LuaValue::Thread(thread) => Ok(thread),
Value::Function(func) => Ok(lua.create_thread(func)?), LuaValue::Function(func) => Ok(lua.create_thread(func)?),
val => Err(Error::RuntimeError(format!( val => Err(LuaError::RuntimeError(format!(
"Expected type thread or function, got {}", "Expected type thread or function, got {}",
val.type_name() val.type_name()
))), ))),
} }
} }
async fn resume_thread(lua: &Lua, thread: Thread<'_>, args: Vararg<'_>) -> Result<()> { async fn resume_thread(lua: &Lua, thread: LuaThread<'_>, args: LuaMultiValue<'_>) -> LuaResult<()> {
let coroutine: Table = lua.globals().raw_get("coroutine")?; let coroutine: LuaTable = lua.globals().raw_get("coroutine")?;
let resume: Function = coroutine.raw_get("resume")?; let resume: LuaFunction = coroutine.raw_get("resume")?;
// FIXME: This is blocking, we should spawn a local tokio task, // FIXME: This is blocking, we should spawn a local tokio task,
// but doing that moves "thread" and "args", that both have // but doing that moves "thread" and "args", that both have
// the lifetime of the outer function, so it doesn't work // the lifetime of the outer function, so it doesn't work
@ -41,14 +39,17 @@ async fn resume_thread(lua: &Lua, thread: Thread<'_>, args: Vararg<'_>) -> Resul
Ok(()) Ok(())
} }
async fn task_cancel(lua: &Lua, thread: Thread<'_>) -> Result<()> { async fn task_cancel(lua: &Lua, thread: LuaThread<'_>) -> LuaResult<()> {
let coroutine: Table = lua.globals().raw_get("coroutine")?; let coroutine: LuaTable = lua.globals().raw_get("coroutine")?;
let close: Function = coroutine.raw_get("close")?; let close: LuaFunction = coroutine.raw_get("close")?;
close.call_async(thread).await?; close.call_async(thread).await?;
Ok(()) Ok(())
} }
async fn task_defer<'a>(lua: &'a Lua, (tof, args): (Value<'a>, Vararg<'a>)) -> Result<Thread<'a>> { async fn task_defer<'a>(
lua: &'a Lua,
(tof, args): (LuaValue<'a>, LuaMultiValue<'a>),
) -> LuaResult<LuaThread<'a>> {
// TODO: Defer (sleep a minimum amount of time) // TODO: Defer (sleep a minimum amount of time)
let thread = get_or_create_thread_from_arg(lua, tof)?; let thread = get_or_create_thread_from_arg(lua, tof)?;
resume_thread(lua, thread.clone(), args).await?; resume_thread(lua, thread.clone(), args).await?;
@ -57,15 +58,18 @@ async fn task_defer<'a>(lua: &'a Lua, (tof, args): (Value<'a>, Vararg<'a>)) -> R
async fn task_delay<'a>( async fn task_delay<'a>(
lua: &'a Lua, lua: &'a Lua,
(_delay, tof, args): (Option<f32>, Value<'a>, Vararg<'a>), (_delay, tof, args): (Option<f32>, LuaValue<'a>, LuaMultiValue<'a>),
) -> Result<Thread<'a>> { ) -> LuaResult<LuaThread<'a>> {
// TODO: Delay by the amount of time wanted // TODO: Delay by the amount of time wanted
let thread = get_or_create_thread_from_arg(lua, tof)?; let thread = get_or_create_thread_from_arg(lua, tof)?;
resume_thread(lua, thread.clone(), args).await?; resume_thread(lua, thread.clone(), args).await?;
Ok(thread) Ok(thread)
} }
async fn task_spawn<'a>(lua: &'a Lua, (tof, args): (Value<'a>, Vararg<'a>)) -> Result<Thread<'a>> { async fn task_spawn<'a>(
lua: &'a Lua,
(tof, args): (LuaValue<'a>, LuaMultiValue<'a>),
) -> LuaResult<LuaThread<'a>> {
let thread = get_or_create_thread_from_arg(lua, tof)?; let thread = get_or_create_thread_from_arg(lua, tof)?;
resume_thread(lua, thread.clone(), args).await?; resume_thread(lua, thread.clone(), args).await?;
Ok(thread) Ok(thread)
@ -74,7 +78,7 @@ async fn task_spawn<'a>(lua: &'a Lua, (tof, args): (Value<'a>, Vararg<'a>)) -> R
// FIXME: It doesn't seem possible to properly make an async wait // FIXME: It doesn't seem possible to properly make an async wait
// function with mlua right now, something breaks when using // function with mlua right now, something breaks when using
// the async wait function inside of a coroutine // the async wait function inside of a coroutine
async fn task_wait(_: &Lua, duration: Option<f32>) -> Result<f32> { async fn task_wait(_: &Lua, duration: Option<f32>) -> LuaResult<f32> {
let start = Instant::now(); let start = Instant::now();
Timer::after( Timer::after(
duration duration

View file

@ -3,7 +3,7 @@ use std::{
io::{self, Write as _}, io::{self, Write as _},
}; };
use mlua::{MultiValue, Value}; use mlua::prelude::*;
const MAX_FORMAT_DEPTH: usize = 4; const MAX_FORMAT_DEPTH: usize = 4;
@ -25,11 +25,11 @@ pub const STYLE_RESET: &str = if cfg!(test) { "" } else { "\x1B[22m" };
pub const STYLE_BOLD: &str = if cfg!(test) { "" } else { "\x1B[1m" }; pub const STYLE_BOLD: &str = if cfg!(test) { "" } else { "\x1B[1m" };
pub const STYLE_DIM: &str = if cfg!(test) { "" } else { "\x1B[2m" }; pub const STYLE_DIM: &str = if cfg!(test) { "" } else { "\x1B[2m" };
pub fn flush_stdout() -> mlua::Result<()> { pub fn flush_stdout() -> LuaResult<()> {
io::stdout().flush().map_err(mlua::Error::external) io::stdout().flush().map_err(LuaError::external)
} }
fn can_be_plain_lua_table_key(s: &mlua::String) -> bool { fn can_be_plain_lua_table_key(s: &LuaString) -> bool {
let str = s.to_string_lossy().to_string(); let str = s.to_string_lossy().to_string();
let first_char = str.chars().next().unwrap(); let first_char = str.chars().next().unwrap();
if first_char.is_alphabetic() { if first_char.is_alphabetic() {
@ -56,13 +56,13 @@ pub fn format_label<S: AsRef<str>>(s: S) -> String {
) )
} }
pub fn print_label<S: AsRef<str>>(s: S) -> mlua::Result<()> { pub fn print_label<S: AsRef<str>>(s: S) -> LuaResult<()> {
print!("{}", format_label(s)); print!("{}", format_label(s));
flush_stdout()?; flush_stdout()?;
Ok(()) Ok(())
} }
pub fn print_style<S: AsRef<str>>(s: S) -> mlua::Result<()> { pub fn print_style<S: AsRef<str>>(s: S) -> LuaResult<()> {
print!( print!(
"{}", "{}",
match s.as_ref() { match s.as_ref() {
@ -70,7 +70,7 @@ pub fn print_style<S: AsRef<str>>(s: S) -> mlua::Result<()> {
"bold" => STYLE_BOLD, "bold" => STYLE_BOLD,
"dim" => STYLE_DIM, "dim" => STYLE_DIM,
_ => { _ => {
return Err(mlua::Error::RuntimeError(format!( return Err(LuaError::RuntimeError(format!(
"The style '{}' is not a valid style name", "The style '{}' is not a valid style name",
s.as_ref() s.as_ref()
))); )));
@ -81,7 +81,7 @@ pub fn print_style<S: AsRef<str>>(s: S) -> mlua::Result<()> {
Ok(()) Ok(())
} }
pub fn print_color<S: AsRef<str>>(s: S) -> mlua::Result<()> { pub fn print_color<S: AsRef<str>>(s: S) -> LuaResult<()> {
print!( print!(
"{}", "{}",
match s.as_ref() { match s.as_ref() {
@ -95,7 +95,7 @@ pub fn print_color<S: AsRef<str>>(s: S) -> mlua::Result<()> {
"cyan" => COLOR_CYAN, "cyan" => COLOR_CYAN,
"white" => COLOR_WHITE, "white" => COLOR_WHITE,
_ => { _ => {
return Err(mlua::Error::RuntimeError(format!( return Err(LuaError::RuntimeError(format!(
"The color '{}' is not a valid color name", "The color '{}' is not a valid color name",
s.as_ref() s.as_ref()
))); )));
@ -106,16 +106,20 @@ pub fn print_color<S: AsRef<str>>(s: S) -> mlua::Result<()> {
Ok(()) Ok(())
} }
pub fn pretty_format_value(buffer: &mut String, value: &Value, depth: usize) -> anyhow::Result<()> { pub fn pretty_format_value(
buffer: &mut String,
value: &LuaValue,
depth: usize,
) -> anyhow::Result<()> {
// TODO: Handle tables with cyclic references // TODO: Handle tables with cyclic references
// TODO: Handle other types like function, userdata, ... // TODO: Handle other types like function, userdata, ...
match &value { match &value {
Value::Nil => write!(buffer, "nil")?, LuaValue::Nil => write!(buffer, "nil")?,
Value::Boolean(true) => write!(buffer, "{COLOR_YELLOW}true{COLOR_RESET}")?, LuaValue::Boolean(true) => write!(buffer, "{COLOR_YELLOW}true{COLOR_RESET}")?,
Value::Boolean(false) => write!(buffer, "{COLOR_YELLOW}false{COLOR_RESET}")?, LuaValue::Boolean(false) => write!(buffer, "{COLOR_YELLOW}false{COLOR_RESET}")?,
Value::Number(n) => write!(buffer, "{COLOR_CYAN}{n}{COLOR_RESET}")?, LuaValue::Number(n) => write!(buffer, "{COLOR_CYAN}{n}{COLOR_RESET}")?,
Value::Integer(i) => write!(buffer, "{COLOR_CYAN}{i}{COLOR_RESET}")?, LuaValue::Integer(i) => write!(buffer, "{COLOR_CYAN}{i}{COLOR_RESET}")?,
Value::String(s) => write!( LuaValue::String(s) => write!(
buffer, buffer,
"{}\"{}\"{}", "{}\"{}\"{}",
COLOR_GREEN, COLOR_GREEN,
@ -124,17 +128,17 @@ pub fn pretty_format_value(buffer: &mut String, value: &Value, depth: usize) ->
.replace('\n', r#"\n"#), .replace('\n', r#"\n"#),
COLOR_RESET COLOR_RESET
)?, )?,
Value::Table(ref tab) => { LuaValue::Table(ref tab) => {
if depth >= MAX_FORMAT_DEPTH { if depth >= MAX_FORMAT_DEPTH {
write!(buffer, "{STYLE_DIM}{{ ... }}{STYLE_RESET}")?; write!(buffer, "{STYLE_DIM}{{ ... }}{STYLE_RESET}")?;
} else { } else {
let mut is_empty = false; let mut is_empty = false;
let depth_indent = INDENT.repeat(depth); let depth_indent = INDENT.repeat(depth);
write!(buffer, "{STYLE_DIM}{{{STYLE_RESET}")?; write!(buffer, "{STYLE_DIM}{{{STYLE_RESET}")?;
for pair in tab.clone().pairs::<Value, Value>() { for pair in tab.clone().pairs::<LuaValue, LuaValue>() {
let (key, value) = pair?; let (key, value) = pair?;
match &key { match &key {
Value::String(s) if can_be_plain_lua_table_key(s) => write!( LuaValue::String(s) if can_be_plain_lua_table_key(s) => write!(
buffer, buffer,
"\n{}{}{} {}={} ", "\n{}{}{} {}={} ",
depth_indent, depth_indent,
@ -160,12 +164,12 @@ pub fn pretty_format_value(buffer: &mut String, value: &Value, depth: usize) ->
} }
} }
} }
Value::Vector(x, y, z) => { LuaValue::Vector(x, y, z) => {
write!(buffer, "{COLOR_PURPLE}<vector({x}, {y}, {z})>{COLOR_RESET}",)? write!(buffer, "{COLOR_PURPLE}<vector({x}, {y}, {z})>{COLOR_RESET}",)?
} }
Value::Thread(_) => write!(buffer, "{COLOR_PURPLE}<thread>{COLOR_RESET}")?, LuaValue::Thread(_) => write!(buffer, "{COLOR_PURPLE}<thread>{COLOR_RESET}")?,
Value::Function(_) => write!(buffer, "{COLOR_PURPLE}<function>{COLOR_RESET}")?, LuaValue::Function(_) => write!(buffer, "{COLOR_PURPLE}<function>{COLOR_RESET}")?,
Value::UserData(_) | Value::LightUserData(_) => { LuaValue::UserData(_) | LuaValue::LightUserData(_) => {
write!(buffer, "{COLOR_PURPLE}<userdata>{COLOR_RESET}")? write!(buffer, "{COLOR_PURPLE}<userdata>{COLOR_RESET}")?
} }
_ => write!(buffer, "?")?, _ => write!(buffer, "?")?,
@ -173,28 +177,28 @@ pub fn pretty_format_value(buffer: &mut String, value: &Value, depth: usize) ->
Ok(()) Ok(())
} }
pub fn pretty_format_multi_value(multi: &MultiValue) -> mlua::Result<String> { pub fn pretty_format_multi_value(multi: &LuaMultiValue) -> LuaResult<String> {
let mut buffer = String::new(); let mut buffer = String::new();
let mut counter = 0; let mut counter = 0;
for value in multi { for value in multi {
counter += 1; counter += 1;
if let Value::String(s) = value { if let LuaValue::String(s) = value {
write!(buffer, "{}", s.to_string_lossy()).map_err(mlua::Error::external)?; write!(buffer, "{}", s.to_string_lossy()).map_err(LuaError::external)?;
} else { } else {
pretty_format_value(&mut buffer, value, 0).map_err(mlua::Error::external)?; pretty_format_value(&mut buffer, value, 0).map_err(LuaError::external)?;
} }
if counter < multi.len() { if counter < multi.len() {
write!(&mut buffer, " ").map_err(mlua::Error::external)?; write!(&mut buffer, " ").map_err(LuaError::external)?;
} }
} }
Ok(buffer) Ok(buffer)
} }
pub fn pretty_format_luau_error(e: &mlua::Error) -> String { pub fn pretty_format_luau_error(e: &LuaError) -> String {
let stack_begin = format!("[{}Stack Begin{}]", COLOR_BLUE, COLOR_RESET); let stack_begin = format!("[{}Stack Begin{}]", COLOR_BLUE, COLOR_RESET);
let stack_end = format!("[{}Stack End{}]", COLOR_BLUE, COLOR_RESET); let stack_end = format!("[{}Stack End{}]", COLOR_BLUE, COLOR_RESET);
let err_string = match e { let err_string = match e {
mlua::Error::RuntimeError(e) => { LuaError::RuntimeError(e) => {
// Add "Stack Begin" instead of default stack traceback string // Add "Stack Begin" instead of default stack traceback string
let err_string = e.to_string(); let err_string = e.to_string();
let mut err_lines = err_string let mut err_lines = err_string
@ -211,7 +215,7 @@ pub fn pretty_format_luau_error(e: &mlua::Error) -> String {
err_lines.push(stack_end); err_lines.push(stack_end);
err_lines.join("\n") err_lines.join("\n")
} }
mlua::Error::CallbackError { cause, traceback } => { LuaError::CallbackError { cause, traceback } => {
// Same error formatting as above // Same error formatting as above
format!( format!(
"{}\n{}{}{}", "{}\n{}{}{}",
@ -221,7 +225,7 @@ pub fn pretty_format_luau_error(e: &mlua::Error) -> String {
stack_end stack_end
) )
} }
mlua::Error::ToLuaConversionError { from, to, message } => { LuaError::ToLuaConversionError { from, to, message } => {
let msg = message let msg = message
.clone() .clone()
.map_or_else(String::new, |m| format!("\nDetails:\n\t{m}")); .map_or_else(String::new, |m| format!("\nDetails:\n\t{m}"));
@ -230,7 +234,7 @@ pub fn pretty_format_luau_error(e: &mlua::Error) -> String {
from, to, msg from, to, msg
) )
} }
mlua::Error::FromLuaConversionError { from, to, message } => { LuaError::FromLuaConversionError { from, to, message } => {
let msg = message let msg = message
.clone() .clone()
.map_or_else(String::new, |m| format!("\nDetails:\n\t{m}")); .map_or_else(String::new, |m| format!("\nDetails:\n\t{m}"));

View file

@ -1,19 +1,19 @@
use std::future::Future; use std::future::Future;
use mlua::{FromLuaMulti, Lua, Result, Table, ToLua, ToLuaMulti, Value}; use mlua::prelude::*;
pub struct TableBuilder<'lua> { pub struct TableBuilder<'lua> {
lua: &'lua Lua, lua: &'lua Lua,
tab: Table<'lua>, tab: LuaTable<'lua>,
} }
impl<'lua> TableBuilder<'lua> { impl<'lua> TableBuilder<'lua> {
pub fn new(lua: &'lua Lua) -> Result<Self> { pub fn new(lua: &'lua Lua) -> LuaResult<Self> {
let tab = lua.create_table()?; let tab = lua.create_table()?;
Ok(Self { lua, tab }) Ok(Self { lua, tab })
} }
pub fn with_value<K, V>(self, key: K, value: V) -> Result<Self> pub fn with_value<K, V>(self, key: K, value: V) -> LuaResult<Self>
where where
K: ToLua<'lua>, K: ToLua<'lua>,
V: ToLua<'lua>, V: ToLua<'lua>,
@ -22,7 +22,7 @@ impl<'lua> TableBuilder<'lua> {
Ok(self) Ok(self)
} }
pub fn with_values<K, V>(self, values: Vec<(K, V)>) -> Result<Self> pub fn with_values<K, V>(self, values: Vec<(K, V)>) -> LuaResult<Self>
where where
K: ToLua<'lua>, K: ToLua<'lua>,
V: ToLua<'lua>, V: ToLua<'lua>,
@ -33,7 +33,7 @@ impl<'lua> TableBuilder<'lua> {
Ok(self) Ok(self)
} }
pub fn with_sequential_value<V>(self, value: V) -> Result<Self> pub fn with_sequential_value<V>(self, value: V) -> LuaResult<Self>
where where
V: ToLua<'lua>, V: ToLua<'lua>,
{ {
@ -41,7 +41,7 @@ impl<'lua> TableBuilder<'lua> {
Ok(self) Ok(self)
} }
pub fn with_sequential_values<V>(self, values: Vec<V>) -> Result<Self> pub fn with_sequential_values<V>(self, values: Vec<V>) -> LuaResult<Self>
where where
V: ToLua<'lua>, V: ToLua<'lua>,
{ {
@ -51,40 +51,40 @@ impl<'lua> TableBuilder<'lua> {
Ok(self) Ok(self)
} }
pub fn with_metatable(self, table: Table) -> Result<Self> { pub fn with_metatable(self, table: LuaTable) -> LuaResult<Self> {
self.tab.set_metatable(Some(table)); self.tab.set_metatable(Some(table));
Ok(self) Ok(self)
} }
pub fn with_function<K, A, R, F>(self, key: K, func: F) -> Result<Self> pub fn with_function<K, A, R, F>(self, key: K, func: F) -> LuaResult<Self>
where where
K: ToLua<'lua>, K: ToLua<'lua>,
A: FromLuaMulti<'lua>, A: FromLuaMulti<'lua>,
R: ToLuaMulti<'lua>, R: ToLuaMulti<'lua>,
F: 'static + Fn(&'lua Lua, A) -> Result<R>, F: 'static + Fn(&'lua Lua, A) -> LuaResult<R>,
{ {
let f = self.lua.create_function(func)?; let f = self.lua.create_function(func)?;
self.with_value(key, Value::Function(f)) self.with_value(key, LuaValue::Function(f))
} }
pub fn with_async_function<K, A, R, F, FR>(self, key: K, func: F) -> Result<Self> pub fn with_async_function<K, A, R, F, FR>(self, key: K, func: F) -> LuaResult<Self>
where where
K: ToLua<'lua>, K: ToLua<'lua>,
A: FromLuaMulti<'lua>, A: FromLuaMulti<'lua>,
R: ToLuaMulti<'lua>, R: ToLuaMulti<'lua>,
F: 'static + Fn(&'lua Lua, A) -> FR, F: 'static + Fn(&'lua Lua, A) -> FR,
FR: 'lua + Future<Output = Result<R>>, FR: 'lua + Future<Output = LuaResult<R>>,
{ {
let f = self.lua.create_async_function(func)?; let f = self.lua.create_async_function(func)?;
self.with_value(key, Value::Function(f)) self.with_value(key, LuaValue::Function(f))
} }
pub fn build_readonly(self) -> Result<Table<'lua>> { pub fn build_readonly(self) -> LuaResult<LuaTable<'lua>> {
self.tab.set_readonly(true); self.tab.set_readonly(true);
Ok(self.tab) Ok(self.tab)
} }
pub fn build(self) -> Result<Table<'lua>> { pub fn build(self) -> LuaResult<LuaTable<'lua>> {
Ok(self.tab) Ok(self.tab)
} }
} }