Add Lua 5.4 (rc2) support

This commit is contained in:
Alex Orlenko 2020-05-08 12:42:40 +01:00
parent 5c226b4915
commit 539b569ff4
15 changed files with 181 additions and 58 deletions

View File

@ -22,6 +22,19 @@ pub fn probe_lua() -> PathBuf {
// Find using via pkg-config
#[cfg(feature = "lua54")]
{
let mut lua = pkg_config::Config::new()
.range_version((Bound::Included("5.4"), Bound::Excluded("5.5")))
.probe("lua");
if lua.is_err() {
lua = pkg_config::Config::new().probe("lua5.4");
}
return lua.unwrap().include_paths[0].clone();
}
#[cfg(feature = "lua53")]
{
let mut lua = pkg_config::Config::new()

View File

@ -1,11 +1,18 @@
use std::path::PathBuf;
#[cfg(any(feature = "lua53", feature = "lua52", feature = "lua51"))]
#[cfg(any(
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "lua51"
))]
use lua_src;
#[cfg(feature = "luajit")]
use luajit_src;
pub fn probe_lua() -> PathBuf {
#[cfg(feature = "lua54")]
let artifacts = lua_src::Build::new().build(lua_src::Lua54);
#[cfg(feature = "lua53")]
let artifacts = lua_src::Build::new().build(lua_src::Lua53);
#[cfg(feature = "lua52")]

View File

@ -59,27 +59,36 @@ fn build_glue<P: AsRef<Path> + std::fmt::Debug>(include_path: &P) {
fn main() {
#[cfg(not(any(
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "lua51",
feature = "luajit"
)))]
panic!("You must enable one of the features: lua53, lua52, lua51, luajit");
panic!("You must enable one of the features: lua54, lua53, lua52, lua51, luajit");
#[cfg(all(
feature = "lua54",
any(
feature = "lua53",
feature = "lua52",
feature = "lua51",
feature = "luajit"
)
))]
panic!("You can enable only one of the features: lua54, lua53, lua52, lua51, luajit");
#[cfg(all(
feature = "lua53",
any(feature = "lua52", feature = "lua51", feature = "luajit")
))]
panic!("You can enable only one of the features: lua53, lua52, lua51, luajit");
panic!("You can enable only one of the features: lua54, lua53, lua52, lua51, luajit");
#[cfg(all(feature = "lua52", any(feature = "lua51", feature = "luajit")))]
panic!("You can enable only one of the features: lua53, lua52, lua51, luajit");
panic!("You can enable only one of the features: lua54, lua53, lua52, lua51, luajit");
#[cfg(all(feature = "lua51", feature = "luajit"))]
panic!("You can enable only one of the features: lua53, lua52, lua51, luajit");
#[cfg(all(feature = "lua51", feature = "luajit"))]
panic!("You can enable only one of the features: lua53, lua52, lua51, luajit");
panic!("You can enable only one of the features: lua54, lua53, lua52, lua51, luajit");
let include_dir = find::probe_lua();
build_glue(&include_dir);

View File

@ -73,7 +73,7 @@ pub use crate::ffi::lua_State;
pub use crate::error::{Error, ExternalError, ExternalResult, Result};
pub use crate::function::Function;
pub use crate::lua::{Chunk, Lua};
pub use crate::lua::{Chunk, GCMode, Lua};
pub use crate::multi::Variadic;
pub use crate::scope::Scope;
pub use crate::stdlib::StdLib;

View File

