use mlua::Lua;
const LUA_ALC_SHAPES_T: &str = include_str!("alc_shapes/t.lua");
const LUA_ALC_SHAPES_REFLECT: &str = include_str!("alc_shapes/reflect.lua");
const LUA_ALC_SHAPES_CHECK: &str = include_str!("alc_shapes/check.lua");
const LUA_ALC_SHAPES_LUACATS: &str = include_str!("alc_shapes/luacats.lua");
const LUA_ALC_SHAPES_SPEC_RESOLVER: &str = include_str!("alc_shapes/spec_resolver.lua");
const LUA_ALC_SHAPES_INSTRUMENT: &str = include_str!("alc_shapes/instrument.lua");
const LUA_ALC_SHAPES_INIT: &str = include_str!("alc_shapes/init.lua");
const ALC_SHAPES_PRELOADS: &[(&str, &str)] = &[
("alc_shapes.t", LUA_ALC_SHAPES_T),
("alc_shapes.reflect", LUA_ALC_SHAPES_REFLECT),
("alc_shapes.check", LUA_ALC_SHAPES_CHECK),
("alc_shapes.luacats", LUA_ALC_SHAPES_LUACATS),
("alc_shapes.spec_resolver", LUA_ALC_SHAPES_SPEC_RESOLVER),
("alc_shapes.instrument", LUA_ALC_SHAPES_INSTRUMENT),
("alc_shapes", LUA_ALC_SHAPES_INIT),
];
pub fn gen_alc_shapes_dlua_contents() -> anyhow::Result<String> {
let lua = Lua::new();
{
let package: mlua::Table = lua.globals().get("package")?;
let preload: mlua::Table = package.get("preload")?;
for (mod_name, src) in ALC_SHAPES_PRELOADS.iter().copied() {
let chunk_name = format!("@embedded:gendoc/{mod_name}.lua");
let loader = lua.create_function(move |lua, ()| {
lua.load(src)
.set_name(chunk_name.clone())
.eval::<mlua::Value>()
})?;
preload.set(mod_name, loader)?;
}
}
let shapes: mlua::Table = lua.load(r#"return require("alc_shapes")"#).eval()?;
let luacats: mlua::Table = shapes.get("LuaCats")?;
let gen: mlua::Function = luacats.get("gen")?;
let contents: String = gen.call(shapes.clone())?;
Ok(contents)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn gen_returns_nonempty_with_trailing_newline() {
let contents = gen_alc_shapes_dlua_contents().expect("generation failed");
assert!(!contents.is_empty(), "generated output should not be empty");
assert!(
contents.ends_with('\n'),
"generated output should end with newline"
);
}
#[test]
fn gen_is_deterministic() {
let first = gen_alc_shapes_dlua_contents().expect("first call failed");
let second = gen_alc_shapes_dlua_contents().expect("second call failed");
assert_eq!(first, second, "generation must be deterministic");
}
#[test]
fn regenerate_if_env_set() {
if std::env::var("ALC_REGENERATE").as_deref() != Ok("1") {
return;
}
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let workspace_root = std::path::Path::new(manifest_dir).join("../..");
let out_path = workspace_root.join("types/alc_shapes.d.lua");
let contents = gen_alc_shapes_dlua_contents().expect("generation failed");
std::fs::write(&out_path, &contents).expect("failed to write types/alc_shapes.d.lua");
println!("Written {} bytes to {}", contents.len(), out_path.display());
}
}