mlua_sys/lua52/
compat.rs

1//! MLua compatibility layer for Lua 5.2
2//!
3//! Based on github.com/keplerproject/lua-compat-5.3
4
5use std::os::raw::{c_char, c_int, c_void};
6use std::ptr;
7
8use super::lauxlib::*;
9use super::lua::*;
10
11#[inline(always)]
12unsafe fn compat53_reverse(L: *mut lua_State, mut a: c_int, mut b: c_int) {
13    while a < b {
14        lua_pushvalue(L, a);
15        lua_pushvalue(L, b);
16        lua_replace(L, a);
17        lua_replace(L, b);
18        a += 1;
19        b -= 1;
20    }
21}
22
23//
24// lua ported functions
25//
26
27pub unsafe fn lua_rotate(L: *mut lua_State, mut idx: c_int, mut n: c_int) {
28    idx = lua_absindex(L, idx);
29    if n > 0 {
30        // Faster version
31        for _ in 0..n {
32            lua_insert(L, idx);
33        }
34        return;
35    }
36    let n_elems = lua_gettop(L) - idx + 1;
37    if n < 0 {
38        n += n_elems;
39    }
40    if n > 0 && n < n_elems {
41        luaL_checkstack(L, 2, cstr!("not enough stack slots available"));
42        n = n_elems - n;
43        compat53_reverse(L, idx, idx + n - 1);
44        compat53_reverse(L, idx + n, idx + n_elems - 1);
45        compat53_reverse(L, idx, idx + n_elems - 1);
46    }
47}
48
49#[inline(always)]
50pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int {
51    if lua_type(L, idx) == LUA_TNUMBER {
52        let n = lua_tonumber(L, idx);
53        let i = lua_tointeger(L, idx);
54        if (n - i as lua_Number).abs() < lua_Number::EPSILON {
55            return 1;
56        }
57    }
58    0
59}
60
61#[inline(always)]
62pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer {
63    lua_tointegerx(L, i, ptr::null_mut())
64}
65
66// Implemented for Lua 5.2 as well
67// See https://github.com/keplerproject/lua-compat-5.3/issues/40
68#[inline(always)]
69pub unsafe fn lua_tointegerx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Integer {
70    let mut ok = 0;
71    let n = lua_tonumberx(L, i, &mut ok);
72    let n_int = n as lua_Integer;
73    if ok != 0 && (n - n_int as lua_Number).abs() < lua_Number::EPSILON {
74        if !isnum.is_null() {
75            *isnum = 1;
76        }
77        return n_int;
78    }
79    if !isnum.is_null() {
80        *isnum = 0;
81    }
82    0
83}
84
85#[inline(always)]
86pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char {
87    if l == 0 {
88        lua_pushlstring_(L, cstr!(""), 0)
89    } else {
90        lua_pushlstring_(L, s, l)
91    }
92}
93
94#[inline(always)]
95pub unsafe fn lua_getglobal(L: *mut lua_State, var: *const c_char) -> c_int {
96    lua_getglobal_(L, var);
97    lua_type(L, -1)
98}
99
100#[inline(always)]
101pub unsafe fn lua_gettable(L: *mut lua_State, idx: c_int) -> c_int {
102    lua_gettable_(L, idx);
103    lua_type(L, -1)
104}
105
106#[inline(always)]
107pub unsafe fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char) -> c_int {
108    lua_getfield_(L, idx, k);
109    lua_type(L, -1)
110}
111
112#[inline(always)]
113pub unsafe fn lua_geti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) -> c_int {
114    idx = lua_absindex(L, idx);
115    lua_pushinteger(L, n);
116    lua_gettable(L, idx)
117}
118
119#[inline(always)]
120pub unsafe fn lua_rawget(L: *mut lua_State, idx: c_int) -> c_int {
121    lua_rawget_(L, idx);
122    lua_type(L, -1)
123}
124
125#[inline(always)]
126pub unsafe fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int {
127    let n = n.try_into().expect("cannot convert index to lua_Integer");
128    lua_rawgeti_(L, idx, n);
129    lua_type(L, -1)
130}
131
132#[inline(always)]
133pub unsafe fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int {
134    lua_rawgetp_(L, idx, p);
135    lua_type(L, -1)
136}
137
138#[inline(always)]
139pub unsafe fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int {
140    lua_getuservalue_(L, idx);
141    lua_type(L, -1)
142}
143
144#[inline(always)]
145pub unsafe fn lua_seti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) {
146    luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
147    idx = lua_absindex(L, idx);
148    lua_pushinteger(L, n);
149    lua_insert(L, -2);
150    lua_settable(L, idx);
151}
152
153#[inline(always)]
154pub unsafe fn lua_rawseti(L: *mut lua_State, idx: c_int, n: lua_Integer) {
155    let n = n.try_into().expect("cannot convert index from lua_Integer");
156    lua_rawseti_(L, idx, n)
157}
158
159#[inline(always)]
160pub unsafe fn lua_dump(L: *mut lua_State, writer: lua_Writer, data: *mut c_void, _strip: c_int) -> c_int {
161    lua_dump_(L, writer, data)
162}
163
164#[inline(always)]
165pub unsafe fn lua_resume(L: *mut lua_State, from: *mut lua_State, narg: c_int, nres: *mut c_int) -> c_int {
166    let ret = lua_resume_(L, from, narg);
167    if (ret == LUA_OK || ret == LUA_YIELD) && !(nres.is_null()) {
168        *nres = lua_gettop(L);
169    }
170    ret
171}
172
173//
174// lauxlib ported functions
175//
176
177#[inline(always)]
178pub unsafe fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int {
179    if luaL_getmetafield_(L, obj, e) != 0 {
180        lua_type(L, -1)
181    } else {
182        LUA_TNIL
183    }
184}
185
186#[inline(always)]
187pub unsafe fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int {
188    if luaL_newmetatable_(L, tname) != 0 {
189        lua_pushstring(L, tname);
190        lua_setfield(L, -2, cstr!("__name"));
191        1
192    } else {
193        0
194    }
195}
196
197pub unsafe fn luaL_tolstring(L: *mut lua_State, mut idx: c_int, len: *mut usize) -> *const c_char {
198    idx = lua_absindex(L, idx);
199    if luaL_callmeta(L, idx, cstr!("__tostring")) == 0 {
200        match lua_type(L, idx) {
201            LUA_TNIL => {
202                lua_pushliteral(L, "nil");
203            }
204            LUA_TSTRING | LUA_TNUMBER => {
205                lua_pushvalue(L, idx);
206            }
207            LUA_TBOOLEAN => {
208                if lua_toboolean(L, idx) == 0 {
209                    lua_pushliteral(L, "false");
210                } else {
211                    lua_pushliteral(L, "true");
212                }
213            }
214            t => {
215                let tt = luaL_getmetafield(L, idx, cstr!("__name"));
216                let name = if tt == LUA_TSTRING {
217                    lua_tostring(L, -1)
218                } else {
219                    lua_typename(L, t)
220                };
221                lua_pushfstring(L, cstr!("%s: %p"), name, lua_topointer(L, idx));
222                if tt != LUA_TNIL {
223                    lua_replace(L, -2); // remove '__name'
224                }
225            }
226        };
227    } else if lua_isstring(L, -1) == 0 {
228        luaL_error(L, cstr!("'__tostring' must return a string"));
229    }
230    lua_tolstring(L, -1, len)
231}
232
233pub unsafe fn luaL_requiref(L: *mut lua_State, modname: *const c_char, openf: lua_CFunction, glb: c_int) {
234    luaL_checkstack(L, 3, cstr!("not enough stack slots available"));
235    luaL_getsubtable(L, LUA_REGISTRYINDEX, cstr!("_LOADED"));
236    if lua_getfield(L, -1, modname) == LUA_TNIL {
237        lua_pop(L, 1);
238        lua_pushcfunction(L, openf);
239        lua_pushstring(L, modname);
240        lua_call(L, 1, 1);
241        lua_pushvalue(L, -1);
242        lua_setfield(L, -3, modname);
243    }
244    if glb != 0 {
245        lua_pushvalue(L, -1);
246        lua_setglobal(L, modname);
247    }
248    lua_replace(L, -2);
249}
250
251pub unsafe fn luaL_loadbufferenv(
252    L: *mut lua_State,
253    data: *const c_char,
254    size: usize,
255    name: *const c_char,
256    mode: *const c_char,
257    mut env: c_int,
258) -> c_int {
259    if env != 0 {
260        env = lua_absindex(L, env);
261    }
262    let status = luaL_loadbufferx(L, data, size, name, mode);
263    if status == LUA_OK && env != 0 {
264        lua_pushvalue(L, env);
265        lua_setupvalue(L, -2, 1);
266    }
267    status
268}