@ -57,14 +57,28 @@ struct ExtraData {
ref_free: Vec<c_int>,
}
#[cfg(feature = "send")]
unsafe impl Send for Lua {}
/// Mode of the Lua garbage collector (GC).
///
/// In Lua 5.4 GC can work in two modes: incremental and generational.
/// Previous Lua versions support only incremental GC.
///
/// More information can be found in the Lua 5.x [documentation][lua_doc].
///
/// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#2.5
pub enum GCMode {
Incremental,
#[cfg(feature = "lua54")]
Generational,
}
#[cfg(feature = "async")]
pub(crate) struct AsyncPollPending;
#[cfg(feature = "async")]
pub(crate) static WAKER_REGISTRY_KEY: u8 = 0;
#[cfg(feature = "send")]
unsafe impl Send for Lua {}
impl Drop for Lua {
fn drop(&mut self) {
unsafe {
@ -224,7 +238,7 @@ impl Lua {
}
/// Returns true if the garbage collector is currently running automatically.
#[cfg(any(feature = "lua53", feature = "lua52"))]
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
pub fn gc_is_running(&self) -> bool {
unsafe { ffi::lua_gc(self.main_state, ffi::LUA_GCISRUNNING, 0) != 0 }
}
@ -287,13 +301,78 @@ impl Lua {
/// Sets the 'step multiplier' value of the collector.
///
/// Returns the previous value of the 'step multiplier'. More information can be found in the
/// [Lua 5.3 documentation][lua_doc].
/// Lua 5.x [documentation][lua_doc].
///
/// [lua_doc]: https://www.lua.org/manual/5.3/manual.html#2.5
pub fn gc_set_step_multiplier(&self, step_multiplier: c_int) -> c_int {
unsafe { ffi::lua_gc(self.main_state, ffi::LUA_GCSETSTEPMUL, step_multiplier) }
}
/// Changes the collector to incremental mode with the given parameters.
///
/// Returns the previous mode (always `GCMode::Incremental` in Lua < 5.4).
/// More information can be found in the Lua 5.x [documentation][lua_doc].
///
/// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#2.5.1
pub fn gc_inc(&self, pause: c_int, step_multiplier: c_int, step_size: c_int) -> GCMode {
#[cfg(any(
feature = "lua53",
feature = "lua52",
feature = "lua51",
feature = "luajit"
))]
{
if pause > 0 {
unsafe { ffi::lua_gc(self.main_state, ffi::LUA_GCSETPAUSE, pause) };
}
if step_multiplier > 0 {
unsafe { ffi::lua_gc(self.main_state, ffi::LUA_GCSETSTEPMUL, step_multiplier) };
}
let _ = step_size; // Ignored
return GCMode::Incremental;
}
#[cfg(feature = "lua54")]
let prev_mode = unsafe {
ffi::lua_gc(
self.main_state,
ffi::LUA_GCSETPAUSE,
pause,
step_multiplier,
step_size,
)
};
#[cfg(feature = "lua54")]
match prev_mode {
ffi::LUA_GCINC => GCMode::Incremental,
ffi::LUA_GCGEN => GCMode::Generational,
_ => unreachable!(),
}
}
/// Changes the collector to generational mode with the given parameters.
///
/// Returns the previous mode. More information about the generational GC
/// can be found in the Lua 5.4 [documentation][lua_doc].
///
/// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#2.5.2
#[cfg(feature = "lua54")]
pub fn gc_gen(&self, minor_multiplier: c_int, major_multiplier: c_int) -> GCMode {
let prev_mode = unsafe {
ffi::lua_gc(
self.main_state,
ffi::LUA_GCGEN,
minor_multiplier,
major_multiplier,
)
};
match prev_mode {
ffi::LUA_GCGEN => GCMode::Generational,
ffi::LUA_GCINC => GCMode::Incremental,
_ => unreachable!(),
}
}
/// Returns Lua source code as a `Chunk` builder type.
///
/// In order to actually compile or run the resulting code, you must call [`Chunk::exec`] or
@ -343,7 +422,7 @@ impl Lua {
ffi::LUA_OK => {
if let Some(env) = env {
self.push_value(env)?;
#[cfg(any(feature = "lua53", feature = "lua52"))]
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
ffi::lua_setupvalue(self.state, -2, 1);
#[cfg(any(feature = "lua51", feature = "luajit"))]
ffi::lua_setfenv(self.state, -2);
@ -595,7 +674,7 @@ impl Lua {
unsafe {
let _sg = StackGuard::new(self.state);
assert_stack(self.state, 2);
#[cfg(any(feature = "lua53", feature = "lua52"))]
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
ffi::lua_rawgeti(self.state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
#[cfg(any(feature = "lua51", feature = "luajit"))]
ffi::lua_pushvalue(self.state, ffi::LUA_GLOBALSINDEX);
@ -1214,7 +1293,7 @@ impl Lua {
where
'lua: 'callback,
{
#[cfg(any(feature = "lua53", feature = "lua52"))]
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
self.load_from_std_lib(StdLib::COROUTINE)?;
unsafe extern "C" fn call_callback(state: *mut ffi::lua_State) -> c_int {
@ -1521,7 +1600,7 @@ impl<'lua, 'a> Chunk<'lua, 'a> {
}
unsafe fn load_from_std_lib(state: *mut ffi::lua_State, libs: StdLib) {
#[cfg(any(feature = "lua53", feature = "lua52"))]
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
{
if libs.contains(StdLib::COROUTINE) {
let colib_name = CString::new(ffi::LUA_COLIBNAME).unwrap();
@ -1554,7 +1633,7 @@ unsafe fn load_from_std_lib(state: *mut ffi::lua_State, libs: StdLib) {
ffi::lua_pop(state, 1);
}
#[cfg(feature = "lua53")]
#[cfg(any(feature = "lua54", feature = "lua53"))]
{
if libs.contains(StdLib::UTF8) {
let utf8lib_name = CString::new(ffi::LUA_UTF8LIBNAME).unwrap();

View File

@ -3,12 +3,13 @@
pub use crate::{
AnyUserData as LuaAnyUserData, Chunk as LuaChunk, Error as LuaError,
ExternalError as LuaExternalError, ExternalResult as LuaExternalResult, FromLua, FromLuaMulti,
Function as LuaFunction, Integer as LuaInteger, LightUserData as LuaLightUserData, Lua,
MetaMethod as LuaMetaMethod, MultiValue as LuaMultiValue, Nil as LuaNil, Number as LuaNumber,
RegistryKey as LuaRegistryKey, Result as LuaResult, String as LuaString, Table as LuaTable,
TableExt as LuaTableExt, TablePairs as LuaTablePairs, TableSequence as LuaTableSequence,
Thread as LuaThread, ThreadStatus as LuaThreadStatus, ToLua, ToLuaMulti,
UserData as LuaUserData, UserDataMethods as LuaUserDataMethods, Value as LuaValue,
Function as LuaFunction, GCMode as LuaGCMode, Integer as LuaInteger,
LightUserData as LuaLightUserData, Lua, MetaMethod as LuaMetaMethod,
MultiValue as LuaMultiValue, Nil as LuaNil, Number as LuaNumber, RegistryKey as LuaRegistryKey,
Result as LuaResult, String as LuaString, Table as LuaTable, TableExt as LuaTableExt,
TablePairs as LuaTablePairs, TableSequence as LuaTableSequence, Thread as LuaThread,
ThreadStatus as LuaThreadStatus, ToLua, ToLuaMulti, UserData as LuaUserData,
UserDataMethods as LuaUserDataMethods, Value as LuaValue,
};
#[cfg(feature = "async")]

View File

@ -282,7 +282,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
assert_stack(lua.state, 6);
push_userdata(lua.state, ())?;
#[cfg(feature = "lua53")]
#[cfg(any(feature = "lua54", feature = "lua53"))]
ffi::lua_pushlightuserdata(lua.state, data.as_ptr() as *mut c_void);
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
protect_lua_closure(lua.state, 0, 1, |state| {
@ -383,7 +383,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
// We know the destructor has not run yet because we hold a reference to the callback.
// First, get the environment table
#[cfg(any(feature = "lua53", feature = "lua52"))]
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
ffi::lua_getupvalue(state, -1, 1);
#[cfg(any(feature = "lua51", feature = "luajit"))]
ffi::lua_getfenv(state, -1);

View File

@ -6,13 +6,13 @@ use std::u32;
pub struct StdLib(u32);
impl StdLib {
#[cfg(any(feature = "lua53", feature = "lua52"))]
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
pub const COROUTINE: StdLib = StdLib(1 << 0);
pub const TABLE: StdLib = StdLib(1 << 1);
pub const IO: StdLib = StdLib(1 << 2);
pub const OS: StdLib = StdLib(1 << 3);
pub const STRING: StdLib = StdLib(1 << 4);
#[cfg(feature = "lua53")]
#[cfg(any(feature = "lua54", feature = "lua53"))]
pub const UTF8: StdLib = StdLib(1 << 5);
#[cfg(any(feature = "lua52", feature = "luajit"))]
pub const BIT: StdLib = StdLib(1 << 6);

View File

@ -129,7 +129,9 @@ impl<'lua> Thread<'lua> {
}
ffi::lua_xmove(lua.state, thread_state, nargs);
let ret = ffi::lua_resume(thread_state, lua.state, nargs);
let mut nresults = 0;
let ret = ffi::lua_resume(thread_state, lua.state, nargs, &mut nresults as *mut c_int);
if ret != ffi::LUA_OK && ret != ffi::LUA_YIELD {
protect_lua_closure(lua.state, 0, 0, |_| {
error_traceback(thread_state);
@ -138,7 +140,6 @@ impl<'lua> Thread<'lua> {
return Err(pop_error(thread_state, ret));
}
let nresults = ffi::lua_gettop(thread_state);
let mut results = MultiValue::new();
ffi::lua_xmove(thread_state, lua.state, nresults);

View File

@ -34,25 +34,25 @@ pub enum MetaMethod {
Pow,
/// The unary minus (`-`) operator.
Unm,
#[cfg(feature = "lua53")]
#[cfg(any(feature = "lua54", feature = "lua53"))]
/// The floor division (//) operator.
IDiv,
#[cfg(feature = "lua53")]
#[cfg(any(feature = "lua54", feature = "lua53"))]
/// The bitwise AND (&) operator.
BAnd,
#[cfg(feature = "lua53")]
#[cfg(any(feature = "lua54", feature = "lua53"))]
/// The bitwise OR (|) operator.
BOr,
#[cfg(feature = "lua53")]
#[cfg(any(feature = "lua54", feature = "lua53"))]
/// The bitwise XOR (binary ~) operator.
BXor,
#[cfg(feature = "lua53")]
#[cfg(any(feature = "lua54", feature = "lua53"))]
/// The bitwise NOT (unary ~) operator.
BNot,
#[cfg(feature = "lua53")]
#[cfg(any(feature = "lua54", feature = "lua53"))]
/// The bitwise left shift (<<) operator.
Shl,
#[cfg(feature = "lua53")]
#[cfg(any(feature = "lua54", feature = "lua53"))]
/// The bitwise right shift (>>) operator.
Shr,
/// The string concatenation operator `..`.
@ -75,7 +75,7 @@ pub enum MetaMethod {
///
/// This is not an operator, but will be called by methods such as `tostring` and `print`.
ToString,
#[cfg(any(feature = "lua53", feature = "lua52"))]
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
/// The `__pairs` metamethod.
///
/// This is not an operator, but it will be called by the built-in `pairs` function.
@ -92,19 +92,19 @@ impl MetaMethod {
MetaMethod::Mod => b"__mod",
MetaMethod::Pow => b"__pow",
MetaMethod::Unm => b"__unm",
#[cfg(feature = "lua53")]
#[cfg(any(feature = "lua54", feature = "lua53"))]
MetaMethod::IDiv => b"__idiv",
#[cfg(feature = "lua53")]
#[cfg(any(feature = "lua54", feature = "lua53"))]
MetaMethod::BAnd => b"__band",
#[cfg(feature = "lua53")]
#[cfg(any(feature = "lua54", feature = "lua53"))]
MetaMethod::BOr => b"__bor",
#[cfg(feature = "lua53")]
#[cfg(any(feature = "lua54", feature = "lua53"))]
MetaMethod::BXor => b"__bxor",
#[cfg(feature = "lua53")]
#[cfg(any(feature = "lua54", feature = "lua53"))]
MetaMethod::BNot => b"__bnot",
#[cfg(feature = "lua53")]
#[cfg(any(feature = "lua54", feature = "lua53"))]
MetaMethod::Shl => b"__shl",
#[cfg(feature = "lua53")]
#[cfg(any(feature = "lua54", feature = "lua53"))]
MetaMethod::Shr => b"__shr",
MetaMethod::Concat => b"__concat",
MetaMethod::Len => b"__len",
@ -115,7 +115,7 @@ impl MetaMethod {
MetaMethod::NewIndex => b"__newindex",
MetaMethod::Call => b"__call",
MetaMethod::ToString => b"__tostring",
#[cfg(any(feature = "lua53", feature = "lua52"))]
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
MetaMethod::Pairs => b"__pairs",
}
}
@ -387,18 +387,19 @@ impl<'lua> AnyUserData<'lua> {
/// Sets an associated value to this `AnyUserData`.
///
/// The value may be any Lua value whatsoever, and can be retrieved with [`get_user_value`].
/// As Lua < 5.3 allows to store only tables, the value will be stored in a table at index 1.
///
/// [`get_user_value`]: #method.get_user_value
pub fn set_user_value<V: ToLua<'lua>>(&self, v: V) -> Result<()> {
let lua = self.0.lua;
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
let v = {
// Lua 5.2/5.1 allows to store only table. Then we will wrap the value.
// Lua 5.2/5.1 allows to store only a table. Then we will wrap the value.
let t = lua.create_table()?;
t.raw_set(1, v)?;
crate::Value::Table(t)
};
#[cfg(feature = "lua53")]
#[cfg(any(feature = "lua54", feature = "lua53"))]
let v = v.to_lua(lua)?;
unsafe {
let _sg = StackGuard::new(lua.state);
@ -412,6 +413,8 @@ impl<'lua> AnyUserData<'lua> {
/// Returns an associated value set by [`set_user_value`].
///
/// For Lua < 5.3 the value will be automatically extracted from the table wrapper from index 1.
///
/// [`set_user_value`]: #method.set_user_value
pub fn get_user_value<V: FromLua<'lua>>(&self) -> Result<V> {
let lua = self.0.lua;
@ -424,7 +427,7 @@ impl<'lua> AnyUserData<'lua> {
};
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
return crate::Table::from_lua(res, lua)?.get(1);
#[cfg(feature = "lua53")]
#[cfg(any(feature = "lua54", feature = "lua53"))]
V::from_lua(res, lua)
}

View File

@ -485,7 +485,7 @@ pub unsafe extern "C" fn error_traceback(state: *mut ffi::lua_State) -> c_int {
// Does not call lua_checkstack, uses 1 stack space.
pub unsafe fn get_main_state(state: *mut ffi::lua_State) -> *mut ffi::lua_State {
#[cfg(any(feature = "lua53", feature = "lua52"))]
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
{
ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_MAINTHREAD);
let main_state = ffi::lua_tothread(state, -1);

View File

@ -7,7 +7,7 @@ fn test_gc_control() -> Result<()> {
let lua = Lua::new();
let globals = lua.globals();
#[cfg(any(feature = "lua53", feature = "lua52"))]
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
{
assert!(lua.gc_is_running());
lua.gc_stop();

View File

@ -389,7 +389,7 @@ fn test_num_conversion() -> Result<()> {
assert_eq!(lua.load("1.0").eval::<i64>()?, 1);
assert_eq!(lua.load("1.0").eval::<f64>()?, 1.0);
#[cfg(feature = "lua53")]
#[cfg(any(feature = "lua54", feature = "lua53"))]
assert_eq!(lua.load("1.0").eval::<String>()?, "1.0");
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
assert_eq!(lua.load("1.0").eval::<String>()?, "1");
@ -466,7 +466,12 @@ fn test_pcall_xpcall() -> Result<()> {
assert_eq!(globals.get::<_, String>("pcall_error")?, "testerror");
assert_eq!(globals.get::<_, bool>("xpcall_statusr")?, false);
#[cfg(any(feature = "lua53", feature = "lua52", feature = "luajit"))]
#[cfg(any(
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "luajit"
))]
assert_eq!(
globals.get::<_, std::string::String>("xpcall_error")?,
"testerror"
@ -799,7 +804,7 @@ fn context_thread() -> Result<()> {
)
.into_function()?;
#[cfg(any(feature = "lua53", feature = "lua52"))]
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
f.call::<_, ()>(lua.current_thread())?;
#[cfg(any(feature = "lua51", feature = "luajit"))]

View File

@ -100,7 +100,12 @@ fn coroutine_from_closure() -> Result<()> {
let thrd_main = lua.create_function(|_, ()| Ok(()))?;
lua.globals().set("main", thrd_main)?;
#[cfg(any(feature = "lua53", feature = "lua52", feature = "luajit"))]
#[cfg(any(
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "luajit"
))]
let thrd: Thread = lua.load("coroutine.create(main)").eval()?;
#[cfg(feature = "lua51")]
let thrd: Thread = lua

View File

@ -95,7 +95,7 @@ fn test_metamethods() -> Result<()> {
Err("no such custom index".to_lua_err())
}
});
#[cfg(any(feature = "lua53", feature = "lua52"))]
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
methods.add_meta_method(MetaMethod::Pairs, |lua, data, ()| {
use std::iter::FromIterator;
let stateless_iter = lua.create_function(|_, (data, i): (MyUserData, i64)| {
@ -120,7 +120,7 @@ fn test_metamethods() -> Result<()> {
10
);
#[cfg(any(feature = "lua53", feature = "lua52"))]
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
let pairs_it = {
lua.load(
r#"
@ -140,7 +140,7 @@ fn test_metamethods() -> Result<()> {
assert_eq!(lua.load("userdata1 - userdata2").eval::<MyUserData>()?.0, 4);
assert_eq!(lua.load("userdata1:get()").eval::<i64>()?, 7);
assert_eq!(lua.load("userdata2.inner").eval::<i64>()?, 3);
#[cfg(any(feature = "lua53", feature = "lua52"))]
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
assert_eq!(pairs_it.call::<_, i64>(())?, 28);
assert!(lua.load("userdata2.nonexist_field").eval::<()>().is_err());