Skip to content

Commit 1ebb4b4

Browse files
committed
Support 52-bit integers for Luau
Simply to float conversion (it actually never fails or goes out of range)
1 parent 5ab9766 commit 1ebb4b4

File tree

7 files changed

+77
-44
lines changed

7 files changed

+77
-44
lines changed

mlua-sys/src/luau/compat.rs

+25
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,11 @@ pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int {
127127
0
128128
}
129129

130+
#[inline(always)]
131+
pub unsafe fn lua_pushinteger(L: *mut lua_State, i: lua_Integer) {
132+
lua_pushnumber(L, i as lua_Number);
133+
}
134+
130135
#[inline(always)]
131136
pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer {
132137
lua_tointegerx(L, i, ptr::null_mut())
@@ -178,6 +183,7 @@ pub unsafe fn lua_geti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) -> c_i
178183

179184
#[inline(always)]
180185
pub unsafe fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int {
186+
let n = n.try_into().expect("cannot convert index from lua_Integer");
181187
lua_rawgeti_(L, idx, n)
182188
}
183189

@@ -213,6 +219,7 @@ pub unsafe fn lua_seti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) {
213219

214220
#[inline(always)]
215221
pub unsafe fn lua_rawseti(L: *mut lua_State, idx: c_int, n: lua_Integer) {
222+
let n = n.try_into().expect("cannot convert index from lua_Integer");
216223
lua_rawseti_(L, idx, n)
217224
}
218225

@@ -315,6 +322,24 @@ pub unsafe fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char)
315322
}
316323
}
317324

