use crate::runtime::Runtime;
use crate::script::{lua_value_to_serde_value, serde_value_to_lua_value};
use crate::support::tomls;
use crate::{Error, Result};
use mlua::{Lua, Table, Value};
pub fn init_module(lua: &Lua, _runtime: &Runtime) -> Result<Table> {
let table = lua.create_table()?;
let parse_fn = lua.create_function(move |lua, content: String| parse(lua, content))?;
let stringify_fn = lua.create_function(move |lua, content: Value| stringify(lua, content))?;
table.set("parse", parse_fn)?;
table.set("stringify", stringify_fn)?;
Ok(table)
}
fn parse(lua: &Lua, content: String) -> mlua::Result<Value> {
let json_value = match tomls::parse_toml_into_json(&content) {
Ok(val) => val,
Err(err) => return Err(Error::custom(format!("aip.toml.parse failed. {err}")).into()),
};
let lua_value = serde_value_to_lua_value(lua, json_value)?;
Ok(lua_value)
}
fn stringify(_lua: &Lua, content: Value) -> mlua::Result<String> {
let json_value = lua_value_to_serde_value(content)?;
tomls::stringify_json_value_to_toml_string(&json_value)
.map_err(|err| Error::custom(format!("aip.toml.stringify fail to stringify. {err}")).into())
}
#[cfg(test)]
mod tests {
type Result<T> = core::result::Result<T, Box<dyn std::error::Error>>;
use crate::_test_support::{assert_contains, eval_lua, setup_lua};
use crate::script::aip_modules;
use crate::support::tomls;
use serde_json::json;
#[tokio::test]
async fn test_script_lua_toml_parse_simple() -> Result<()> {
let lua = setup_lua(aip_modules::aip_toml::init_module, "toml").await?;
let script = r#"
local content = [[
title = "Example"
year = 2024
[owner]
name = "John"
]]
return aip.toml.parse(content)
"#;
let res = eval_lua(&lua, script)?;
let expected = json!({
"title": "Example",
"year": 2024,
"owner": {
"name": "John"
}
});
assert_eq!(res, expected);
Ok(())
}
#[tokio::test]
async fn test_script_lua_toml_parse_invalid() -> Result<()> {
let lua = setup_lua(aip_modules::aip_toml::init_module, "toml").await?;
let script = r#"
local ok, err = pcall(function()
local content = "invalid = [1, 2,,]"
return aip.toml.parse(content)
end)
if ok then
return "should not reach here"
else
return err
end
"#;
let res = eval_lua(&lua, script);
let Err(err) = res else {
panic!("Expected error, got {res:?}");
};
let err_str = err.to_string();
assert_contains(&err_str, "aip.toml.parse failed");
Ok(())
}
#[tokio::test]
async fn test_script_lua_toml_stringify_simple() -> Result<()> {
let lua = setup_lua(aip_modules::aip_toml::init_module, "toml").await?;
let script = r#"
local obj = {
title = "Example",
year = 2024
}
return aip.toml.stringify(obj)
"#;
let res = eval_lua(&lua, script)?;
let result = res.as_str().ok_or("Expected string result")?;
assert_contains(result, r#"title = "Example""#);
assert_contains(result, "year = 2024");
let parsed = tomls::parse_toml_into_json(result)?;
let expected = json!({
"title": "Example",
"year": 2024
});
assert_eq!(parsed, expected);
Ok(())
}
#[tokio::test]
async fn test_script_lua_toml_stringify_nested_tables() -> Result<()> {
let lua = setup_lua(aip_modules::aip_toml::init_module, "toml").await?;
let script = r#"
local obj = {
title = "Example",
owner = {
name = "John",
email = "john@example.com"
},
tags = {"alpha", "beta"}
}
return aip.toml.stringify(obj)
"#;
let res = eval_lua(&lua, script)?;
let result = res.as_str().ok_or("Expected string result")?;
assert_contains(result, "[owner]");
assert_contains(result, r#"name = "John""#);
assert_contains(result, r#"tags = ["alpha", "beta"]"#);
let parsed = tomls::parse_toml_into_json(result)?;
let expected = json!({
"title": "Example",
"owner": {
"name": "John",
"email": "john@example.com"
},
"tags": ["alpha", "beta"]
});
assert_eq!(parsed, expected);
Ok(())
}
}