nvim_oxi_luajit/
utils.rs

1use core::ffi::{CStr, c_int};
2use core::fmt::Display;
3
4use crate::ffi::{self, State};
5
6/// Does nothing if the stack is already taller than `n`, grows the stack
7/// height to `n` by adding `nil`s if it's not.
8pub unsafe fn grow_stack(lstate: *mut State, n: c_int) {
9    unsafe {
10        if ffi::lua_gettop(lstate) < n {
11            ffi::lua_settop(lstate, n);
12        }
13    }
14}
15
16/// Returns a displayable representation of the Lua value at a given stack
17/// index.
18pub unsafe fn debug_value(lstate: *mut State, n: c_int) -> Box<dyn Display> {
19    match ffi::lua_type(lstate, n) {
20        ffi::LUA_TNONE | ffi::LUA_TNIL => Box::new("()"),
21
22        ffi::LUA_TBOOLEAN => Box::new(ffi::lua_toboolean(lstate, n) == 1),
23
24        ffi::LUA_TSTRING => Box::new(
25            CStr::from_ptr(ffi::lua_tostring(lstate, n)).to_string_lossy(),
26        ),
27
28        ffi::LUA_TNUMBER => Box::new(ffi::lua_tonumber(lstate, n)),
29
30        _ => Box::new("other"),
31    }
32}
33
34/// Assumes that the value at index `index` is a table and returns whether it's
35/// an array table (as opposed to a dictionary table).
36pub unsafe fn is_table_array(lstate: *mut State, index: c_int) -> bool {
37    ffi::lua_pushnil(lstate);
38
39    if ffi::lua_next(lstate, index - 1) == 0 {
40        // Empty table.
41        if ffi::lua_getmetatable(lstate, index) == 0 {
42            return true;
43        }
44        ffi::lua_pop(lstate, 1);
45        return false;
46    }
47
48    let ty = ffi::lua_type(lstate, -2);
49    ffi::lua_pop(lstate, 2);
50    ty == ffi::LUA_TNUMBER
51}
52
53/// Returns the type of the Lua value at a given stack index.
54pub unsafe fn debug_type(lstate: *mut State, n: c_int) -> impl Display {
55    CStr::from_ptr(ffi::luaL_typename(lstate, n)).to_string_lossy()
56}
57
58/// Pretty prints the contents of the Lua stack to the Neovim message area.
59pub unsafe fn debug_stack(lstate: *mut State) {
60    let height = ffi::lua_gettop(lstate);
61
62    let stack_pp = (1..height + 1)
63        .map(|n| {
64            let idx = height + 1 - n;
65            let value = debug_value(lstate, -n);
66            let typename = debug_type(lstate, -n);
67            format!("{idx}: {value} ({typename})")
68        })
69        .collect::<Vec<String>>()
70        .join("\n");
71
72    crate::print!("{stack_pp}");
73}
74
75pub unsafe fn push_error<E: core::fmt::Display + ?Sized>(
76    err: &E,
77    lstate: *mut State,
78) -> ! {
79    let msg = err.to_string();
80    ffi::lua_pushlstring(lstate, msg.as_ptr() as *const _, msg.len());
81    drop(msg);
82    ffi::lua_error(lstate);
83}
84
85pub fn type_name(ty: c_int) -> &'static str {
86    match ty {
87        ffi::LUA_TNONE => "empty stack",
88        ffi::LUA_TNIL => "nil",
89        ffi::LUA_TBOOLEAN => "boolean",
90        ffi::LUA_TLIGHTUSERDATA => "light userdata",
91        ffi::LUA_TNUMBER => "number",
92        ffi::LUA_TSTRING => "string",
93        ffi::LUA_TTABLE => "table",
94        ffi::LUA_TFUNCTION => "function",
95        ffi::LUA_TUSERDATA => "userdata",
96        ffi::LUA_TTHREAD => "thread",
97        _ => unreachable!(),
98    }
99}