Skip to content

Commit 8068172

Browse files
committed
Rename Lua::init_from_ptr to Lua::get_or_init_from_ptr.
Return reference to `&Lua` with unbound lifetime (chosen by user).
1 parent 95c623e commit 8068172

File tree

4 files changed

+48
-18
lines changed

4 files changed

+48
-18
lines changed

src/state.rs

+15-12
Original file line numberDiff line numberDiff line change
@@ -261,16 +261,23 @@ impl Lua {
261261
lua
262262
}
263263

264-
/// Constructs a new Lua instance from an existing raw state.
264+
/// Returns or constructs Lua instance from a raw state.
265265
///
266-
/// Once called, a returned Lua state is cached in the registry and can be retrieved
266+
/// Once initialized, the returned Lua instance is cached in the registry and can be retrieved
267267
/// by calling this function again.
268-
#[allow(clippy::missing_safety_doc)]
268+
///
269+
/// # Safety
270+
/// The `Lua` must outlive the chosen lifetime `'a`.
269271
#[inline]
270-
pub unsafe fn init_from_ptr(state: *mut ffi::lua_State) -> Lua {
271-
Lua {
272-
raw: RawLua::init_from_ptr(state, false),
273-
collect_garbage: true,
272+
pub unsafe fn get_or_init_from_ptr<'a>(state: *mut ffi::lua_State) -> &'a Lua {
273+
debug_assert!(!state.is_null(), "Lua state is null");
274+
match ExtraData::get(state) {
275+
extra if !extra.is_null() => (*extra).lua(),
276+
_ => {
277+
// The `owned` flag is set to `false` as we don't own the Lua state.
278+
RawLua::init_from_ptr(state, false);
279+
(*ExtraData::get(state)).lua()
280+
}
274281
}
275282
}
276283

@@ -410,11 +417,7 @@ impl Lua {
410417
R: IntoLua,
411418
{
412419
// Make sure that Lua is initialized
413-
let mut lua = Self::init_from_ptr(state);
414-
lua.collect_garbage = false;
415-
// `Lua` is no longer needed and must be dropped at this point to avoid memory leak
416-
// in case of possible longjmp (lua_error) below
417-
drop(lua);
420+
let _ = Self::get_or_init_from_ptr(state);
418421

419422
callback_error_ext(state, ptr::null_mut(), move |extra, nargs| {
420423
let rawlua = (*extra).raw_lua();

src/state/extra.rs

-3
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,6 @@ impl ExtraData {
195195
raw: XRc::clone(raw),
196196
collect_garbage: false,
197197
});
198-
if self.owned {
199-
XRc::decrement_strong_count(XRc::as_ptr(raw));
200-
}
201198
self.weak.write(WeakLua(XRc::downgrade(raw)));
202199
}
203200

src/state/raw.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,13 @@ pub struct RawLua {
5858
pub(super) state: Cell<*mut ffi::lua_State>,
5959
pub(super) main_state: Option<NonNull<ffi::lua_State>>,
6060
pub(super) extra: XRc<UnsafeCell<ExtraData>>,
61+
owned: bool,
6162
}
6263

6364
impl Drop for RawLua {
6465
fn drop(&mut self) {
6566
unsafe {
66-
if !(*self.extra.get()).owned {
67+
if !self.owned {
6768
return;
6869
}
6970

@@ -233,8 +234,17 @@ impl RawLua {
233234
// Make sure that we don't store current state as main state (if it's not available)
234235
main_state: get_main_state(state).and_then(NonNull::new),
235236
extra: XRc::clone(&extra),
237+
owned,
236238
}));
237239
(*extra.get()).set_lua(&rawlua);
240+
if owned {
241+
// If Lua state is managed by us, then make internal `RawLua` reference "weak"
242+
XRc::decrement_strong_count(XRc::as_ptr(&rawlua));
243+
} else {
244+
// If Lua state is not managed by us, then keep internal `RawLua` reference "strong"
245+
// but `Extra` reference weak (it will be collected from registry at lua_close time)
246+
XRc::decrement_strong_count(XRc::as_ptr(&extra));
247+
}
238248

239249
rawlua
240250
}

tests/tests.rs

+22-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ use std::sync::Arc;
88
use std::{error, f32, f64, fmt};
99

1010
use mlua::{
11-
ChunkMode, Error, ExternalError, Function, Lua, LuaOptions, Nil, Result, StdLib, String, Table, UserData,
12-
Value, Variadic,
11+
ffi, ChunkMode, Error, ExternalError, Function, Lua, LuaOptions, Nil, Result, StdLib, String, Table,
12+
UserData, Value, Variadic,
1313
};
1414

1515
#[cfg(not(feature = "luau"))]
@@ -1425,3 +1425,23 @@ fn test_gc_drop_ref_thread() -> Result<()> {
14251425

14261426
Ok(())
14271427
}
1428+
1429+
#[cfg(not(feature = "luau"))]
1430+
#[test]
1431+
fn test_get_or_init_from_ptr() -> Result<()> {
1432+
// This would not work with Luau, the state must be init by mlua internally
1433+
let state = unsafe { ffi::luaL_newstate() };
1434+
1435+
let mut lua = unsafe { Lua::get_or_init_from_ptr(state) };
1436+
lua.globals().set("hello", "world678")?;
1437+
1438+
// The same Lua instance must be returned
1439+
lua = unsafe { Lua::get_or_init_from_ptr(state) };
1440+
assert_eq!(lua.globals().get::<String>("hello")?, "world678");
1441+
1442+
unsafe { ffi::lua_close(state) };
1443+
1444+
// Lua must not be accessed after closing
1445+
1446+
Ok(())
1447+
}

0 commit comments

Comments
 (0)