Skip to main content

luaur_vm/functions/
lua_c_dump.rs

1use crate::functions::dumpgco::dumpgco;
2use crate::functions::dumpref::dumpref;
3use crate::functions::lua_m_visitgco::lua_m_visitgco;
4use crate::macros::gcvalue::gcvalue;
5use crate::macros::lua_memory_categories::LUA_MEMORY_CATEGORIES;
6use crate::macros::obj_2_gco::obj2gco;
7use crate::type_aliases::lua_state::lua_State;
8use core::ffi::{c_char, c_int, c_void};
9
10#[allow(non_snake_case)]
11pub unsafe fn lua_c_dump(
12    l: *mut lua_State,
13    file: *mut c_void,
14    category_name: Option<unsafe extern "C" fn(*mut lua_State, u8) -> *const c_char>,
15) {
16    let g = (*l).global;
17    let f = file;
18
19    extern "C" {
20        fn fprintf(stream: *mut c_void, format: *const c_char, ...) -> c_int;
21    }
22
23    fprintf(f, b"{\"objects\":{\n\0".as_ptr() as *const c_char);
24
25    // The C++ code uses obj2gco(g->mainthread).
26    // In Rust, obj2gco! expects a pointer to a type where (*p).tt exists or is accessible.
27    // Since lua_State's first field is hdr (GCheader) which contains tt, we cast to *mut GCObject directly
28    // to satisfy the macro's expectation of a collectable object pointer.
29    let mainthread_gco = (*g).mainthread as *mut crate::records::gc_object::GCObject;
30    dumpgco(f, core::ptr::null_mut(), mainthread_gco);
31
32    lua_m_visitgco(l, f, dumpgco as *mut c_void);
33
34    fprintf(
35        f,
36        b"\"0\":{\"type\":\"userdata\",\"cat\":0,\"size\":0}\n},\"roots\":{\n\"mainthread\":\0"
37            .as_ptr() as *const c_char,
38    );
39    dumpref(f, mainthread_gco);
40    fprintf(f, b",\"registry\":\0".as_ptr() as *const c_char);
41    dumpref(f, gcvalue!(&(*g).registry));
42
43    fprintf(
44        f,
45        b"},\"stats\":{\n\"size\":%d,\n\0".as_ptr() as *const c_char,
46        (*g).totalbytes as c_int,
47    );
48
49    fprintf(f, b"\"categories\":{\n\0".as_ptr() as *const c_char);
50    for i in 0..LUA_MEMORY_CATEGORIES {
51        let bytes = (*g).memcatbytes[i as usize];
52        if bytes != 0 {
53            if let Some(cat_name_fn) = category_name {
54                let name = cat_name_fn(l, i as u8);
55                fprintf(
56                    f,
57                    b"\"%d\":{\"name\":\"%s\", \"size\":%d},\n\0".as_ptr() as *const c_char,
58                    i,
59                    name,
60                    bytes as c_int,
61                );
62            } else {
63                fprintf(
64                    f,
65                    b"\"%d\":{\"size\":%d},\n\0".as_ptr() as *const c_char,
66                    i,
67                    bytes as c_int,
68                );
69            }
70        }
71    }
72    fprintf(f, b"\"none\":{}\n}\n}}\n\0".as_ptr() as *const c_char);
73}
74
75#[allow(non_snake_case)]
76pub unsafe fn luaC_dump(
77    L: *mut lua_State,
78    file: *mut c_void,
79    categoryName: Option<unsafe extern "C" fn(*mut lua_State, u8) -> *const c_char>,
80) {
81    lua_c_dump(L, file, categoryName);
82}