Skip to main content

luaur_repl_cli/functions/
coverage_dump.rs

1use core::ffi::{c_char, c_int, c_void};
2
3use luaur_vm::functions::lua_getcoverage::lua_getcoverage;
4use luaur_vm::functions::lua_getinfo::lua_getinfo;
5use luaur_vm::macros::lua_getref::lua_getref;
6use luaur_vm::macros::lua_pop::lua_pop;
7use luaur_vm::records::lua_debug::LuaDebug;
8
9use crate::functions::coverage_callback::coverage_callback;
10use crate::functions::coverage_init::G_COVERAGE;
11
12extern "C" {
13    fn fopen(path: *const c_char, mode: *const c_char) -> *mut c_void;
14    fn fclose(stream: *mut c_void) -> c_int;
15    fn fprintf(stream: *mut c_void, format: *const c_char, ...) -> c_int;
16    fn fputs(s: *const c_char, stream: *mut c_void) -> c_int;
17}
18
19// `extern "C"` adapter so `coverage_callback` can be handed to lua_getcoverage
20// as a `lua_Coverage` function pointer.
21unsafe extern "C" fn coverage_callback_cb(
22    context: *mut c_void,
23    function: *const c_char,
24    linedefined: c_int,
25    depth: c_int,
26    hits: *const c_int,
27    size: usize,
28) {
29    coverage_callback(context, function, linedefined, depth, hits, size);
30}
31
32// Faithful port of `void coverageDump(const char* path)`.
33pub fn coverage_dump(path: &str) {
34    unsafe {
35        let coverage = &*core::ptr::addr_of!(G_COVERAGE);
36        let l = coverage.l;
37
38        let path_c = alloc::format!("{}\0", path);
39        let f = fopen(path_c.as_ptr() as *const c_char, c"wb".as_ptr());
40        if f.is_null() {
41            eprintln!("Error opening coverage {}", path);
42            return;
43        }
44
45        fputs(c"TN:\n".as_ptr(), f);
46
47        for &fref in coverage.functions.iter() {
48            lua_getref(l, fref);
49
50            // C++ `lua_Debug ar = {}` — zero-initialized activation record.
51            let mut ar: LuaDebug = core::mem::zeroed();
52            lua_getinfo(l, -1, c"s".as_ptr(), &mut ar as *mut LuaDebug);
53
54            fprintf(f, c"SF:%s\n".as_ptr(), ar.short_src);
55            lua_getcoverage(l, -1, f, Some(coverage_callback_cb));
56            fputs(c"end_of_record\n".as_ptr(), f);
57
58            lua_pop(l, 1);
59        }
60
61        fclose(f);
62
63        println!(
64            "Coverage dump written to {} ({} functions)",
65            path,
66            coverage.functions.len()
67        );
68    }
69}