Bind Futures lifetimes to 'lua rather than 'static.
Fix async examples.
This commit is contained in:
parent
7efcee853d
commit
6e2bb73cff
|
@ -61,10 +61,7 @@ impl UserData for LuaTcpStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
async fn run_server(lua: &'static Lua) -> Result<()> {
|
||||||
async fn main() -> Result<()> {
|
|
||||||
let lua = Lua::new();
|
|
||||||
|
|
||||||
let spawn = lua.create_function(move |_, func: Function| {
|
let spawn = lua.create_function(move |_, func: Function| {
|
||||||
task::spawn_local(async move { func.call_async::<_, ()>(()).await.unwrap() });
|
task::spawn_local(async move { func.call_async::<_, ()>(()).await.unwrap() });
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -80,20 +77,33 @@ async fn main() -> Result<()> {
|
||||||
local addr = ...
|
local addr = ...
|
||||||
local listener = tcp.bind(addr)
|
local listener = tcp.bind(addr)
|
||||||
print("listening on "..addr)
|
print("listening on "..addr)
|
||||||
|
|
||||||
|
local accept_new = true
|
||||||
while true do
|
while true do
|
||||||
local stream = listener:accept()
|
local stream = listener:accept()
|
||||||
local peer_addr = stream:peer_addr()
|
local peer_addr = stream:peer_addr()
|
||||||
print("connected from "..peer_addr)
|
print("connected from "..peer_addr)
|
||||||
|
|
||||||
|
if not accept_new then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
spawn(function()
|
spawn(function()
|
||||||
while true do
|
while true do
|
||||||
local data = stream:read(100)
|
local data = stream:read(100)
|
||||||
data = data:match("^%s*(.-)%s*$") -- trim
|
data = data:match("^%s*(.-)%s*$") -- trim
|
||||||
print("["..peer_addr.."] "..data)
|
print("["..peer_addr.."] "..data)
|
||||||
stream:write("got: "..data.."\n")
|
if data == "bye" then
|
||||||
|
stream:write("bye bye\n")
|
||||||
|
stream:close()
|
||||||
|
return
|
||||||
|
end
|
||||||
if data == "exit" then
|
if data == "exit" then
|
||||||
stream:close()
|
stream:close()
|
||||||
break
|
accept_new = false
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
stream:write("echo: "..data.."\n")
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
@ -105,3 +115,15 @@ async fn main() -> Result<()> {
|
||||||
.run_until(server.call_async::<_, ()>("0.0.0.0:1234"))
|
.run_until(server.call_async::<_, ()>("0.0.0.0:1234"))
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
let lua = Lua::new().into_static();
|
||||||
|
|
||||||
|
run_server(lua).await.unwrap();
|
||||||
|
|
||||||
|
// Consume the static reference and drop it.
|
||||||
|
// This is safe as long as we don't hold any other references to Lua
|
||||||
|
// or alive resources.
|
||||||
|
unsafe { Lua::from_static(lua) };
|
||||||
|
}
|
||||||
|
|
36
src/lua.rs
36
src/lua.rs
|
@ -75,7 +75,7 @@ impl Drop for Lua {
|
||||||
extra.registry_unref_list.try_borrow_mut(),
|
extra.registry_unref_list.try_borrow_mut(),
|
||||||
"unref list borrowed"
|
"unref list borrowed"
|
||||||
) = None;
|
) = None;
|
||||||
ffi::lua_close(self.state);
|
ffi::lua_close(self.main_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,6 +113,30 @@ impl Lua {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Consumes and leaks `Lua` object, returning a static reference `&'static Lua`.
|
||||||
|
///
|
||||||
|
/// This function is useful when the `Lua` object is supposed to live for the remainder
|
||||||
|
/// of the program's life.
|
||||||
|
/// In particular in asynchronous context this will allow to spawn Lua tasks to execute
|
||||||
|
/// in background.
|
||||||
|
///
|
||||||
|
/// Dropping the returned reference will cause a memory leak. If this is not acceptable,
|
||||||
|
/// the reference should first be wrapped with the [`Lua::from_static`] function producing a `Lua`.
|
||||||
|
/// This `Lua` object can then be dropped which will properly release the allocated memory.
|
||||||
|
///
|
||||||
|
/// [`Lua::from_static`]: #method.from_static
|
||||||
|
pub fn into_static(self) -> &'static Self {
|
||||||
|
Box::leak(Box::new(self))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a `Lua` from a static reference to it.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// This function is unsafe because improper use may lead to memory problems or undefined behavior.
|
||||||
|
pub unsafe fn from_static(lua: &'static Lua) -> Self {
|
||||||
|
*Box::from_raw(lua as *const Lua as *mut Lua)
|
||||||
|
}
|
||||||
|
|
||||||
/// Loads the specified set of standard libraries into an existing Lua state.
|
/// Loads the specified set of standard libraries into an existing Lua state.
|
||||||
///
|
///
|
||||||
/// Use the [`StdLib`] flags to specifiy the libraries you want to load.
|
/// Use the [`StdLib`] flags to specifiy the libraries you want to load.
|
||||||
|
@ -529,7 +553,7 @@ impl Lua {
|
||||||
A: FromLuaMulti<'callback>,
|
A: FromLuaMulti<'callback>,
|
||||||
R: ToLuaMulti<'callback>,
|
R: ToLuaMulti<'callback>,
|
||||||
F: 'static + Fn(&'callback Lua, A) -> FR,
|
F: 'static + Fn(&'callback Lua, A) -> FR,
|
||||||
FR: 'static + Future<Output = Result<R>>,
|
FR: 'lua + Future<Output = Result<R>>,
|
||||||
{
|
{
|
||||||
self.create_async_callback(Box::new(move |lua, args| {
|
self.create_async_callback(Box::new(move |lua, args| {
|
||||||
let args = match A::from_lua_multi(args, lua) {
|
let args = match A::from_lua_multi(args, lua) {
|
||||||
|
@ -1614,7 +1638,7 @@ impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMet
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: ToLuaMulti<'lua>,
|
R: ToLuaMulti<'lua>,
|
||||||
M: 'static + Fn(&'lua Lua, T, A) -> MR,
|
M: 'static + Fn(&'lua Lua, T, A) -> MR,
|
||||||
MR: 'static + Future<Output = Result<R>>,
|
MR: 'lua + Future<Output = Result<R>>,
|
||||||
{
|
{
|
||||||
self.async_methods
|
self.async_methods
|
||||||
.push((name.as_ref().to_vec(), Self::box_async_method(method)));
|
.push((name.as_ref().to_vec(), Self::box_async_method(method)));
|
||||||
|
@ -1650,7 +1674,7 @@ impl<'lua, T: 'static + UserData> UserDataMethods<'lua, T> for StaticUserDataMet
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: ToLuaMulti<'lua>,
|
R: ToLuaMulti<'lua>,
|
||||||
F: 'static + Fn(&'lua Lua, A) -> FR,
|
F: 'static + Fn(&'lua Lua, A) -> FR,
|
||||||
FR: 'static + Future<Output = Result<R>>,
|
FR: 'lua + Future<Output = Result<R>>,
|
||||||
{
|
{
|
||||||
self.async_methods
|
self.async_methods
|
||||||
.push((name.as_ref().to_vec(), Self::box_async_function(function)));
|
.push((name.as_ref().to_vec(), Self::box_async_function(function)));
|
||||||
|
@ -1748,7 +1772,7 @@ impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: ToLuaMulti<'lua>,
|
R: ToLuaMulti<'lua>,
|
||||||
M: 'static + Fn(&'lua Lua, T, A) -> MR,
|
M: 'static + Fn(&'lua Lua, T, A) -> MR,
|
||||||
MR: 'static + Future<Output = Result<R>>,
|
MR: 'lua + Future<Output = Result<R>>,
|
||||||
{
|
{
|
||||||
Box::new(move |lua, mut args| {
|
Box::new(move |lua, mut args| {
|
||||||
let fut_res = || {
|
let fut_res = || {
|
||||||
|
@ -1801,7 +1825,7 @@ impl<'lua, T: 'static + UserData> StaticUserDataMethods<'lua, T> {
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: ToLuaMulti<'lua>,
|
R: ToLuaMulti<'lua>,
|
||||||
F: 'static + Fn(&'lua Lua, A) -> FR,
|
F: 'static + Fn(&'lua Lua, A) -> FR,
|
||||||
FR: 'static + Future<Output = Result<R>>,
|
FR: 'lua + Future<Output = Result<R>>,
|
||||||
{
|
{
|
||||||
Box::new(move |lua, args| {
|
Box::new(move |lua, args| {
|
||||||
let args = match A::from_lua_multi(args, lua) {
|
let args = match A::from_lua_multi(args, lua) {
|
||||||
|
|
|
@ -165,7 +165,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: ToLuaMulti<'lua>,
|
R: ToLuaMulti<'lua>,
|
||||||
M: 'static + Fn(&'lua Lua, T, A) -> MR,
|
M: 'static + Fn(&'lua Lua, T, A) -> MR,
|
||||||
MR: 'static + Future<Output = Result<R>>;
|
MR: 'lua + Future<Output = Result<R>>;
|
||||||
|
|
||||||
/// Add a regular method as a function which accepts generic arguments, the first argument will
|
/// Add a regular method as a function which accepts generic arguments, the first argument will
|
||||||
/// be a `UserData` of type T if the method is called with Lua method syntax:
|
/// be a `UserData` of type T if the method is called with Lua method syntax:
|
||||||
|
@ -209,7 +209,7 @@ pub trait UserDataMethods<'lua, T: UserData> {
|
||||||
A: FromLuaMulti<'lua>,
|
A: FromLuaMulti<'lua>,
|
||||||
R: ToLuaMulti<'lua>,
|
R: ToLuaMulti<'lua>,
|
||||||
F: 'static + Fn(&'lua Lua, A) -> FR,
|
F: 'static + Fn(&'lua Lua, A) -> FR,
|
||||||
FR: 'static + Future<Output = Result<R>>;
|
FR: 'lua + Future<Output = Result<R>>;
|
||||||
|
|
||||||
/// Add a metamethod which accepts a `&T` as the first parameter.
|
/// Add a metamethod which accepts a `&T` as the first parameter.
|
||||||
///
|
///
|
||||||
|
|
Loading…
Reference in New Issue