Skip to content
This repository has been archived by the owner on Jun 5, 2024. It is now read-only.

Commit

Permalink
Expand handle struct and runtime ext trait to be able to use from ins…
Browse files Browse the repository at this point in the history
…ide lua
  • Loading branch information
filiptibell committed Jan 28, 2024
1 parent da28466 commit b03a010
Show file tree
Hide file tree
Showing 9 changed files with 254 additions and 55 deletions.
50 changes: 48 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ categories = ["async"]
[dependencies]
async-executor = "1.8"
concurrent-queue = "2.4"
derive_more = "0.99"
event-listener = "4.0"
futures-lite = "2.2"
tracing = "0.1"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ lua.globals().set(
lua.create_async_function(|lua, path: String| async move {
// Spawn background task that does not take up resources on the lua thread
// Normally, futures in mlua can not be shared across threads, but this can
let task = lua.spawn(async move {
let task = lua.spawn_future(async move {
match read_to_string(path).await {
Ok(s) => Ok(Some(s)),
Err(e) if e.kind() == ErrorKind::NotFound => Ok(None),
Expand Down
4 changes: 2 additions & 2 deletions examples/basic_spawn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use async_fs::read_to_string;
use async_io::block_on;

use mlua::prelude::*;
use mlua_luau_runtime::{LuaSpawnExt, Runtime};
use mlua_luau_runtime::{LuaRuntimeExt, Runtime};

const MAIN_SCRIPT: &str = include_str!("./lua/basic_spawn.luau");

Expand All @@ -19,7 +19,7 @@ pub fn main() -> LuaResult<()> {
"readFile",
lua.create_async_function(|lua, path: String| async move {
// Spawn background task that does not take up resources on the Lua thread
let task = lua.spawn(async move {
let task = lua.spawn_future(async move {
match read_to_string(path).await {
Ok(s) => Ok(Some(s)),
Err(e) if e.kind() == ErrorKind::NotFound => Ok(None),
Expand Down
45 changes: 38 additions & 7 deletions lib/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,35 @@
#![allow(clippy::missing_panics_doc)]
#![allow(clippy::module_name_repetitions)]

use std::{cell::RefCell, rc::Rc};
use std::{
cell::{Cell, RefCell},
rc::Rc,
};

use event_listener::Event;
use mlua::prelude::*;

use crate::{
runtime::Runtime,
status::Status,
traits::IntoLuaThread,
util::{run_until_yield, ThreadWithArgs},
IntoLuaThread,
};

/**
A handle to a thread that has been spawned onto a [`Runtime`].
This handle contains a single public method, [`Handle::result`], which may
be used to extract the result of the thread, once it has finished running.
This handle contains a public method, [`Handle::result`], which may
be used to extract the result of the thread, once it finishes running.
A result may be waited for using the [`Handle::listen`] method.
*/
#[derive(Debug, Clone)]
pub struct Handle {
thread: Rc<RefCell<Option<ThreadWithArgs>>>,
result: Rc<RefCell<Option<(bool, LuaRegistryKey)>>>,
status: Rc<Cell<bool>>,
event: Rc<Event>,
}

impl Handle {
Expand All @@ -39,6 +47,8 @@ impl Handle {
Ok(Self {
thread: Rc::new(RefCell::new(Some(packed))),
result: Rc::new(RefCell::new(None)),
status: Rc::new(Cell::new(false)),
event: Rc::new(Event::new()),
})
}

Expand All @@ -59,14 +69,23 @@ impl Handle {
.into_inner(lua)
}

fn set<'lua>(&self, lua: &'lua Lua, result: &LuaResult<LuaMultiValue<'lua>>) -> LuaResult<()> {
fn set<'lua>(
&self,
lua: &'lua Lua,
result: &LuaResult<LuaMultiValue<'lua>>,
is_final: bool,
) -> LuaResult<()> {
self.result.borrow_mut().replace((
result.is_ok(),
match &result {
Ok(v) => lua.create_registry_value(v.clone().into_vec())?,
Err(e) => lua.create_registry_value(e.clone())?,
},
));
self.status.replace(is_final);
if is_final {
self.event.notify(usize::MAX);
}
Ok(())
}

Expand All @@ -90,6 +109,17 @@ impl Handle {
Err(lua.registry_value(key).unwrap())
})
}

/**
Waits for this handle to have its final result available.
Does not wait if the final result is already available.
*/
pub async fn listen(&self) {
if !self.status.get() {
self.event.listen().await;
}
}
}

impl LuaUserData for Handle {
Expand All @@ -103,8 +133,9 @@ impl LuaUserData for Handle {
it may be caught using the runtime and any error callback(s)
*/
let (thread, args) = this.take(lua);
let result = run_until_yield(thread, args).await;
this.set(lua, &result)?;
let result = run_until_yield(thread.clone(), args).await;
let is_final = thread.status() != LuaThreadStatus::Resumable;
this.set(lua, &result, is_final)?;
result
});
}
Expand Down
2 changes: 1 addition & 1 deletion lib/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ mod util;
pub use handle::Handle;
pub use runtime::Runtime;
pub use status::Status;
pub use traits::{IntoLuaThread, LuaSpawnExt};
pub use traits::{IntoLuaThread, LuaRuntimeExt};
41 changes: 40 additions & 1 deletion lib/queue.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use std::sync::Arc;

use concurrent_queue::ConcurrentQueue;
use derive_more::{Deref, DerefMut};
use event_listener::Event;
use mlua::prelude::*;

use crate::{util::ThreadWithArgs, IntoLuaThread};
use crate::{handle::Handle, traits::IntoLuaThread, util::ThreadWithArgs};

/**
Queue for storing [`LuaThread`]s with associated arguments.
Expand Down Expand Up @@ -43,6 +44,20 @@ impl ThreadQueue {
Ok(())
}

pub fn push_item_with_handle<'lua>(
&self,
lua: &'lua Lua,
thread: impl IntoLuaThread<'lua>,
args: impl IntoLuaMulti<'lua>,
) -> LuaResult<Handle> {
let handle = Handle::new(lua, thread, args)?;
let handle_thread = handle.create_thread(lua)?;

self.push_item(lua, handle_thread, ())?;

Ok(handle)
}

pub fn drain_items<'outer, 'lua>(
&'outer self,
lua: &'lua Lua,
Expand All @@ -59,3 +74,27 @@ impl ThreadQueue {
}
}
}

/**
Alias for [`ThreadQueue`], providing a newtype to store in Lua app data.
*/
#[derive(Debug, Clone, Deref, DerefMut)]
pub(crate) struct SpawnedThreadQueue(ThreadQueue);

impl SpawnedThreadQueue {
pub fn new() -> Self {
Self(ThreadQueue::new())
}
}

/**
Alias for [`ThreadQueue`], providing a newtype to store in Lua app data.
*/
#[derive(Debug, Clone, Deref, DerefMut)]
pub(crate) struct DeferredThreadQueue(ThreadQueue);

impl DeferredThreadQueue {
pub fn new() -> Self {
Self(ThreadQueue::new())
}
}
Loading

0 comments on commit b03a010

Please sign in to comment.