Compare commits

..

9 Commits

Author SHA1 Message Date
Alex Orlenko 9caf3542d9 v0.10.3 2025-01-27 21:33:51 +00:00
Alex Orlenko cb45db05fa Update README/CHANGELOG 2025-01-27 21:33:24 +00:00
Alex Orlenko d1cb2a9a96 mlua-sys: v0.6.7 2025-01-27 21:20:47 +00:00
Alex Orlenko aa3f6ba46c Fix prototype of new Luau compiler options and methods 2025-01-27 21:19:31 +00:00
Alex Orlenko cc57bed4c8 Update Luau to 0.657 2025-01-27 14:19:40 +00:00
Radiant b5d38ab2e3 Set Default for LuaValue to be nil. (#512) 2025-01-19 23:52:58 +00:00
Alex Orlenko cd4091f64d Allow exhaustive match on Value.
It was not possible because `ValueRef` variant in `Value::Other` was private.
Closes #502 and #503
2024-12-10 23:37:19 +00:00
Alex Orlenko 91e069a77e Optimize (and simplify) protected mode for Rust function calls 2024-12-07 00:04:12 +00:00
Alex Orlenko cacd3dc70f Add Table::set_safeenv method (Luau) 2024-12-04 10:40:49 +00:00
12 changed files with 151 additions and 45 deletions
+6
View File
@@ -1,3 +1,9 @@
## v0.10.2 (Jan 27th, 2025)
- Set `Default` for `Value` to be `Nil`
- Allow exhaustive match on `Value` (#502)
- Add `Table::set_safeenv` method (Luau)
## v0.10.2 (Dec 1st, 2024)
- Switch proc-macro-error to proc-macro-error2 (#493)
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "mlua"
version = "0.10.2" # remember to update mlua_derive
version = "0.10.3" # remember to update mlua_derive
authors = ["Aleksandr Orlenko <zxteam@pm.me>", "kyren <catherine@kyju.org>"]
rust-version = "1.79.0"
edition = "2021"
+2 -2
View File
@@ -133,7 +133,7 @@ Add to `Cargo.toml` :
``` toml
[dependencies]
mlua = { version = "0.10.2", features = ["lua54", "vendored"] }
mlua = { version = "0.10", features = ["lua54", "vendored"] }
```
`main.rs`
@@ -168,7 +168,7 @@ Add to `Cargo.toml` :
crate-type = ["cdylib"]
[dependencies]
mlua = { version = "0.10.2", features = ["lua54", "module"] }
mlua = { version = "0.10", features = ["lua54", "module"] }
```
`lib.rs` :
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "mlua-sys"
version = "0.6.6"
version = "0.6.7"
authors = ["Aleksandr Orlenko <zxteam@pm.me>"]
rust-version = "1.71"
edition = "2021"
@@ -40,7 +40,7 @@ cfg-if = "1.0"
pkg-config = "0.3.17"
lua-src = { version = ">= 547.0.0, < 547.1.0", optional = true }
luajit-src = { version = ">= 210.5.0, < 210.6.0", optional = true }
luau0-src = { version = "0.11.1", optional = true }
luau0-src = { version = "0.12.0", optional = true }
[lints.rust]
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(raw_dylib)'] }
+51
View File
@@ -1,5 +1,6 @@
//! Contains definitions from `luacode.h`.
use std::marker::{PhantomData, PhantomPinned};
use std::os::raw::{c_char, c_int, c_void};
use std::{ptr, slice};
@@ -15,6 +16,10 @@ pub struct lua_CompileOptions {
pub vectorType: *const c_char,
pub mutableGlobals: *const *const c_char,
pub userdataTypes: *const *const c_char,
pub librariesWithKnownMembers: *const *const c_char,
pub libraryMemberTypeCallback: Option<lua_LibraryMemberTypeCallback>,
pub libraryMemberConstantCallback: Option<lua_LibraryMemberConstantCallback>,
pub disabledBuiltins: *const *const c_char,
}
impl Default for lua_CompileOptions {
@@ -29,10 +34,56 @@ impl Default for lua_CompileOptions {
vectorType: ptr::null(),
mutableGlobals: ptr::null(),
userdataTypes: ptr::null(),
librariesWithKnownMembers: ptr::null(),
libraryMemberTypeCallback: None,
libraryMemberConstantCallback: None,
disabledBuiltins: ptr::null(),
}
}
}
#[repr(C)]
pub struct lua_CompileConstant {
_data: [u8; 0],
_marker: PhantomData<(*mut u8, PhantomPinned)>,
}
/// Type table tags
#[doc(hidden)]
#[repr(i32)]
#[non_exhaustive]
pub enum luau_BytecodeType {
Nil = 0,
Boolean,
Number,
String,
Table,
Function,
Thread,
UserData,
Vector,
Buffer,
Any = 15,
}
pub type lua_LibraryMemberTypeCallback =
unsafe extern "C-unwind" fn(library: *const c_char, member: *const c_char) -> c_int;
pub type lua_LibraryMemberConstantCallback = unsafe extern "C-unwind" fn(
library: *const c_char,
member: *const c_char,
constant: *mut lua_CompileConstant,
);
extern "C" {
pub fn luau_set_compile_constant_nil(cons: *mut lua_CompileConstant);
pub fn luau_set_compile_constant_boolean(cons: *mut lua_CompileConstant, b: c_int);
pub fn luau_set_compile_constant_number(cons: *mut lua_CompileConstant, n: f64);
pub fn luau_set_compile_constant_vector(cons: *mut lua_CompileConstant, x: f32, y: f32, z: f32, w: f32);
pub fn luau_set_compile_constant_string(cons: *mut lua_CompileConstant, s: *const c_char, l: usize);
}
extern "C-unwind" {
#[link_name = "luau_compile"]
pub fn luau_compile_(
+4 -2
View File
@@ -27,7 +27,7 @@ use super::{Lua, WeakLua};
// Unique key to store `ExtraData` in the registry
static EXTRA_REGISTRY_KEY: u8 = 0;
const WRAPPED_FAILURE_POOL_SIZE: usize = 64;
const WRAPPED_FAILURE_POOL_DEFAULT_CAPACITY: usize = 64;
const REF_STACK_RESERVE: c_int = 1;
/// Data associated with the Lua state.
@@ -60,6 +60,7 @@ pub(crate) struct ExtraData {
// Pool of `WrappedFailure` enums in the ref thread (as userdata)
pub(super) wrapped_failure_pool: Vec<c_int>,
pub(super) wrapped_failure_top: usize,
// Pool of `Thread`s (coroutines) for async execution
#[cfg(feature = "async")]
pub(super) thread_pool: Vec<c_int>,
@@ -160,7 +161,8 @@ impl ExtraData {
ref_stack_size: ffi::LUA_MINSTACK - REF_STACK_RESERVE,
ref_stack_top: ffi::lua_gettop(ref_thread),
ref_free: Vec::new(),
wrapped_failure_pool: Vec::with_capacity(WRAPPED_FAILURE_POOL_SIZE),
wrapped_failure_pool: Vec::with_capacity(WRAPPED_FAILURE_POOL_DEFAULT_CAPACITY),
wrapped_failure_top: 0,
#[cfg(feature = "async")]
thread_pool: Vec::new(),
wrapped_failure_mt_ptr,
+23 -35
View File
@@ -7,8 +7,6 @@ use crate::error::{Error, Result};
use crate::state::{ExtraData, RawLua};
use crate::util::{self, get_internal_metatable, WrappedFailure};
const WRAPPED_FAILURE_POOL_SIZE: usize = 64;
pub(super) struct StateGuard<'a>(&'a RawLua, *mut ffi::lua_State);
impl<'a> StateGuard<'a> {
@@ -42,26 +40,27 @@ where
enum PreallocatedFailure {
New(*mut WrappedFailure),
Existing(i32),
Reserved,
}
impl PreallocatedFailure {
unsafe fn reserve(state: *mut ffi::lua_State, extra: *mut ExtraData) -> Self {
match (*extra).wrapped_failure_pool.pop() {
Some(index) => PreallocatedFailure::Existing(index),
None => {
// We need to check stack for Luau in case when callback is called from interrupt
// See https://github.com/Roblox/luau/issues/446 and mlua #142 and #153
#[cfg(feature = "luau")]
ffi::lua_rawcheckstack(state, 2);
// Place it to the beginning of the stack
let ud = WrappedFailure::new_userdata(state);
ffi::lua_insert(state, 1);
PreallocatedFailure::New(ud)
}
if (*extra).wrapped_failure_top > 0 {
(*extra).wrapped_failure_top -= 1;
return PreallocatedFailure::Reserved;
}
// We need to check stack for Luau in case when callback is called from interrupt
// See https://github.com/Roblox/luau/issues/446 and mlua #142 and #153
#[cfg(feature = "luau")]
ffi::lua_rawcheckstack(state, 2);
// Place it to the beginning of the stack
let ud = WrappedFailure::new_userdata(state);
ffi::lua_insert(state, 1);
PreallocatedFailure::New(ud)
}
#[cold]
unsafe fn r#use(&self, state: *mut ffi::lua_State, extra: *mut ExtraData) -> *mut WrappedFailure {
let ref_thread = (*extra).ref_thread;
match *self {
@@ -69,12 +68,12 @@ where
ffi::lua_settop(state, 1);
ud
}
PreallocatedFailure::Existing(index) => {
PreallocatedFailure::Reserved => {
let index = (*extra).wrapped_failure_pool.pop().unwrap();
ffi::lua_settop(state, 0);
#[cfg(feature = "luau")]
ffi::lua_rawcheckstack(state, 2);
ffi::lua_pushvalue(ref_thread, index);
ffi::lua_xmove(ref_thread, state, 1);
ffi::lua_xpush(ref_thread, state, index);
ffi::lua_pushnil(ref_thread);
ffi::lua_replace(ref_thread, index);
(*extra).ref_free.push(index);
@@ -87,24 +86,13 @@ where
let ref_thread = (*extra).ref_thread;
match self {
PreallocatedFailure::New(_) => {
if (*extra).wrapped_failure_pool.len() < WRAPPED_FAILURE_POOL_SIZE {
ffi::lua_rotate(state, 1, -1);
ffi::lua_xmove(state, ref_thread, 1);
let index = ref_stack_pop(extra);
(*extra).wrapped_failure_pool.push(index);
} else {
ffi::lua_remove(state, 1);
}
}
PreallocatedFailure::Existing(index) => {
if (*extra).wrapped_failure_pool.len() < WRAPPED_FAILURE_POOL_SIZE {
(*extra).wrapped_failure_pool.push(index);
} else {
ffi::lua_pushnil(ref_thread);
ffi::lua_replace(ref_thread, index);
(*extra).ref_free.push(index);
}
ffi::lua_rotate(state, 1, -1);
ffi::lua_xmove(state, ref_thread, 1);
let index = ref_stack_pop(extra);
(*extra).wrapped_failure_pool.push(index);
(*extra).wrapped_failure_top += 1;
}
PreallocatedFailure::Reserved => (*extra).wrapped_failure_top += 1,
}
}
}
+18
View File
@@ -581,6 +581,24 @@ impl Table {
unsafe { ffi::lua_getreadonly(ref_thread, self.0.index) != 0 }
}
/// Controls `safeenv` attribute on the table.
///
/// This a special flag that activates some performance optimizations for environment tables.
/// In particular, it controls:
/// - Optimization of import resolution (cache values of constant keys).
/// - Fast-path for built-in iteration with pairs/ipairs.
/// - Fast-path for some built-in functions (fastcall).
///
/// For `safeenv` environments, monkey patching or modifying values may not work as expected.
///
/// Requires `feature = "luau"`
#[cfg(any(feature = "luau", doc))]
#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
pub fn set_safeenv(&self, enabled: bool) {
let lua = self.0.lua.lock();
unsafe { ffi::lua_setsafeenv(lua.ref_thread(), self.0.index, enabled as _) };
}
/// Converts this table to a generic C pointer.
///
/// Different tables will give different pointers.
+1 -1
View File
@@ -4,7 +4,7 @@ use std::os::raw::{c_int, c_void};
use crate::state::{RawLua, WeakLua};
/// A reference to a Lua (complex) value stored in the Lua auxiliary thread.
pub(crate) struct ValueRef {
pub struct ValueRef {
pub(crate) lua: WeakLua,
pub(crate) index: c_int,
pub(crate) drop: bool,
+7 -2
View File
@@ -67,8 +67,7 @@ pub enum Value {
/// `Error` is a special builtin userdata type. When received from Lua it is implicitly cloned.
Error(Box<Error>),
/// Any other value not known to mlua (eg. LuaJIT CData).
#[allow(private_interfaces)]
Other(ValueRef),
Other(#[doc(hidden)] ValueRef),
}
pub use self::Value::Nil;
@@ -570,6 +569,12 @@ impl Value {
}
}
impl Default for Value {
fn default() -> Self {
Self::Nil
}
}
impl fmt::Debug for Value {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
if fmt.alternate() {
+14
View File
@@ -282,6 +282,20 @@ fn test_sandbox() -> Result<()> {
Ok(())
}
#[test]
fn test_sandbox_safeenv() -> Result<()> {
let lua = Lua::new();
lua.sandbox(true)?;
lua.globals().set("state", lua.create_table()?)?;
lua.globals().set_safeenv(false);
lua.load("state.a = 123").exec()?;
let a: i32 = lua.load("state.a = 321; return state.a").eval()?;
assert_eq!(a, 321);
Ok(())
}
#[test]
fn test_sandbox_nolibs() -> Result<()> {
let lua = Lua::new_with(StdLib::NONE, LuaOptions::default()).unwrap();
+22
View File
@@ -296,3 +296,25 @@ fn test_value_conversions() -> Result<()> {
Ok(())
}
#[test]
fn test_value_exhaustive_match() {
match Value::Nil {
Value::Nil => {}
Value::Boolean(_) => {}
Value::LightUserData(_) => {}
Value::Integer(_) => {}
Value::Number(_) => {}
#[cfg(feature = "luau")]
Value::Vector(_) => {}
Value::String(_) => {}
Value::Table(_) => {}
Value::Function(_) => {}
Value::Thread(_) => {}
Value::UserData(_) => {}
#[cfg(feature = "luau")]
Value::Buffer(_) => {}
Value::Error(_) => {}
Value::Other(_) => {}
}
}