factorio_mlua_sys/lua_factorio/
compat.rs

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