Skip to main content

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