diff --git a/examples/async_http_server.rs b/examples/async_http_server.rs
index 43ae7a9..337eebb 100644
--- a/examples/async_http_server.rs
+++ b/examples/async_http_server.rs
@@ -1,7 +1,6 @@
use std::future::Future;
use std::net::SocketAddr;
use std::pin::Pin;
-use std::rc::Rc;
use std::task::{Context, Poll};
use hyper::server::conn::AddrStream;
@@ -9,7 +8,8 @@ use hyper::service::Service;
use hyper::{Body, Request, Response, Server};
use mlua::{
- chunk, Error as LuaError, Function, Lua, String as LuaString, Table, UserData, UserDataMethods,
+ chunk, Error as LuaError, Function, Lua, OwnedFunction, String as LuaString, Table, UserData,
+ UserDataMethods,
};
struct LuaRequest(SocketAddr, Request
);
@@ -21,7 +21,10 @@ impl UserData for LuaRequest {
}
}
-pub struct Svc(Rc, SocketAddr);
+#[derive(Clone)]
+struct Handler(OwnedFunction);
+
+pub struct Svc(Handler, SocketAddr);
impl Service> for Svc {
type Response = Response;
@@ -34,11 +37,10 @@ impl Service> for Svc {
fn call(&mut self, req: Request) -> Self::Future {
// If handler returns an error then generate 5xx response
- let lua = self.0.clone();
+ let handler = self.0.clone();
let lua_req = LuaRequest(self.1, req);
Box::pin(async move {
- let handler: Function = lua.named_registry_value("http_handler")?;
- match handler.call_async::<_, Table>(lua_req).await {
+ match handler.0.to_ref().call_async::<_, Table>(lua_req).await {
Ok(lua_resp) => {
let status = lua_resp.get::<_, Option>("status")?.unwrap_or(200);
let mut resp = Response::builder().status(status);
@@ -72,10 +74,10 @@ impl Service> for Svc {
#[tokio::main(flavor = "current_thread")]
async fn main() {
- let lua = Rc::new(Lua::new());
+ let lua = Lua::new();
// Create Lua handler function
- let handler: Function = lua
+ let handler_fn: Function = lua
.load(chunk! {
function(req)
return {
@@ -91,12 +93,10 @@ async fn main() {
.eval()
.expect("cannot create Lua handler");
- // Store it in the Registry
- lua.set_named_registry_value("http_handler", handler)
- .expect("cannot store Lua handler");
-
let addr = ([127, 0, 0, 1], 3000).into();
- let server = Server::bind(&addr).executor(LocalExec).serve(MakeSvc(lua));
+ let server = Server::bind(&addr)
+ .executor(LocalExec)
+ .serve(MakeSvc(Handler(handler_fn.into_owned())));
println!("Listening on http://{}", addr);
@@ -105,7 +105,7 @@ async fn main() {
local.run_until(server).await.expect("cannot run server")
}
-struct MakeSvc(Rc);
+struct MakeSvc(Handler);
impl Service<&AddrStream> for MakeSvc {
type Response = Svc;
@@ -117,9 +117,9 @@ impl Service<&AddrStream> for MakeSvc {
}
fn call(&mut self, stream: &AddrStream) -> Self::Future {
- let lua = self.0.clone();
+ let handler = self.0.clone();
let remote_addr = stream.remote_addr();
- Box::pin(async move { Ok(Svc(lua, remote_addr)) })
+ Box::pin(async move { Ok(Svc(handler, remote_addr)) })
}
}
diff --git a/src/conversion.rs b/src/conversion.rs
index 59717f0..5e89649 100644
--- a/src/conversion.rs
+++ b/src/conversion.rs
@@ -11,13 +11,13 @@ use bstr::{BStr, BString};
use num_traits::cast;
use crate::error::{Error, Result};
-use crate::function::Function;
+use crate::function::{Function, OwnedFunction};
use crate::lua::Lua;
-use crate::string::String;
-use crate::table::Table;
-use crate::thread::Thread;
+use crate::string::{OwnedString, String};
+use crate::table::{OwnedTable, Table};
+use crate::thread::{OwnedThread, Thread};
use crate::types::{LightUserData, MaybeSend};
-use crate::userdata::{AnyUserData, UserData};
+use crate::userdata::{AnyUserData, OwnedAnyUserData, UserData};
use crate::value::{FromLua, Nil, ToLua, Value};
impl<'lua> ToLua<'lua> for Value<'lua> {
@@ -54,6 +54,20 @@ impl<'lua> FromLua<'lua> for String<'lua> {
}
}
+impl<'lua> ToLua<'lua> for OwnedString {
+ #[inline]
+ fn to_lua(self, lua: &'lua Lua) -> Result> {
+ Ok(Value::String(String(lua.adopt_owned_ref(self.0))))
+ }
+}
+
+impl<'lua> FromLua<'lua> for OwnedString {
+ #[inline]
+ fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result {
+ String::from_lua(value, lua).map(|s| s.into_owned())
+ }
+}
+
impl<'lua> ToLua<'lua> for Table<'lua> {
#[inline]
fn to_lua(self, _: &'lua Lua) -> Result> {
@@ -75,6 +89,20 @@ impl<'lua> FromLua<'lua> for Table<'lua> {
}
}
+impl<'lua> ToLua<'lua> for OwnedTable {
+ #[inline]
+ fn to_lua(self, lua: &'lua Lua) -> Result> {
+ Ok(Value::Table(Table(lua.adopt_owned_ref(self.0))))
+ }
+}
+
+impl<'lua> FromLua<'lua> for OwnedTable {
+ #[inline]
+ fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result {
+ Table::from_lua(value, lua).map(|s| s.into_owned())
+ }
+}
+
impl<'lua> ToLua<'lua> for Function<'lua> {
#[inline]
fn to_lua(self, _: &'lua Lua) -> Result> {
@@ -96,6 +124,20 @@ impl<'lua> FromLua<'lua> for Function<'lua> {
}
}
+impl<'lua> ToLua<'lua> for OwnedFunction {
+ #[inline]
+ fn to_lua(self, lua: &'lua Lua) -> Result> {
+ Ok(Value::Function(Function(lua.adopt_owned_ref(self.0))))
+ }
+}
+
+impl<'lua> FromLua<'lua> for OwnedFunction {
+ #[inline]
+ fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result {
+ Function::from_lua(value, lua).map(|s| s.into_owned())
+ }
+}
+
impl<'lua> ToLua<'lua> for Thread<'lua> {
#[inline]
fn to_lua(self, _: &'lua Lua) -> Result> {
@@ -117,6 +159,20 @@ impl<'lua> FromLua<'lua> for Thread<'lua> {
}
}
+impl<'lua> ToLua<'lua> for OwnedThread {
+ #[inline]
+ fn to_lua(self, lua: &'lua Lua) -> Result> {
+ Ok(Value::Thread(Thread(lua.adopt_owned_ref(self.0))))
+ }
+}
+
+impl<'lua> FromLua<'lua> for OwnedThread {
+ #[inline]
+ fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result {
+ Thread::from_lua(value, lua).map(|s| s.into_owned())
+ }
+}
+
impl<'lua> ToLua<'lua> for AnyUserData<'lua> {
#[inline]
fn to_lua(self, _: &'lua Lua) -> Result> {
@@ -138,6 +194,20 @@ impl<'lua> FromLua<'lua> for AnyUserData<'lua> {
}
}
+impl<'lua> ToLua<'lua> for OwnedAnyUserData {
+ #[inline]
+ fn to_lua(self, lua: &'lua Lua) -> Result> {
+ Ok(Value::UserData(AnyUserData(lua.adopt_owned_ref(self.0))))
+ }
+}
+
+impl<'lua> FromLua<'lua> for OwnedAnyUserData {
+ #[inline]
+ fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result {
+ AnyUserData::from_lua(value, lua).map(|s| s.into_owned())
+ }
+}
+
impl<'lua, T: 'static + MaybeSend + UserData> ToLua<'lua> for T {
#[inline]
fn to_lua(self, lua: &'lua Lua) -> Result> {
@@ -145,6 +215,7 @@ impl<'lua, T: 'static + MaybeSend + UserData> ToLua<'lua> for T {
}
}
+// TODO: Remove
impl<'lua, T: 'static + UserData + Clone> FromLua<'lua> for T {
#[inline]
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result {
diff --git a/src/function.rs b/src/function.rs
index 8fb8d28..a981007 100644
--- a/src/function.rs
+++ b/src/function.rs
@@ -5,7 +5,7 @@ use std::slice;
use crate::error::{Error, Result};
use crate::ffi;
-use crate::types::LuaRef;
+use crate::types::{LuaOwnedRef, LuaRef};
use crate::util::{
assert_stack, check_stack, error_traceback, pop_error, ptr_to_cstr_bytes, StackGuard,
};
@@ -18,6 +18,17 @@ use {futures_core::future::LocalBoxFuture, futures_util::future};
#[derive(Clone, Debug)]
pub struct Function<'lua>(pub(crate) LuaRef<'lua>);
+/// Owned handle to an internal Lua function.
+#[derive(Clone, Debug)]
+pub struct OwnedFunction(pub(crate) LuaOwnedRef);
+
+impl OwnedFunction {
+ /// Get borrowed handle to the underlying Lua function.
+ pub const fn to_ref(&self) -> Function {
+ Function(self.0.to_ref())
+ }
+}
+
#[derive(Clone, Debug)]
pub struct FunctionInfo {
pub name: Option>,
@@ -373,6 +384,12 @@ impl<'lua> Function<'lua> {
ffi::lua_getcoverage(lua.state, -1, func_ptr, callback::);
}
}
+
+ /// Convert this handle to owned version.
+ #[inline]
+ pub fn into_owned(self) -> OwnedFunction {
+ OwnedFunction(self.0.into_owned())
+ }
}
impl<'lua> PartialEq for Function<'lua> {
diff --git a/src/lib.rs b/src/lib.rs
index 24208b8..3dd3ca6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -108,15 +108,15 @@ pub use crate::{ffi::lua_CFunction, ffi::lua_State};
pub use crate::chunk::{AsChunk, Chunk, ChunkMode};
pub use crate::error::{Error, ExternalError, ExternalResult, Result};
-pub use crate::function::{Function, FunctionInfo};
+pub use crate::function::{Function, FunctionInfo, OwnedFunction};
pub use crate::hook::{Debug, DebugEvent, DebugNames, DebugSource, DebugStack};
pub use crate::lua::{GCMode, Lua, LuaOptions};
pub use crate::multi::Variadic;
pub use crate::scope::Scope;
pub use crate::stdlib::StdLib;
-pub use crate::string::String;
-pub use crate::table::{Table, TableExt, TablePairs, TableSequence};
-pub use crate::thread::{Thread, ThreadStatus};
+pub use crate::string::{OwnedString, String};
+pub use crate::table::{OwnedTable, Table, TableExt, TablePairs, TableSequence};
+pub use crate::thread::{OwnedThread, Thread, ThreadStatus};
pub use crate::types::{Integer, LightUserData, Number, RegistryKey};
pub use crate::userdata::{
AnyUserData, MetaMethod, UserData, UserDataFields, UserDataMetatable, UserDataMethods,
diff --git a/src/lua.rs b/src/lua.rs
index d1001de..4820dc7 100644
--- a/src/lua.rs
+++ b/src/lua.rs
@@ -25,8 +25,8 @@ use crate::string::String;
use crate::table::Table;
use crate::thread::Thread;
use crate::types::{
- Callback, CallbackUpvalue, DestructedUserdata, Integer, LightUserData, LuaRef, MaybeSend,
- Number, RegistryKey,
+ Callback, CallbackUpvalue, DestructedUserdata, Integer, LightUserData, LuaOwnedRef, LuaRef,
+ MaybeSend, Number, RegistryKey,
};
use crate::userdata::{AnyUserData, UserData, UserDataCell};
use crate::userdata_impl::{StaticUserDataFields, StaticUserDataMethods, UserDataProxy};
@@ -1721,7 +1721,7 @@ impl Lua {
ffi::lua_replace(thread_state, ffi::LUA_GLOBALSINDEX);
}
- return Ok(Thread(LuaRef { lua: self, index }));
+ return Ok(Thread(LuaRef::new(self, index)));
}
};
self.create_thread(func)
@@ -1750,7 +1750,7 @@ impl Lua {
#[cfg(feature = "luau")]
ffi::lua_resetthread(thread_state);
extra.recycled_thread_cache.push(thread.0.index);
- thread.0.index = 0;
+ thread.0.drop = false;
return true;
}
false
@@ -2440,7 +2440,7 @@ impl Lua {
// Pushes a LuaRef value onto the stack, uses 1 stack space, does not call checkstack
pub(crate) unsafe fn push_ref(&self, lref: &LuaRef) {
assert!(
- Arc::ptr_eq(&lref.lua.extra, &self.extra),
+ Arc::ptr_eq(&lref.lua.0, &self.0),
"Lua instance passed Value created from a different main Lua state"
);
let extra = &*self.extra.get();
@@ -2460,14 +2460,14 @@ impl Lua {
let extra = &mut *self.extra.get();
ffi::lua_xmove(self.state, extra.ref_thread, 1);
let index = ref_stack_pop(extra);
- LuaRef { lua: self, index }
+ LuaRef::new(self, index)
}
// Same as `pop_ref` but assumes the value is already on the reference thread
pub(crate) unsafe fn pop_ref_thread(&self) -> LuaRef {
let extra = &mut *self.extra.get();
let index = ref_stack_pop(extra);
- LuaRef { lua: self, index }
+ LuaRef::new(self, index)
}
pub(crate) fn clone_ref<'lua>(&'lua self, lref: &LuaRef<'lua>) -> LuaRef<'lua> {
@@ -2475,7 +2475,7 @@ impl Lua {
let extra = &mut *self.extra.get();
ffi::lua_pushvalue(extra.ref_thread, lref.index);
let index = ref_stack_pop(extra);
- LuaRef { lua: self, index }
+ LuaRef::new(self, index)
}
}
@@ -2488,6 +2488,29 @@ impl Lua {
}
}
+ pub(crate) fn make_owned_ref(&self, lref: LuaRef) -> LuaOwnedRef {
+ assert!(lref.drop, "Cannot make owned non-drop reference");
+ let owned_ref = LuaOwnedRef {
+ lua: Lua(self.0.clone()),
+ index: lref.index,
+ };
+ mem::forget(lref);
+ owned_ref
+ }
+
+ pub(crate) fn adopt_owned_ref(&self, loref: LuaOwnedRef) -> LuaRef {
+ assert!(
+ Arc::ptr_eq(&loref.lua.0, &self.0),
+ "Lua instance passed Value created from a different main Lua state"
+ );
+ let index = loref.index;
+ unsafe {
+ ptr::read(&loref.lua);
+ mem::forget(loref);
+ }
+ LuaRef::new(self, index)
+ }
+
unsafe fn push_userdata_metatable(&self) -> Result<()> {
let extra = &mut *self.extra.get();
diff --git a/src/string.rs b/src/string.rs
index 7ea251a..60d7072 100644
--- a/src/string.rs
+++ b/src/string.rs
@@ -12,7 +12,7 @@ use {
use crate::error::{Error, Result};
use crate::ffi;
-use crate::types::LuaRef;
+use crate::types::{LuaOwnedRef, LuaRef};
/// Handle to an internal Lua string.
///
@@ -20,6 +20,17 @@ use crate::types::LuaRef;
#[derive(Clone, Debug)]
pub struct String<'lua>(pub(crate) LuaRef<'lua>);
+/// Owned handle to an internal Lua string.
+#[derive(Clone, Debug)]
+pub struct OwnedString(pub(crate) LuaOwnedRef);
+
+impl OwnedString {
+ /// Get borrowed handle to the underlying Lua string.
+ pub const fn to_ref(&self) -> String {
+ String(self.0.to_ref())
+ }
+}
+
impl<'lua> String<'lua> {
/// Get a `&str` slice if the Lua string is valid UTF-8.
///
@@ -122,6 +133,12 @@ impl<'lua> String<'lua> {
let ref_thread = self.0.lua.ref_thread();
unsafe { ffi::lua_topointer(ref_thread, self.0.index) }
}
+
+ /// Convert this handle to owned version.
+ #[inline]
+ pub fn into_owned(self) -> OwnedString {
+ OwnedString(self.0.into_owned())
+ }
}
impl<'lua> AsRef<[u8]> for String<'lua> {
diff --git a/src/table.rs b/src/table.rs
index 424aaf0..2d9a889 100644
--- a/src/table.rs
+++ b/src/table.rs
@@ -11,7 +11,7 @@ use {
use crate::error::{Error, Result};
use crate::ffi;
use crate::function::Function;
-use crate::types::{Integer, LuaRef};
+use crate::types::{Integer, LuaOwnedRef, LuaRef};
use crate::util::{assert_stack, check_stack, StackGuard};
use crate::value::{FromLua, FromLuaMulti, Nil, ToLua, ToLuaMulti, Value};
@@ -22,6 +22,17 @@ use {futures_core::future::LocalBoxFuture, futures_util::future};
#[derive(Clone, Debug)]
pub struct Table<'lua>(pub(crate) LuaRef<'lua>);
+/// Owned handle to an internal Lua table.
+#[derive(Clone, Debug)]
+pub struct OwnedTable(pub(crate) LuaOwnedRef);
+
+impl OwnedTable {
+ /// Get borrowed handle to the underlying Lua table.
+ pub const fn to_ref(&self) -> Table {
+ Table(self.0.to_ref())
+ }
+}
+
#[allow(clippy::len_without_is_empty)]
impl<'lua> Table<'lua> {
/// Sets a key-value pair in the table.
@@ -512,6 +523,12 @@ impl<'lua> Table<'lua> {
unsafe { ffi::lua_topointer(ref_thread, self.0.index) }
}
+ /// Convert this handle to owned version.
+ #[inline]
+ pub fn into_owned(self) -> OwnedTable {
+ OwnedTable(self.0.into_owned())
+ }
+
/// Consume this table and return an iterator over the pairs of the table.
///
/// This works like the Lua `pairs` function, but does not invoke the `__pairs` metamethod.
diff --git a/src/thread.rs b/src/thread.rs
index c0a4260..811c056 100644
--- a/src/thread.rs
+++ b/src/thread.rs
@@ -3,7 +3,7 @@ use std::os::raw::c_int;
use crate::error::{Error, Result};
use crate::ffi;
-use crate::types::LuaRef;
+use crate::types::{LuaOwnedRef, LuaRef};
use crate::util::{check_stack, error_traceback_thread, pop_error, StackGuard};
use crate::value::{FromLuaMulti, ToLuaMulti};
@@ -48,6 +48,17 @@ pub enum ThreadStatus {
#[derive(Clone, Debug)]
pub struct Thread<'lua>(pub(crate) LuaRef<'lua>);
+/// Owned handle to an internal Lua thread.
+#[derive(Clone, Debug)]
+pub struct OwnedThread(pub(crate) LuaOwnedRef);
+
+impl OwnedThread {
+ /// Get borrowed handle to the underlying Lua thread.
+ pub const fn to_ref(&self) -> Thread {
+ Thread(self.0.to_ref())
+ }
+}
+
/// Thread (coroutine) representation as an async [`Future`] or [`Stream`].
///
/// Requires `feature = "async"`
@@ -333,6 +344,12 @@ impl<'lua> Thread<'lua> {
protect_lua!(lua.state, 0, 0, |_| ffi::luaL_sandboxthread(thread))
}
}
+
+ /// Convert this handle to owned version.
+ #[inline]
+ pub fn into_owned(self) -> OwnedThread {
+ OwnedThread(self.0.into_owned())
+ }
}
impl<'lua> PartialEq for Thread<'lua> {
diff --git a/src/types.rs b/src/types.rs
index 9404d10..d5a5413 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -180,6 +180,21 @@ impl RegistryKey {
pub(crate) struct LuaRef<'lua> {
pub(crate) lua: &'lua Lua,
pub(crate) index: c_int,
+ pub(crate) drop: bool,
+}
+
+impl<'lua> LuaRef<'lua> {
+ pub(crate) const fn new(lua: &'lua Lua, index: c_int) -> Self {
+ LuaRef {
+ lua,
+ index,
+ drop: true,
+ }
+ }
+
+ pub(crate) fn into_owned(self) -> LuaOwnedRef {
+ self.lua.make_owned_ref(self)
+ }
}
impl<'lua> fmt::Debug for LuaRef<'lua> {
@@ -196,7 +211,7 @@ impl<'lua> Clone for LuaRef<'lua> {
impl<'lua> Drop for LuaRef<'lua> {
fn drop(&mut self) {
- if self.index > 0 {
+ if self.drop {
self.lua.drop_ref(self);
}
}
@@ -214,3 +229,40 @@ impl<'lua> PartialEq for LuaRef<'lua> {
}
}
}
+
+pub(crate) struct LuaOwnedRef {
+ pub(crate) lua: Lua,
+ pub(crate) index: c_int,
+}
+
+impl fmt::Debug for LuaOwnedRef {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "OwnedRef({})", self.index)
+ }
+}
+
+impl Clone for LuaOwnedRef {
+ fn clone(&self) -> Self {
+ self.lua.make_owned_ref(self.to_ref().clone())
+ }
+}
+
+impl Drop for LuaOwnedRef {
+ fn drop(&mut self) {
+ self.lua.drop_ref(&LuaRef {
+ lua: &self.lua,
+ index: self.index,
+ drop: false,
+ });
+ }
+}
+
+impl LuaOwnedRef {
+ pub(crate) const fn to_ref(&self) -> LuaRef {
+ LuaRef {
+ lua: &self.lua,
+ index: self.index,
+ drop: false,
+ }
+ }
+}
diff --git a/src/userdata.rs b/src/userdata.rs
index 0ad5f46..af5b304 100644
--- a/src/userdata.rs
+++ b/src/userdata.rs
@@ -20,7 +20,7 @@ use crate::ffi;
use crate::function::Function;
use crate::lua::Lua;
use crate::table::{Table, TablePairs};
-use crate::types::{Callback, LuaRef, MaybeSend};
+use crate::types::{Callback, LuaOwnedRef, LuaRef, MaybeSend};
use crate::util::{check_stack, get_userdata, take_userdata, StackGuard};
use crate::value::{FromLua, FromLuaMulti, ToLua, ToLuaMulti};
@@ -799,6 +799,15 @@ impl Serialize for UserDataSerializeError {
#[derive(Clone, Debug)]
pub struct AnyUserData<'lua>(pub(crate) LuaRef<'lua>);
+#[derive(Clone, Debug)]
+pub struct OwnedAnyUserData(pub(crate) LuaOwnedRef);
+
+impl OwnedAnyUserData {
+ pub const fn to_ref(&self) -> AnyUserData {
+ AnyUserData(self.0.to_ref())
+ }
+}
+
impl<'lua> AnyUserData<'lua> {
/// Checks whether the type of this userdata is `T`.
pub fn is(&self) -> bool {
@@ -1090,6 +1099,11 @@ impl<'lua> AnyUserData<'lua> {
}
}
+ #[inline]
+ pub fn into_owned(self) -> OwnedAnyUserData {
+ OwnedAnyUserData(self.0.into_owned())
+ }
+
pub(crate) fn equals>(&self, other: T) -> Result {
let other = other.as_ref();
// Uses lua_rawequal() under the hood