Skip to main content

mlua_isle/
lib.rs

1//! Thread-isolated Lua VM with cancellation for mlua.
2//!
3//! `mlua-isle` runs a Lua VM on a dedicated thread and communicates via
4//! channels.  This solves two fundamental problems with mlua:
5//!
6//! 1. **`Lua` is `!Send`** — it cannot cross thread boundaries.  By
7//!    confining the VM to one thread and sending requests over a channel,
8//!    callers on any thread (UI, async runtime, etc.) can interact with
9//!    Lua without `Send` issues.
10//!
11//! 2. **Cancellation** — long-running Lua code (including blocking Rust
12//!    callbacks like HTTP calls) can be interrupted via a cancel token
13//!    that triggers both a Lua debug hook and a caller-side signal.
14//!
15//! # Architecture
16//!
17//! ```text
18//! ┌─────────────────┐   mpsc    ┌──────────────────┐
19//! │  caller thread   │─────────►│  Lua thread       │
20//! │  (UI / async)    │          │  (mlua confined)   │
21//! │                  │◄─────────│                    │
22//! │  Isle handle     │  oneshot  │  Lua VM + hook    │
23//! └─────────────────┘           └──────────────────┘
24//! ```
25//!
26//! # Example
27//!
28//! ```rust
29//! use mlua_isle::Isle;
30//!
31//! let isle = Isle::spawn(|lua| {
32//!     lua.globals().set("greeting", "hello")?;
33//!     Ok(())
34//! }).unwrap();
35//!
36//! let result: String = isle.eval("return greeting").unwrap();
37//! assert_eq!(result, "hello");
38//!
39//! isle.shutdown().unwrap();
40//! ```
41
42mod error;
43mod handle;
44mod hook;
45#[cfg(feature = "pool")]
46mod pool;
47mod task;
48mod thread;
49
50#[cfg(feature = "tokio")]
51mod async_isle;
52#[cfg(all(feature = "pool", feature = "tokio"))]
53mod async_pool;
54#[cfg(feature = "tokio")]
55mod async_task;
56
57pub use error::IsleError;
58pub use handle::Isle;
59pub use hook::CancelToken;
60pub use task::Task;
61
62#[cfg(feature = "pool")]
63pub use pool::{IslePool, PoolConfig, PoolStrategy, PooledIsle};
64
65#[cfg(feature = "tokio")]
66pub use async_isle::{AsyncIsle, AsyncIsleBuilder, AsyncIsleDriver};
67#[cfg(all(feature = "pool", feature = "tokio"))]
68pub use async_pool::{AsyncIslePool, AsyncPooledIsle};
69#[cfg(feature = "tokio")]
70pub use async_task::AsyncTask;
71
72/// Type alias for exec closures to keep the `Request` enum readable.
73pub(crate) type ExecFn = Box<dyn FnOnce(&mlua::Lua) -> Result<String, IsleError> + Send>;
74
75/// Channel sender for results.
76pub(crate) type ResultTx = std::sync::mpsc::Sender<Result<String, IsleError>>;
77
78/// Request sent from caller to the Lua thread.
79pub(crate) enum Request {
80    /// Evaluate a Lua chunk and return the result as a string.
81    Eval {
82        code: String,
83        cancel: CancelToken,
84        tx: ResultTx,
85    },
86    /// Call a named global function with string arguments.
87    Call {
88        func: String,
89        args: Vec<String>,
90        cancel: CancelToken,
91        tx: ResultTx,
92    },
93    /// Execute an arbitrary closure on the Lua thread.
94    Exec {
95        f: ExecFn,
96        cancel: CancelToken,
97        tx: ResultTx,
98    },
99    /// Graceful shutdown.
100    Shutdown,
101}