use super::PastaLuaRuntime;
use super::enc;
use super::log;
use super::persistence;
use crate::loader::{LoaderContext, PastaConfig};
use mlua::{IntoLua, Lua, Result as LuaResult, Table, Value};
use std::path::{Path, PathBuf};
use std::sync::Arc;
fn set_loaded_module(lua: &Lua, name: &str, module: impl IntoLua) -> LuaResult<()> {
let package: Table = lua.globals().get("package")?;
let loaded: Table = package.get("loaded")?;
loaded.set(name, module)?;
tracing::debug!("Registered {name} module");
Ok(())
}
impl PastaLuaRuntime {
pub(crate) fn setup_package_path(lua: &Lua, loader_context: &LoaderContext) -> LuaResult<()> {
let path_bytes = loader_context
.generate_package_path_bytes()
.map_err(|e| mlua::Error::ExternalError(Arc::new(e)))?;
let lua_path_string = lua.create_string(&path_bytes)?;
let package: Table = lua.globals().get("package")?;
package.set("path", lua_path_string)?;
let path_display = String::from_utf8_lossy(&path_bytes);
tracing::debug!(path = %path_display, "Set package.path");
Ok(())
}
pub(crate) fn register_config_module(lua: &Lua, custom_fields: &toml::Table) -> LuaResult<()> {
let config_table = Self::toml_to_lua(lua, &toml::Value::Table(custom_fields.clone()))?;
Self::inject_actor_names(lua, &config_table)?;
set_loaded_module(lua, "@pasta_config", config_table)
}
fn inject_actor_names(_lua: &Lua, config_table: &Value) -> LuaResult<()> {
let config = match config_table {
Value::Table(t) => t,
_ => return Ok(()),
};
let actor_section: Value = config.get("actor")?;
let actor_table = match actor_section {
Value::Table(t) => t,
_ => return Ok(()),
};
for pair in actor_table.pairs::<mlua::String, Value>() {
let (key, value) = pair?;
if let Value::Table(sub_table) = value {
sub_table.set("name", key.clone())?;
}
}
Ok(())
}
pub(crate) fn register_enc_module(lua: &Lua) -> LuaResult<()> {
let enc_table = enc::register(lua)?;
set_loaded_module(lua, "@enc", enc_table)
}
pub(crate) fn register_persistence_module(
lua: &Lua,
config: &Option<PastaConfig>,
base_dir: &Option<PathBuf>,
) -> LuaResult<()> {
let persistence_config = config
.as_ref()
.and_then(|c| c.persistence())
.unwrap_or_default();
let base = base_dir.as_deref().unwrap_or(Path::new("."));
let persistence_table = persistence::register(lua, &persistence_config, base)?;
set_loaded_module(lua, "@pasta_persistence", persistence_table)
}
pub(crate) fn register_sakura_script_module(
lua: &Lua,
config: &Option<PastaConfig>,
) -> LuaResult<()> {
let talk_config = config.as_ref().and_then(|c| c.talk());
let sakura_module = crate::sakura_script::register(lua, talk_config.as_ref())?;
set_loaded_module(lua, "@pasta_sakura_script", sakura_module)
}
pub(crate) fn register_log_module(lua: &Lua) -> LuaResult<()> {
let log_table = log::register(lua)?;
set_loaded_module(lua, "@pasta_log", log_table)
}
fn toml_to_lua(lua: &Lua, value: &toml::Value) -> LuaResult<Value> {
match value {
toml::Value::String(s) => Ok(Value::String(lua.create_string(s)?)),
toml::Value::Integer(i) => Ok(Value::Number(*i as f64)),
toml::Value::Float(f) => Ok(Value::Number(*f)),
toml::Value::Boolean(b) => Ok(Value::Boolean(*b)),
toml::Value::Datetime(dt) => Ok(Value::String(lua.create_string(dt.to_string())?)),
toml::Value::Array(arr) => {
let table = lua.create_table()?;
for (i, v) in arr.iter().enumerate() {
table.set(i + 1, Self::toml_to_lua(lua, v)?)?;
}
Ok(Value::Table(table))
}
toml::Value::Table(t) => {
let table = lua.create_table()?;
for (k, v) in t {
table.set(k.as_str(), Self::toml_to_lua(lua, v)?)?;
}
Ok(Value::Table(table))
}
}
}
}