mirror of
https://github.com/mlua-rs/mlua
synced 2026-06-08 16:05:43 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9caf3542d9 | |||
| cb45db05fa | |||
| d1cb2a9a96 | |||
| aa3f6ba46c | |||
| cc57bed4c8 | |||
| b5d38ab2e3 | |||
| cd4091f64d | |||
| 91e069a77e | |||
| cacd3dc70f |
@@ -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
@@ -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"
|
||||
|
||||
@@ -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
@@ -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)'] }
|
||||
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user