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

View file

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

View file

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

View file

@ -1,10 +1,10 @@
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};
pub async fn create(lua: &Lua) -> Result<()> {
pub async fn create(lua: &Lua) -> LuaResult<()> {
lua.globals().raw_set(
"net",
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 {
serde_json::to_string_pretty(&val).map_err(Error::external)
serde_json::to_string_pretty(&val).map_err(LuaError::external)
} 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> {
let json: serde_json::Value = serde_json::from_str(&json).map_err(Error::external)?;
fn net_json_decode(lua: &Lua, json: String) -> LuaResult<LuaValue> {
let json: serde_json::Value = serde_json::from_str(&json).map_err(LuaError::external)?;
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
let (url, method, headers, body) = match config {
Value::String(s) => {
LuaValue::String(s) => {
let url = s.to_string_lossy().to_string();
let method = "GET".to_string();
Ok((url, method, HashMap::new(), None))
}
Value::Table(tab) => {
LuaValue::Table(tab) => {
// 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()),
Err(_) => Err(Error::RuntimeError(
Err(_) => Err(LuaError::RuntimeError(
"Missing 'url' in request config".to_string(),
)),
}?;
// 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(),
Err(_) => "GET".to_string(),
};
// Extract headers
let headers = match tab.raw_get::<&str, mlua::Table>("headers") {
let headers = match tab.raw_get::<_, LuaTable>("headers") {
Ok(config_headers) => {
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();
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(),
};
// 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()),
Err(_) => None,
};
Ok((url, method, headers, body))
}
value => Err(Error::RuntimeError(format!(
value => Err(LuaError::RuntimeError(format!(
"Invalid request config - expected string or table, got {}",
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 = match method.as_ref() {
"GET" | "POST" | "PUT" | "DELETE" | "HEAD" | "OPTIONS" | "PATCH" => Ok(&method),
_ => Err(Error::RuntimeError(format!(
_ => Err(LuaError::RuntimeError(format!(
"Invalid request config 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)?)?
.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},
};
use mlua::{Error, Function, Lua, MetaMethod, Result, Table, Value};
use mlua::prelude::*;
use os_str_bytes::RawOsString;
use smol::process::Command;
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
let args_tab = TableBuilder::new(lua)?
.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)?
.with_metatable(
TableBuilder::new(lua)?
.with_function(MetaMethod::Index.name(), process_env_get)?
.with_function(MetaMethod::NewIndex.name(), process_env_set)?
.with_function(MetaMethod::Iter.name(), process_env_iter)?
.with_function(LuaMetaMethod::Index.name(), process_env_get)?
.with_function(LuaMetaMethod::NewIndex.name(), process_env_set)?
.with_function(LuaMetaMethod::Iter.name(), process_env_iter)?
.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) {
Some(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
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('=') {
Err(Error::RuntimeError(
Err(LuaError::RuntimeError(
"Key must not contain the equals character '='".to_string(),
))
} else if key.contains('\0') {
Err(Error::RuntimeError(
Err(LuaError::RuntimeError(
"Key must not contain the NUL character".to_string(),
))
} else {
@ -63,7 +68,7 @@ fn process_env_set(_: &Lua, (_, key, value): (Value, String, Option<String>)) ->
Some(value) => {
// Make sure value is valid, otherwise set_var will panic
if value.contains('\0') {
Err(Error::RuntimeError(
Err(LuaError::RuntimeError(
"Value must not contain the NUL character".to_string(),
))
} 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();
lua.create_function_mut(move |lua, _: ()| match vars.next() {
Some((key, value)) => {
let raw_key = RawOsString::new(key);
let raw_value = RawOsString::new(value);
Ok((
Value::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_key.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
// result instead of completely exiting the process
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
// wait for it to terminate with output
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);
}
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())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.map_err(mlua::Error::external)?;
let output = child.output().await.map_err(mlua::Error::external)?;
.map_err(LuaError::external)?;
let output = child.output().await.map_err(LuaError::external)?;
// NOTE: If an exit code was not given by the child process,
// we default to 1 if it yielded any error output, otherwise 0
let code = output

View file

@ -1,13 +1,11 @@
use std::time::{Duration, Instant};
use mlua::{Error, Function, Lua, Result, Table, Thread, Value, Variadic};
use mlua::prelude::*;
use smol::Timer;
use crate::utils::table_builder::TableBuilder;
type Vararg<'lua> = Variadic<Value<'lua>>;
pub async fn create(lua: &Lua) -> Result<()> {
pub async fn create(lua: &Lua) -> LuaResult<()> {
lua.globals().raw_set(
"task",
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 {
Value::Thread(thread) => Ok(thread),
Value::Function(func) => Ok(lua.create_thread(func)?),
val => Err(Error::RuntimeError(format!(
LuaValue::Thread(thread) => Ok(thread),
LuaValue::Function(func) => Ok(lua.create_thread(func)?),
val => Err(LuaError::RuntimeError(format!(
"Expected type thread or function, got {}",
val.type_name()
))),
}
}
async fn resume_thread(lua: &Lua, thread: Thread<'_>, args: Vararg<'_>) -> Result<()> {
let coroutine: Table = lua.globals().raw_get("coroutine")?;
let resume: Function = coroutine.raw_get("resume")?;
async fn resume_thread(lua: &Lua, thread: LuaThread<'_>, args: LuaMultiValue<'_>) -> LuaResult<()> {
let coroutine: LuaTable = lua.globals().raw_get("coroutine")?;
let resume: LuaFunction = coroutine.raw_get("resume")?;
// FIXME: This is blocking, we should spawn a local tokio task,
// but doing that moves "thread" and "args", that both have
// 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(())
}
async fn task_cancel(lua: &Lua, thread: Thread<'_>) -> Result<()> {
let coroutine: Table = lua.globals().raw_get("coroutine")?;
let close: Function = coroutine.raw_get("close")?;
async fn task_cancel(lua: &Lua, thread: LuaThread<'_>) -> LuaResult<()> {
let coroutine: LuaTable = lua.globals().raw_get("coroutine")?;
let close: LuaFunction = coroutine.raw_get("close")?;
close.call_async(thread).await?;
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)
let thread = get_or_create_thread_from_arg(lua, tof)?;
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>(
lua: &'a Lua,
(_delay, tof, args): (Option<f32>, Value<'a>, Vararg<'a>),
) -> Result<Thread<'a>> {
(_delay, tof, args): (Option<f32>, LuaValue<'a>, LuaMultiValue<'a>),
) -> LuaResult<LuaThread<'a>> {
// TODO: Delay by the amount of time wanted
let thread = get_or_create_thread_from_arg(lua, tof)?;
resume_thread(lua, thread.clone(), args).await?;
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)?;
resume_thread(lua, thread.clone(), args).await?;
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
// function with mlua right now, something breaks when using
// 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();
Timer::after(
duration

View file

@ -3,7 +3,7 @@ use std::{
io::{self, Write as _},
};
use mlua::{MultiValue, Value};
use mlua::prelude::*;
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_DIM: &str = if cfg!(test) { "" } else { "\x1B[2m" };
pub fn flush_stdout() -> mlua::Result<()> {
io::stdout().flush().map_err(mlua::Error::external)
pub fn flush_stdout() -> LuaResult<()> {
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 first_char = str.chars().next().unwrap();
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));
flush_stdout()?;
Ok(())
}
pub fn print_style<S: AsRef<str>>(s: S) -> mlua::Result<()> {
pub fn print_style<S: AsRef<str>>(s: S) -> LuaResult<()> {
print!(
"{}",
match s.as_ref() {
@ -70,7 +70,7 @@ pub fn print_style<S: AsRef<str>>(s: S) -> mlua::Result<()> {
"bold" => STYLE_BOLD,
"dim" => STYLE_DIM,
_ => {
return Err(mlua::Error::RuntimeError(format!(
return Err(LuaError::RuntimeError(format!(
"The style '{}' is not a valid style name",
s.as_ref()
)));
@ -81,7 +81,7 @@ pub fn print_style<S: AsRef<str>>(s: S) -> mlua::Result<()> {
Ok(())
}
pub fn print_color<S: AsRef<str>>(s: S) -> mlua::Result<()> {
pub fn print_color<S: AsRef<str>>(s: S) -> LuaResult<()> {
print!(
"{}",
match s.as_ref() {
@ -95,7 +95,7 @@ pub fn print_color<S: AsRef<str>>(s: S) -> mlua::Result<()> {
"cyan" => COLOR_CYAN,
"white" => COLOR_WHITE,
_ => {
return Err(mlua::Error::RuntimeError(format!(
return Err(LuaError::RuntimeError(format!(
"The color '{}' is not a valid color name",
s.as_ref()
)));
@ -106,16 +106,20 @@ pub fn print_color<S: AsRef<str>>(s: S) -> mlua::Result<()> {
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 other types like function, userdata, ...
match &value {
Value::Nil => write!(buffer, "nil")?,
Value::Boolean(true) => write!(buffer, "{COLOR_YELLOW}true{COLOR_RESET}")?,
Value::Boolean(false) => write!(buffer, "{COLOR_YELLOW}false{COLOR_RESET}")?,
Value::Number(n) => write!(buffer, "{COLOR_CYAN}{n}{COLOR_RESET}")?,
Value::Integer(i) => write!(buffer, "{COLOR_CYAN}{i}{COLOR_RESET}")?,
Value::String(s) => write!(
LuaValue::Nil => write!(buffer, "nil")?,
LuaValue::Boolean(true) => write!(buffer, "{COLOR_YELLOW}true{COLOR_RESET}")?,
LuaValue::Boolean(false) => write!(buffer, "{COLOR_YELLOW}false{COLOR_RESET}")?,
LuaValue::Number(n) => write!(buffer, "{COLOR_CYAN}{n}{COLOR_RESET}")?,
LuaValue::Integer(i) => write!(buffer, "{COLOR_CYAN}{i}{COLOR_RESET}")?,
LuaValue::String(s) => write!(
buffer,
"{}\"{}\"{}",
COLOR_GREEN,
@ -124,17 +128,17 @@ pub fn pretty_format_value(buffer: &mut String, value: &Value, depth: usize) ->
.replace('\n', r#"\n"#),
COLOR_RESET
)?,
Value::Table(ref tab) => {
LuaValue::Table(ref tab) => {
if depth >= MAX_FORMAT_DEPTH {
write!(buffer, "{STYLE_DIM}{{ ... }}{STYLE_RESET}")?;
} else {
let mut is_empty = false;
let depth_indent = INDENT.repeat(depth);
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?;
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,
"\n{}{}{} {}={} ",
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}",)?
}
Value::Thread(_) => write!(buffer, "{COLOR_PURPLE}<thread>{COLOR_RESET}")?,
Value::Function(_) => write!(buffer, "{COLOR_PURPLE}<function>{COLOR_RESET}")?,
Value::UserData(_) | Value::LightUserData(_) => {
LuaValue::Thread(_) => write!(buffer, "{COLOR_PURPLE}<thread>{COLOR_RESET}")?,
LuaValue::Function(_) => write!(buffer, "{COLOR_PURPLE}<function>{COLOR_RESET}")?,
LuaValue::UserData(_) | LuaValue::LightUserData(_) => {
write!(buffer, "{COLOR_PURPLE}<userdata>{COLOR_RESET}")?
}
_ => write!(buffer, "?")?,
@ -173,28 +177,28 @@ pub fn pretty_format_value(buffer: &mut String, value: &Value, depth: usize) ->
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 counter = 0;
for value in multi {
counter += 1;
if let Value::String(s) = value {
write!(buffer, "{}", s.to_string_lossy()).map_err(mlua::Error::external)?;
if let LuaValue::String(s) = value {
write!(buffer, "{}", s.to_string_lossy()).map_err(LuaError::external)?;
} 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() {
write!(&mut buffer, " ").map_err(mlua::Error::external)?;
write!(&mut buffer, " ").map_err(LuaError::external)?;
}
}
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_end = format!("[{}Stack End{}]", COLOR_BLUE, COLOR_RESET);
let err_string = match e {
mlua::Error::RuntimeError(e) => {
LuaError::RuntimeError(e) => {
// Add "Stack Begin" instead of default stack traceback string
let err_string = e.to_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.join("\n")
}
mlua::Error::CallbackError { cause, traceback } => {
LuaError::CallbackError { cause, traceback } => {
// Same error formatting as above
format!(
"{}\n{}{}{}",
@ -221,7 +225,7 @@ pub fn pretty_format_luau_error(e: &mlua::Error) -> String {
stack_end
)
}
mlua::Error::ToLuaConversionError { from, to, message } => {
LuaError::ToLuaConversionError { from, to, message } => {
let msg = message
.clone()
.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
)
}
mlua::Error::FromLuaConversionError { from, to, message } => {
LuaError::FromLuaConversionError { from, to, message } => {
let msg = message
.clone()
.map_or_else(String::new, |m| format!("\nDetails:\n\t{m}"));

View file

@ -1,19 +1,19 @@
use std::future::Future;
use mlua::{FromLuaMulti, Lua, Result, Table, ToLua, ToLuaMulti, Value};
use mlua::prelude::*;
pub struct TableBuilder<'lua> {
lua: &'lua Lua,
tab: Table<'lua>,
tab: LuaTable<'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()?;
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
K: ToLua<'lua>,
V: ToLua<'lua>,
@ -22,7 +22,7 @@ impl<'lua> TableBuilder<'lua> {
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
K: ToLua<'lua>,
V: ToLua<'lua>,
@ -33,7 +33,7 @@ impl<'lua> TableBuilder<'lua> {
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
V: ToLua<'lua>,
{
@ -41,7 +41,7 @@ impl<'lua> TableBuilder<'lua> {
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
V: ToLua<'lua>,
{
@ -51,40 +51,40 @@ impl<'lua> TableBuilder<'lua> {
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));
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
K: ToLua<'lua>,
A: FromLuaMulti<'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)?;
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
K: ToLua<'lua>,
A: FromLuaMulti<'lua>,
R: ToLuaMulti<'lua>,
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)?;
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);
Ok(self.tab)
}
pub fn build(self) -> Result<Table<'lua>> {
pub fn build(self) -> LuaResult<LuaTable<'lua>> {
Ok(self.tab)
}
}