325+
#[inline(always)]
326+
pub unsafe fn luaL_checkinteger(L: *mut lua_State, narg: c_int) -> lua_Integer {
327+
let mut isnum = 0;
328+
let int = lua_tointegerx(L, narg, &mut isnum);
329+
if isnum == 0 {
330+
luaL_typeerror(L, narg, lua_typename(L, LUA_TNUMBER));
331+
}
332+
int
333+
}
334+
335+
pub unsafe fn luaL_optinteger(L: *mut lua_State, narg: c_int, def: lua_Integer) -> lua_Integer {
336+
if lua_isnoneornil(L, narg) != 0 {
337+
def
338+
} else {
339+
luaL_checkinteger(L, narg)
340+
}
341+
}
342+
318343
#[inline(always)]
319344
pub unsafe fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int {
320345
if luaL_getmetafield_(L, obj, e) != 0 {

mlua-sys/src/luau/lauxlib.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use std::os::raw::{c_char, c_float, c_int, c_void};
44
use std::ptr;
55

6-
use super::lua::{self, lua_CFunction, lua_Integer, lua_Number, lua_State, lua_Unsigned, LUA_REGISTRYINDEX};
6+
use super::lua::{self, lua_CFunction, lua_Number, lua_State, lua_Unsigned, LUA_REGISTRYINDEX};
77

88
#[repr(C)]
99
pub struct luaL_Reg {
@@ -33,8 +33,10 @@ extern "C-unwind" {
3333
pub fn luaL_checkboolean(L: *mut lua_State, narg: c_int) -> c_int;
3434
pub fn luaL_optboolean(L: *mut lua_State, narg: c_int, def: c_int) -> c_int;
3535

36-
pub fn luaL_checkinteger(L: *mut lua_State, narg: c_int) -> lua_Integer;
37-
pub fn luaL_optinteger(L: *mut lua_State, narg: c_int, def: lua_Integer) -> lua_Integer;
36+
#[link_name = "luaL_checkinteger"]
37+
pub fn luaL_checkinteger_(L: *mut lua_State, narg: c_int) -> c_int;
38+
#[link_name = "luaL_optinteger"]
39+
pub fn luaL_optinteger_(L: *mut lua_State, narg: c_int, def: c_int) -> c_int;
3840
pub fn luaL_checkunsigned(L: *mut lua_State, narg: c_int) -> lua_Unsigned;
3941
pub fn luaL_optunsigned(L: *mut lua_State, narg: c_int, def: lua_Unsigned) -> lua_Unsigned;
4042

mlua-sys/src/luau/lua.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,11 @@ pub const LUA_MINSTACK: c_int = 20;
6969
/// A Lua number, usually equivalent to `f64`.
7070
pub type lua_Number = c_double;
7171

72-
/// A Lua integer, equivalent to `i32`.
73-
pub type lua_Integer = c_int;
72+
/// A Lua integer, usually equivalent to `i64`
73+
#[cfg(target_pointer_width = "32")]
74+
pub type lua_Integer = i32;
75+
#[cfg(target_pointer_width = "64")]
76+
pub type lua_Integer = i64;
7477

7578
/// A Lua unsigned integer, equivalent to `u32`.
7679
pub type lua_Unsigned = c_uint;
@@ -136,7 +139,7 @@ extern "C-unwind" {
136139

137140
pub fn lua_tonumberx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Number;
138141
#[link_name = "lua_tointegerx"]
139-
pub fn lua_tointegerx_(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Integer;
142+
pub fn lua_tointegerx_(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> c_int;
140143
pub fn lua_tounsignedx(L: *mut lua_State, idx: c_int, isnum: *mut c_int) -> lua_Unsigned;
141144
pub fn lua_tovector(L: *mut lua_State, idx: c_int) -> *const c_float;
142145
pub fn lua_toboolean(L: *mut lua_State, idx: c_int) -> c_int;
@@ -160,7 +163,8 @@ extern "C-unwind" {
160163
//
161164
pub fn lua_pushnil(L: *mut lua_State);
162165
pub fn lua_pushnumber(L: *mut lua_State, n: lua_Number);
163-
pub fn lua_pushinteger(L: *mut lua_State, n: lua_Integer);
166+
#[link_name = "lua_pushinteger"]
167+
pub fn lua_pushinteger_(L: *mut lua_State, n: c_int);
164168
pub fn lua_pushunsigned(L: *mut lua_State, n: lua_Unsigned);
165169
#[cfg(not(feature = "luau-vector4"))]
166170
pub fn lua_pushvector(L: *mut lua_State, x: c_float, y: c_float, z: c_float);
@@ -310,13 +314,13 @@ extern "C-unwind" {
310314
//
311315

312316
#[inline(always)]
313-
pub unsafe fn lua_tonumber(L: *mut lua_State, i: c_int) -> lua_Number {
314-
lua_tonumberx(L, i, ptr::null_mut())
317+
pub unsafe fn lua_tonumber(L: *mut lua_State, idx: c_int) -> lua_Number {
318+
lua_tonumberx(L, idx, ptr::null_mut())
315319
}
316320

317321
#[inline(always)]
318-
pub unsafe fn lua_tointeger_(L: *mut lua_State, i: c_int) -> lua_Integer {
319-
lua_tointegerx_(L, i, ptr::null_mut())
322+
pub unsafe fn lua_tointeger_(L: *mut lua_State, idx: c_int) -> c_int {
323+
lua_tointegerx_(L, idx, ptr::null_mut())
320324
}
321325

322326
#[inline(always)]

src/conversion.rs

+5-31
Original file line numberDiff line numberDiff line change
@@ -808,15 +808,9 @@ macro_rules! lua_convert_int {
808808
impl IntoLua for $x {
809809
#[inline]
810810
fn into_lua(self, _: &Lua) -> Result<Value> {
811-
cast(self)
811+
Ok(cast(self)
812812
.map(Value::Integer)
813-
.or_else(|| cast(self).map(Value::Number))
814-
// This is impossible error because conversion to Number never fails
815-
.ok_or_else(|| Error::ToLuaConversionError {
816-
from: stringify!($x).to_string(),
817-
to: "number",
818-
message: Some("out of range".to_owned()),
819-
})
813+
.unwrap_or_else(|| Value::Number(self as ffi::lua_Number)))
820814
}
821815

822816
#[inline]
@@ -899,13 +893,7 @@ macro_rules! lua_convert_float {
899893
impl IntoLua for $x {
900894
#[inline]
901895
fn into_lua(self, _: &Lua) -> Result<Value> {
902-
cast(self)
903-
.ok_or_else(|| Error::ToLuaConversionError {
904-
from: stringify!($x).to_string(),
905-
to: "number",
906-
message: Some("out of range".to_string()),
907-
})
908-
.map(Value::Number)
896+
Ok(Value::Number(self as _))
909897
}
910898
}
911899

@@ -914,33 +902,19 @@ macro_rules! lua_convert_float {
914902
fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
915903
let ty = value.type_name();
916904
lua.coerce_number(value)?
905+
.map(|n| n as $x)
917906
.ok_or_else(|| Error::FromLuaConversionError {
918907
from: ty,
919908
to: stringify!($x).to_string(),
920909
message: Some("expected number or string coercible to number".to_string()),
921910
})
922-
.and_then(|n| {
923-
cast(n).ok_or_else(|| Error::FromLuaConversionError {
924-
from: ty,
925-
to: stringify!($x).to_string(),
926-
message: Some("number out of range".to_string()),
927-
})
928-
})
929911
}
930912

931913
unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> {
932914
let state = lua.state();
933915
let type_id = ffi::lua_type(state, idx);
934916
if type_id == ffi::LUA_TNUMBER {
935-
let mut ok = 0;
936-
let i = ffi::lua_tonumberx(state, idx, &mut ok);
937-
if ok != 0 {
938-
return cast(i).ok_or_else(|| Error::FromLuaConversionError {
939-
from: "number",
940-
to: stringify!($x).to_string(),
941-
message: Some("out of range".to_owned()),
942-
});
943-
}
917+
return Ok(ffi::lua_tonumber(state, idx) as _);
944918
}
945919
// Fallback to default
946920
Self::from_lua(lua.stack_value(idx, Some(type_id)), lua.lua())

src/luau/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ unsafe extern "C-unwind" fn lua_collectgarbage(state: *mut ffi::lua_State) -> c_
5151
1
5252
}
5353
Ok("step") => {
54-
let res = ffi::lua_gc(state, ffi::LUA_GCSTEP, arg);
54+
let res = ffi::lua_gc(state, ffi::LUA_GCSTEP, arg as _);
5555
ffi::lua_pushboolean(state, res);
5656
1
5757
}

src/value.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,10 @@ impl Value {
272272
/// If the value is a Lua [`Integer`], try to convert it to `i64` or return `None` otherwise.
273273
#[inline]
274274
pub fn as_i64(&self) -> Option<i64> {
275-
self.as_integer().map(i64::from)
275+
#[cfg(target_pointer_width = "64")]
276+
return self.as_integer();
277+
#[cfg(not(target_pointer_width = "64"))]
278+
return self.as_integer().map(i64::from);
276279
}
277280

278281
/// Cast the value to `u64`.

tests/tests.rs

+25
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,31 @@ fn test_panic() -> Result<()> {
483483
Ok(())
484484
}
485485

486+
#[cfg(target_pointer_width = "64")]
487+
#[test]
488+
fn test_safe_integers() -> Result<()> {
489+
const MAX_SAFE_INTEGER: i64 = 2i64.pow(53) - 1;
490+
const MIN_SAFE_INTEGER: i64 = -2i64.pow(53) + 1;
491+
492+
let lua = Lua::new();
493+
let f = lua.load("return ...").into_function()?;
494+
495+
assert_eq!(f.call::<i64>(MAX_SAFE_INTEGER)?, MAX_SAFE_INTEGER);
496+
assert_eq!(f.call::<i64>(MIN_SAFE_INTEGER)?, MIN_SAFE_INTEGER);
497+
498+
// For Lua versions that does not support 64-bit integers, the values will be converted to f64
499+
#[cfg(any(feature = "luau", feature = "lua51", feature = "luajit"))]
500+
{
501+
assert_ne!(f.call::<i64>(MAX_SAFE_INTEGER + 2)?, MAX_SAFE_INTEGER + 2);
502+
assert_ne!(f.call::<i64>(MIN_SAFE_INTEGER - 2)?, MIN_SAFE_INTEGER - 2);
503+
504+
let n = f.call::<i64>(i64::MAX)?;
505+
println!("i64::MAX = {}", n);
506+
}
507+
508+
Ok(())
509+
}
510+
486511
#[test]
487512
fn test_num_conversion() -> Result<()> {
488513
let lua = Lua::new();

0 commit comments

Comments
 (0)