Skip to content

Commit 815d1bd

Browse files
committed
Better handling negative zeros to match Lua 5.3+ behavior
In Lua 5.3+ the function `lua_isinteger` returns "false" for -0.0 numbers. In earlier Lua versions we should follow the same behavior to avoid losing the sign when converting to Integer. Close #618
1 parent 78331ce commit 815d1bd

File tree

5 files changed

+24
-4
lines changed

5 files changed

+24
-4
lines changed

mlua-sys/src/lua51/compat.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,8 @@ pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int {
186186
if lua_type(L, idx) == LUA_TNUMBER {
187187
let n = lua_tonumber(L, idx);
188188
let i = lua_tointeger(L, idx);
189-
if (n - i as lua_Number).abs() < lua_Number::EPSILON {
189+
// Lua 5.3+ returns "false" for `-0.0`
190+
if (n - i as lua_Number).abs() < lua_Number::EPSILON && !(n == 0.0 && n.is_sign_negative()) {
190191
return 1;
191192
}
192193
}

mlua-sys/src/lua52/compat.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int {
5151
if lua_type(L, idx) == LUA_TNUMBER {
5252
let n = lua_tonumber(L, idx);
5353
let i = lua_tointeger(L, idx);
54-
if (n - i as lua_Number).abs() < lua_Number::EPSILON {
54+
// Lua 5.3+ returns "false" for `-0.0`
55+
if (n - i as lua_Number).abs() < lua_Number::EPSILON && !(n == 0.0 && n.is_sign_negative()) {
5556
return 1;
5657
}
5758
}

mlua-sys/src/luau/compat.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int {
120120
if lua_type(L, idx) == LUA_TNUMBER {
121121
let n = lua_tonumber(L, idx);
122122
let i = lua_tointeger(L, idx);
123-
if (n - i as lua_Number).abs() < lua_Number::EPSILON {
123+
// Lua 5.3+ returns "false" for `-0.0`
124+
if (n - i as lua_Number).abs() < lua_Number::EPSILON && !(n == 0.0 && n.is_sign_negative()) {
124125
return 1;
125126
}
126127
}

src/state/raw.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -726,9 +726,13 @@ impl RawLua {
726726
ffi::LUA_TNUMBER => {
727727
use crate::types::Number;
728728

729+
fn same(n: Number, i: Integer) -> bool {
730+
(n - (i as Number)).abs() < Number::EPSILON && !(n == 0.0 && n.is_sign_negative())
731+
}
732+
729733
let n = ffi::lua_tonumber(state, idx);
730734
match num_traits::cast(n) {
731-
Some(i) if (n - (i as Number)).abs() < Number::EPSILON => Value::Integer(i),
735+
Some(i) if same(n, i) => Value::Integer(i),
732736
_ => Value::Number(n),
733737
}
734738
}

tests/conversion.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,19 @@ fn test_float_from_lua() -> Result<()> {
372372
// Should fallback to default conversion
373373
assert_eq!(f.call::<f32>("42.0")?, 42.0);
374374

375+
// Negative zero
376+
let negative_zero = lua.load("return -0.0").eval::<f64>()?;
377+
assert_eq!(negative_zero, 0.0);
378+
assert!(negative_zero.is_sign_negative());
379+
380+
// In Lua <5.3 all numbers are floats
381+
#[cfg(not(any(feature = "lua54", feature = "lua53")))]
382+
{
383+
let negative_zero = lua.load("return -0").eval::<f64>()?;
384+
assert_eq!(negative_zero, 0.0);
385+
assert!(negative_zero.is_sign_negative());
386+
}
387+
375388
Ok(())
376389
}
377390

0 commit comments

Comments
 (0)