mirror of
https://github.com/mlua-rs/mlua
synced 2026-06-08 16:05:43 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 93d63cef35 | |||
| b743245aba | |||
| a172c021c9 | |||
| de2c5cd9a9 | |||
| d201beadc9 | |||
| dd58cdad52 | |||
| 5c8a5e0a5a | |||
| e07c53eafe | |||
| ad619390e1 | |||
| 350602ab6e | |||
| 4b1bc88273 | |||
| 883bf082b9 | |||
| 4265250cfd |
@@ -65,8 +65,8 @@ jobs:
|
||||
cargo test --release --features "${{ matrix.lua }} vendored"
|
||||
cargo test --release --features "${{ matrix.lua }} vendored async send"
|
||||
shell: bash
|
||||
- name: Run compile tests
|
||||
if: ${{ matrix.os == 'ubuntu-18.04' && matrix.lua == 'lua53' }}
|
||||
- name: Run compile tests (macos lua53)
|
||||
if: ${{ matrix.os == 'macos-latest' && matrix.lua == 'lua53' }}
|
||||
run: |
|
||||
cargo test --release --features "${{ matrix.lua }} vendored" -- --ignored
|
||||
cargo test --release --features "${{ matrix.lua }} vendored async send" -- --ignored
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
## v0.4.2
|
||||
|
||||
- Added `Function::dump()` to dump lua function to a binary chunk
|
||||
- Added `ChunkMode` enum to mark chunks as text or binary
|
||||
- Updated `set_memory_limit` doc
|
||||
|
||||
## v0.4.0
|
||||
|
||||
- Lua 5.4 support with `MetaMethod::Close`.
|
||||
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mlua"
|
||||
version = "0.4.0"
|
||||
version = "0.4.2"
|
||||
authors = ["Aleksandr Orlenko <zxteam@pm.me>", "kyren <catherine@chucklefish.org>"]
|
||||
edition = "2018"
|
||||
repository = "https://github.com/khvzak/mlua"
|
||||
@@ -12,7 +12,7 @@ license = "MIT"
|
||||
links = "lua"
|
||||
build = "build/main.rs"
|
||||
description = """
|
||||
High level bindings to Lua 5.1/5.2/5.3/5.4 (including LuaJIT)
|
||||
High level bindings to Lua 5.4/5.3/5.2/5.1 (including LuaJIT)
|
||||
with async/await features and support of writing native lua modules in Rust.
|
||||
"""
|
||||
|
||||
@@ -21,7 +21,7 @@ with async/await features and support of writing native lua modules in Rust.
|
||||
maintenance = { status = "actively-developed" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["async"]
|
||||
features = ["async", "send", "lua53"]
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
@@ -52,7 +52,7 @@ futures-util = { version = "0.3.5", optional = true }
|
||||
[build-dependencies]
|
||||
cc = { version = "1.0" }
|
||||
pkg-config = { version = "0.3.17" }
|
||||
lua-src = { version = "535.0.4", optional = true }
|
||||
lua-src = { version = "540.0.0", optional = true }
|
||||
luajit-src = { version = "210.1.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -38,7 +38,10 @@ pub use super::glue::LUA_REGISTRYINDEX;
|
||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||
pub use super::glue::{LUA_ENVIRONINDEX, LUA_GLOBALSINDEX};
|
||||
|
||||
#[cfg(not(feature = "luajit"))]
|
||||
pub const LUA_SIGNATURE: &[u8] = b"\x1bLua";
|
||||
#[cfg(feature = "luajit")]
|
||||
pub const LUA_SIGNATURE: &[u8] = b"\x1bLJ";
|
||||
|
||||
// option for multiple returns in 'lua_pcall' and 'lua_call'
|
||||
pub const LUA_MULTRET: c_int = -1;
|
||||
|
||||
+2
-2
@@ -211,8 +211,8 @@ pub use self::lua::{
|
||||
LUA_HOOKCOUNT, LUA_HOOKLINE, LUA_HOOKRET, LUA_HOOKTAILCALL, LUA_MASKCALL, LUA_MASKCOUNT,
|
||||
LUA_MASKLINE, LUA_MASKRET, LUA_MINSTACK, LUA_MULTRET, LUA_OK, LUA_OPADD, LUA_OPDIV, LUA_OPEQ,
|
||||
LUA_OPLE, LUA_OPLT, LUA_OPMOD, LUA_OPMUL, LUA_OPPOW, LUA_OPSUB, LUA_OPUNM, LUA_REGISTRYINDEX,
|
||||
LUA_TBOOLEAN, LUA_TFUNCTION, LUA_TLIGHTUSERDATA, LUA_TNIL, LUA_TNONE, LUA_TNUMBER, LUA_TSTRING,
|
||||
LUA_TTABLE, LUA_TTHREAD, LUA_TUSERDATA, LUA_YIELD,
|
||||
LUA_SIGNATURE, LUA_TBOOLEAN, LUA_TFUNCTION, LUA_TLIGHTUSERDATA, LUA_TNIL, LUA_TNONE,
|
||||
LUA_TNUMBER, LUA_TSTRING, LUA_TTABLE, LUA_TTHREAD, LUA_TUSERDATA, LUA_YIELD,
|
||||
};
|
||||
|
||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
||||
|
||||
+38
-2
@@ -1,5 +1,5 @@
|
||||
use std::os::raw::c_int;
|
||||
use std::ptr;
|
||||
use std::os::raw::{c_int, c_void};
|
||||
use std::{ptr, slice};
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::ffi;
|
||||
@@ -205,6 +205,42 @@ impl<'lua> Function<'lua> {
|
||||
Ok(Function(lua.pop_ref()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Dumps the function as a binary chunk.
|
||||
///
|
||||
/// If `strip` is true, the binary representation may not include all debug information
|
||||
/// about the function, to save space.
|
||||
pub fn dump(&self, strip: bool) -> Result<Vec<u8>> {
|
||||
unsafe extern "C" fn writer(
|
||||
_state: *mut ffi::lua_State,
|
||||
buf: *const c_void,
|
||||
buf_len: usize,
|
||||
data: *mut c_void,
|
||||
) -> c_int {
|
||||
let data = &mut *(data as *mut Vec<u8>);
|
||||
let buf = slice::from_raw_parts(buf as *const u8, buf_len);
|
||||
data.extend_from_slice(buf);
|
||||
0
|
||||
}
|
||||
|
||||
let lua = self.0.lua;
|
||||
let mut data: Vec<u8> = Vec::new();
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(lua.state);
|
||||
assert_stack(lua.state, 1);
|
||||
lua.push_ref(&self.0);
|
||||
let strip = if strip { 1 } else { 0 };
|
||||
ffi::lua_dump(
|
||||
lua.state,
|
||||
writer,
|
||||
&mut data as *mut Vec<u8> as *mut c_void,
|
||||
strip,
|
||||
);
|
||||
ffi::lua_pop(lua.state, 1);
|
||||
}
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> PartialEq for Function<'lua> {
|
||||
|
||||
+1
-1
@@ -81,7 +81,7 @@ pub use crate::ffi::lua_State;
|
||||
pub use crate::error::{Error, ExternalError, ExternalResult, Result};
|
||||
pub use crate::function::Function;
|
||||
pub use crate::hook::{Debug, DebugNames, DebugSource, DebugStack, HookTriggers};
|
||||
pub use crate::lua::{Chunk, GCMode, Lua};
|
||||
pub use crate::lua::{Chunk, ChunkMode, GCMode, Lua};
|
||||
pub use crate::multi::Variadic;
|
||||
pub use crate::scope::Scope;
|
||||
pub use crate::stdlib::StdLib;
|
||||
|
||||
+68
-30
@@ -100,13 +100,15 @@ impl Drop for Lua {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if !self.ephemeral {
|
||||
let mut extra = mlua_expect!(self.extra.lock(), "extra is poisoned");
|
||||
let extra = mlua_expect!(self.extra.lock(), "extra is poisoned");
|
||||
mlua_debug_assert!(
|
||||
ffi::lua_gettop(extra.ref_thread) == extra.ref_stack_max
|
||||
&& extra.ref_stack_max as usize == extra.ref_free.len(),
|
||||
"reference leak detected"
|
||||
);
|
||||
*mlua_expect!(extra.registry_unref_list.lock(), "unref list poisoned") = None;
|
||||
let mut unref_list =
|
||||
mlua_expect!(extra.registry_unref_list.lock(), "unref list poisoned");
|
||||
*unref_list = None;
|
||||
ffi::lua_close(self.main_state.expect("main_state is null"));
|
||||
if !extra.mem_info.is_null() {
|
||||
Box::from_raw(extra.mem_info);
|
||||
@@ -490,7 +492,7 @@ impl Lua {
|
||||
unsafe { (*extra.mem_info).used_memory as usize }
|
||||
}
|
||||
|
||||
/// Sets a memory limit on this Lua state.
|
||||
/// Sets a memory limit (in bytes) on this Lua state.
|
||||
///
|
||||
/// Once an allocation occurs that would pass this memory limit,
|
||||
/// a `Error::MemoryError` is generated instead.
|
||||
@@ -658,6 +660,9 @@ impl Lua {
|
||||
/// similar on the returned builder. Code is not even parsed until one of these methods is
|
||||
/// called.
|
||||
///
|
||||
/// If this `Lua` was created with `unsafe_new`, `load` will automatically detect and load
|
||||
/// chunks of either text or binary type, as if passing `bt` mode to `luaL_loadbufferx`.
|
||||
///
|
||||
/// [`Chunk::exec`]: struct.Chunk.html#method.exec
|
||||
pub fn load<'lua, 'a, S>(&'lua self, source: &'a S) -> Chunk<'lua, 'a>
|
||||
where
|
||||
@@ -668,6 +673,7 @@ impl Lua {
|
||||
source: source.as_ref(),
|
||||
name: None,
|
||||
env: None,
|
||||
mode: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -676,28 +682,35 @@ impl Lua {
|
||||
source: &[u8],
|
||||
name: Option<&CString>,
|
||||
env: Option<Value<'lua>>,
|
||||
mode: Option<ChunkMode>,
|
||||
) -> Result<Function<'lua>> {
|
||||
unsafe {
|
||||
let _sg = StackGuard::new(self.state);
|
||||
assert_stack(self.state, 1);
|
||||
|
||||
match if let Some(name) = name {
|
||||
ffi::luaL_loadbufferx(
|
||||
self.state,
|
||||
source.as_ptr() as *const c_char,
|
||||
source.len(),
|
||||
name.as_ptr() as *const c_char,
|
||||
cstr!("t"),
|
||||
)
|
||||
} else {
|
||||
ffi::luaL_loadbufferx(
|
||||
self.state,
|
||||
source.as_ptr() as *const c_char,
|
||||
source.len(),
|
||||
ptr::null(),
|
||||
cstr!("t"),
|
||||
)
|
||||
} {
|
||||
let mode_str = match mode {
|
||||
Some(ChunkMode::Binary) if self.safe => {
|
||||
return Err(Error::SafetyError(
|
||||
"binary chunks are disabled in safe mode".to_string(),
|
||||
))
|
||||
}
|
||||
Some(ChunkMode::Binary) => cstr!("b"),
|
||||
Some(ChunkMode::Text) => cstr!("t"),
|
||||
None if source.starts_with(ffi::LUA_SIGNATURE) && self.safe => {
|
||||
return Err(Error::SafetyError(
|
||||
"binary chunks are disabled in safe mode".to_string(),
|
||||
))
|
||||
}
|
||||
None => cstr!("bt"),
|
||||
};
|
||||
|
||||
match ffi::luaL_loadbufferx(
|
||||
self.state,
|
||||
source.as_ptr() as *const c_char,
|
||||
source.len(),
|
||||
name.map(|n| n.as_ptr()).unwrap_or_else(ptr::null),
|
||||
mode_str,
|
||||
) {
|
||||
ffi::LUA_OK => {
|
||||
if let Some(env) = env {
|
||||
self.push_value(env)?;
|
||||
@@ -903,7 +916,7 @@ impl Lua {
|
||||
/// ```
|
||||
///
|
||||
/// [`Thread`]: struct.Thread.html
|
||||
/// [`ThreadStream`]: struct.ThreadStream.html
|
||||
/// [`AsyncThread`]: struct.AsyncThread.html
|
||||
#[cfg(feature = "async")]
|
||||
pub fn create_async_function<'lua, 'callback, A, R, F, FR>(
|
||||
&'lua self,
|
||||
@@ -1274,11 +1287,10 @@ impl Lua {
|
||||
/// by `Lua::remove_registry_value`.
|
||||
pub fn expire_registry_values(&self) {
|
||||
unsafe {
|
||||
let mut extra = mlua_expect!(self.extra.lock(), "extra is poisoned");
|
||||
let unref_list = mem::replace(
|
||||
&mut *mlua_expect!(extra.registry_unref_list.lock(), "unref list poisoned"),
|
||||
Some(Vec::new()),
|
||||
);
|
||||
let extra = mlua_expect!(self.extra.lock(), "extra is poisoned");
|
||||
let mut unref_list =
|
||||
mlua_expect!(extra.registry_unref_list.lock(), "unref list poisoned");
|
||||
let unref_list = mem::replace(&mut *unref_list, Some(Vec::new()));
|
||||
for id in mlua_expect!(unref_list, "unref list not set") {
|
||||
ffi::luaL_unref(self.state, ffi::LUA_REGISTRYINDEX, id);
|
||||
}
|
||||
@@ -1802,6 +1814,14 @@ pub struct Chunk<'lua, 'a> {
|
||||
source: &'a [u8],
|
||||
name: Option<CString>,
|
||||
env: Option<Value<'lua>>,
|
||||
mode: Option<ChunkMode>,
|
||||
}
|
||||
|
||||
/// Represents chunk mode (text or binary).
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ChunkMode {
|
||||
Text,
|
||||
Binary,
|
||||
}
|
||||
|
||||
impl<'lua, 'a> Chunk<'lua, 'a> {
|
||||
@@ -1833,6 +1853,17 @@ impl<'lua, 'a> Chunk<'lua, 'a> {
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Sets whether the chunk is text or binary (autodetected by default).
|
||||
///
|
||||
/// Lua does not check the consistency of binary chunks, therefore this mode is allowed only
|
||||
/// for instances created with [`Lua::unsafe_new`].
|
||||
///
|
||||
/// [`Lua::unsafe_new`]: struct.Lua.html#method.unsafe_new
|
||||
pub fn set_mode(mut self, mode: ChunkMode) -> Chunk<'lua, 'a> {
|
||||
self.mode = Some(mode);
|
||||
self
|
||||
}
|
||||
|
||||
/// Execute this chunk of code.
|
||||
///
|
||||
/// This is equivalent to calling the chunk function with no arguments and no return values.
|
||||
@@ -1862,13 +1893,17 @@ impl<'lua, 'a> Chunk<'lua, 'a> {
|
||||
/// the value that it evaluates to. Otherwise, the chunk is interpreted as a block as normal,
|
||||
/// and this is equivalent to calling `exec`.
|
||||
pub fn eval<R: FromLuaMulti<'lua>>(self) -> Result<R> {
|
||||
// First, try interpreting the lua as an expression by adding
|
||||
// Bytecode is always interpreted as a statement.
|
||||
// For source code, first try interpreting the lua as an expression by adding
|
||||
// "return", then as a statement. This is the same thing the
|
||||
// actual lua repl does.
|
||||
if let Ok(function) = self.lua.load_chunk(
|
||||
if self.source.starts_with(ffi::LUA_SIGNATURE) {
|
||||
self.call(())
|
||||
} else if let Ok(function) = self.lua.load_chunk(
|
||||
&self.expression_source(),
|
||||
self.name.as_ref(),
|
||||
self.env.clone(),
|
||||
self.mode,
|
||||
) {
|
||||
function.call(())
|
||||
} else {
|
||||
@@ -1889,10 +1924,13 @@ impl<'lua, 'a> Chunk<'lua, 'a> {
|
||||
'lua: 'fut,
|
||||
R: FromLuaMulti<'lua> + 'fut,
|
||||
{
|
||||
if let Ok(function) = self.lua.load_chunk(
|
||||
if self.source.starts_with(ffi::LUA_SIGNATURE) {
|
||||
self.call_async(())
|
||||
} else if let Ok(function) = self.lua.load_chunk(
|
||||
&self.expression_source(),
|
||||
self.name.as_ref(),
|
||||
self.env.clone(),
|
||||
self.mode,
|
||||
) {
|
||||
function.call_async(())
|
||||
} else {
|
||||
@@ -1932,7 +1970,7 @@ impl<'lua, 'a> Chunk<'lua, 'a> {
|
||||
/// This simply compiles the chunk without actually executing it.
|
||||
pub fn into_function(self) -> Result<Function<'lua>> {
|
||||
self.lua
|
||||
.load_chunk(self.source, self.name.as_ref(), self.env)
|
||||
.load_chunk(self.source, self.name.as_ref(), self.env, self.mode)
|
||||
}
|
||||
|
||||
fn expression_source(&self) -> Vec<u8> {
|
||||
|
||||
@@ -22,8 +22,8 @@ note: ...so that the types are compatible
|
||||
13 | | Ok(())
|
||||
14 | | });
|
||||
| |_____________^
|
||||
= note: expected `main::MyUserData<'_>`
|
||||
found `main::MyUserData<'a>`
|
||||
= note: expected `main::MyUserData<'_>`
|
||||
found `main::MyUserData<'a>`
|
||||
note: but, the lifetime must be valid for the lifetime `'lua` as defined on the method body at 10:24...
|
||||
--> $DIR/async_nonstatic_userdata.rs:10:24
|
||||
|
|
||||
|
||||
@@ -1,45 +1,26 @@
|
||||
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
|
||||
--> $DIR/scope_callback_capture.rs:8:14
|
||||
|
|
||||
8 | .create_function_mut(move |_, t: Table| {
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 5:15...
|
||||
--> $DIR/scope_callback_capture.rs:5:15
|
||||
|
|
||||
5 | lua.scope(|scope| {
|
||||
| _______________^
|
||||
6 | | let mut inner: Option<Table> = None;
|
||||
7 | | let f = scope
|
||||
8 | | .create_function_mut(move |_, t: Table| {
|
||||
... |
|
||||
16 | | Ok(())
|
||||
17 | | });
|
||||
| |_____^
|
||||
note: ...so that reference does not outlive borrowed content
|
||||
warning: unused variable: `old`
|
||||
--> $DIR/scope_callback_capture.rs:9:29
|
||||
|
|
||||
9 | if let Some(old) = inner.take() {
|
||||
| ^^^ help: if this is intentional, prefix it with an underscore: `_old`
|
||||
|
|
||||
= note: `#[warn(unused_variables)]` on by default
|
||||
|
||||
error[E0521]: borrowed data escapes outside of closure
|
||||
--> $DIR/scope_callback_capture.rs:7:17
|
||||
|
|
||||
7 | let f = scope
|
||||
| ^^^^^
|
||||
note: but, the lifetime must be valid for the method call at 5:5...
|
||||
--> $DIR/scope_callback_capture.rs:5:5
|
||||
|
|
||||
5 | / lua.scope(|scope| {
|
||||
6 | | let mut inner: Option<Table> = None;
|
||||
7 | | let f = scope
|
||||
5 | lua.scope(|scope| {
|
||||
| -----
|
||||
| |
|
||||
| `scope` declared here, outside of the closure body
|
||||
| `scope` is a reference that is only valid in the closure body
|
||||
6 | let mut inner: Option<Table> = None;
|
||||
7 | let f = scope
|
||||
| _________________^
|
||||
8 | | .create_function_mut(move |_, t: Table| {
|
||||
9 | | if let Some(old) = inner.take() {
|
||||
10 | | // Access old callback `Lua`.
|
||||
... |
|
||||
16 | | Ok(())
|
||||
17 | | });
|
||||
| |______^
|
||||
note: ...so that a type/lifetime parameter is in scope here
|
||||
--> $DIR/scope_callback_capture.rs:5:5
|
||||
|
|
||||
5 | / lua.scope(|scope| {
|
||||
6 | | let mut inner: Option<Table> = None;
|
||||
7 | | let f = scope
|
||||
8 | | .create_function_mut(move |_, t: Table| {
|
||||
... |
|
||||
16 | | Ok(())
|
||||
17 | | });
|
||||
| |______^
|
||||
13 | | Ok(())
|
||||
14 | | })?;
|
||||
| |______________^ `scope` escapes the closure body here
|
||||
|
||||
@@ -1,45 +1,42 @@
|
||||
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
|
||||
--> $DIR/scope_callback_inner.rs:8:14
|
||||
|
|
||||
8 | .create_function_mut(|_, t: Table| {
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 5:15...
|
||||
--> $DIR/scope_callback_inner.rs:5:15
|
||||
|
|
||||
5 | lua.scope(|scope| {
|
||||
| _______________^
|
||||
6 | | let mut inner: Option<Table> = None;
|
||||
7 | | let f = scope
|
||||
8 | | .create_function_mut(|_, t: Table| {
|
||||
... |
|
||||
13 | | Ok(())
|
||||
14 | | });
|
||||
| |_____^
|
||||
note: ...so that reference does not outlive borrowed content
|
||||
error[E0521]: borrowed data escapes outside of closure
|
||||
--> $DIR/scope_callback_inner.rs:7:17
|
||||
|
|
||||
7 | let f = scope
|
||||
| ^^^^^
|
||||
note: but, the lifetime must be valid for the method call at 5:5...
|
||||
--> $DIR/scope_callback_inner.rs:5:5
|
||||
|
|
||||
5 | / lua.scope(|scope| {
|
||||
6 | | let mut inner: Option<Table> = None;
|
||||
7 | | let f = scope
|
||||
5 | lua.scope(|scope| {
|
||||
| -----
|
||||
| |
|
||||
| `scope` declared here, outside of the closure body
|
||||
| `scope` is a reference that is only valid in the closure body
|
||||
6 | let mut inner: Option<Table> = None;
|
||||
7 | let f = scope
|
||||
| _________________^
|
||||
8 | | .create_function_mut(|_, t: Table| {
|
||||
... |
|
||||
13 | | Ok(())
|
||||
14 | | });
|
||||
| |______^
|
||||
note: ...so that a type/lifetime parameter is in scope here
|
||||
--> $DIR/scope_callback_inner.rs:5:5
|
||||
9 | | inner = Some(t);
|
||||
10 | | Ok(())
|
||||
11 | | })?;
|
||||
| |______________^ `scope` escapes the closure body here
|
||||
|
||||
error[E0373]: closure may outlive the current function, but it borrows `inner`, which is owned by the current function
|
||||
--> $DIR/scope_callback_inner.rs:8:34
|
||||
|
|
||||
5 | / lua.scope(|scope| {
|
||||
6 | | let mut inner: Option<Table> = None;
|
||||
7 | | let f = scope
|
||||
5 | lua.scope(|scope| {
|
||||
| ----- has type `&mlua::scope::Scope<'_, '2>`
|
||||
...
|
||||
8 | .create_function_mut(|_, t: Table| {
|
||||
| ^^^^^^^^^^^^^ may outlive borrowed value `inner`
|
||||
9 | inner = Some(t);
|
||||
| ----- `inner` is borrowed here
|
||||
|
|
||||
note: function requires argument type to outlive `'2`
|
||||
--> $DIR/scope_callback_inner.rs:7:17
|
||||
|
|
||||
7 | let f = scope
|
||||
| _________________^
|
||||
8 | | .create_function_mut(|_, t: Table| {
|
||||
... |
|
||||
13 | | Ok(())
|
||||
14 | | });
|
||||
| |______^
|
||||
9 | | inner = Some(t);
|
||||
10 | | Ok(())
|
||||
11 | | })?;
|
||||
| |______________^
|
||||
help: to force the closure to take ownership of `inner` (and any other referenced variables), use the `move` keyword
|
||||
|
|
||||
8 | .create_function_mut(move |_, t: Table| {
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -1,11 +1,30 @@
|
||||
error: borrowed data cannot be stored outside of its closure
|
||||
--> $DIR/scope_callback_outer.rs:7:17
|
||||
|
|
||||
5 | let mut outer: Option<Table> = None;
|
||||
| --------- ...so that variable is valid at time of its declaration
|
||||
6 | lua.scope(|scope| {
|
||||
| ------- borrowed data cannot outlive this closure
|
||||
7 | let f = scope
|
||||
| ^^^^^ cannot be stored outside of its closure
|
||||
8 | .create_function_mut(|_, t: Table| {
|
||||
| ------------------- cannot infer an appropriate lifetime...
|
||||
error[E0521]: borrowed data escapes outside of closure
|
||||
--> $DIR/scope_callback_outer.rs:7:17
|
||||
|
|
||||
6 | lua.scope(|scope| {
|
||||
| -----
|
||||
| |
|
||||
| `scope` declared here, outside of the closure body
|
||||
| `scope` is a reference that is only valid in the closure body
|
||||
7 | let f = scope
|
||||
| _________________^
|
||||
8 | | .create_function_mut(|_, t: Table| {
|
||||
9 | | outer = Some(t);
|
||||
10 | | Ok(())
|
||||
11 | | })?;
|
||||
| |______________^ `scope` escapes the closure body here
|
||||
|
||||
error[E0597]: `outer` does not live long enough
|
||||
--> $DIR/scope_callback_outer.rs:9:17
|
||||
|
|
||||
6 | lua.scope(|scope| {
|
||||
| ------- value captured here
|
||||
...
|
||||
9 | outer = Some(t);
|
||||
| ^^^^^ borrowed value does not live long enough
|
||||
...
|
||||
15 | }
|
||||
| -
|
||||
| |
|
||||
| `outer` dropped here while still borrowed
|
||||
| borrow might be used here, when `outer` is dropped and runs the destructor for type `std::option::Option<mlua::table::Table<'_>>`
|
||||
|
||||
@@ -87,3 +87,17 @@ fn test_rust_function() -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dump() -> Result<()> {
|
||||
let lua = unsafe { Lua::unsafe_new() };
|
||||
|
||||
let concat_lua = lua
|
||||
.load(r#"function(arg1, arg2) return arg1 .. arg2 end"#)
|
||||
.eval::<Function>()?;
|
||||
let concat = lua.load(&concat_lua.dump(false)?).into_function()?;
|
||||
|
||||
assert_eq!(concat.call::<_, String>(("foo", "bar"))?, "foobar");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+54
-2
@@ -16,8 +16,8 @@ use std::sync::Arc;
|
||||
use std::{error, f32, f64, fmt};
|
||||
|
||||
use mlua::{
|
||||
Error, ExternalError, Function, Lua, Nil, Result, StdLib, String, Table, UserData, Value,
|
||||
Variadic,
|
||||
ChunkMode, Error, ExternalError, Function, Lua, Nil, Result, StdLib, String, Table, UserData,
|
||||
Value, Variadic,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -56,6 +56,23 @@ fn test_safety() -> Result<()> {
|
||||
Ok(_) => panic!("expected RuntimeError, got no error"),
|
||||
}
|
||||
|
||||
match lua.load("1 + 1").set_mode(ChunkMode::Binary).exec() {
|
||||
Err(Error::SafetyError(msg)) => {
|
||||
assert!(msg.contains("binary chunks are disabled in safe mode"))
|
||||
}
|
||||
Err(e) => panic!("expected SafetyError, got {:?}", e),
|
||||
Ok(_) => panic!("expected SafetyError, got no error"),
|
||||
}
|
||||
|
||||
let bytecode = lua.load("return 1 + 1").into_function()?.dump(true)?;
|
||||
match lua.load(&bytecode).exec() {
|
||||
Err(Error::SafetyError(msg)) => {
|
||||
assert!(msg.contains("binary chunks are disabled in safe mode"))
|
||||
}
|
||||
Err(e) => panic!("expected SafetyError, got {:?}", e),
|
||||
Ok(_) => panic!("expected SafetyError, got no error"),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -127,6 +144,41 @@ fn test_eval() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_load_mode() -> Result<()> {
|
||||
let lua = unsafe { Lua::unsafe_new() };
|
||||
|
||||
assert_eq!(
|
||||
lua.load("1 + 1").set_mode(ChunkMode::Text).eval::<i32>()?,
|
||||
2
|
||||
);
|
||||
match lua.load("1 + 1").set_mode(ChunkMode::Binary).exec() {
|
||||
Ok(_) => panic!("expected SyntaxError, got no error"),
|
||||
Err(Error::SyntaxError { message: msg, .. }) => {
|
||||
assert!(msg.contains("attempt to load a text chunk"))
|
||||
}
|
||||
Err(e) => panic!("expected SyntaxError, got {:?}", e),
|
||||
};
|
||||
|
||||
let bytecode = lua.load("return 1 + 1").into_function()?.dump(true)?;
|
||||
assert_eq!(lua.load(&bytecode).eval::<i32>()?, 2);
|
||||
assert_eq!(
|
||||
lua.load(&bytecode)
|
||||
.set_mode(ChunkMode::Binary)
|
||||
.eval::<i32>()?,
|
||||
2
|
||||
);
|
||||
match lua.load(&bytecode).set_mode(ChunkMode::Text).exec() {
|
||||
Ok(_) => panic!("expected SyntaxError, got no error"),
|
||||
Err(Error::SyntaxError { message: msg, .. }) => {
|
||||
assert!(msg.contains("attempt to load a binary chunk"))
|
||||
}
|
||||
Err(e) => panic!("expected SyntaxError, got {:?}", e),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lua_multi() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
Reference in New Issue
Block a user