Skip to content

mlua-isle 0.8.0

Latest

Choose a tag to compare

@ynishi ynishi released this 25 Sep 10:52
· 32 commits to main since this release
990979f

mlua-isle 0.8.0

Typed results and typed errors at every boundary, and a documented in-thread layer (runtime::Vm) that the actors are built on. The 0.7 in-thread API (run_root, hooks::*, tasks::install) now forwards to runtime and is deprecated.

This is a breaking release (0.7 → 0.8). Per the crate's versioning policy, return types and error payloads change in place (no _as / _raw twins); only renames that forward get #[deprecated].

Breaking

Typed results and arguments (#10)

Results are converted on the VM thread with FromLuaMulti and the T crosses back; arguments are converted there with IntoLuaMulti.

0.7 0.8 Migration
isle.eval(code) -> Result<String, _> isle.eval::<T>(code) -> Result<T, _> isle.eval::<String>(code)? or annotate the binding
isle.call(f, &["a", "b"]) isle.call::<A, T>(f, args) call::<_, String>("f", ("a", "b")); &[] → ()
isle.exec(|lua| Ok(x.to_string())) isle.exec(|lua| Ok(x)) returning T: Send return the value itself
Task<T = String> / AsyncTask<T = String> Task<T> / AsyncTask<T> name the T

The same applies to AsyncIsle (eval, call, exec, coroutine_eval, coroutine_call and their spawn_* forms) and to the pooled handles. The lossy string conversion is gone: nil is None with Option<T>, tables are rejected at compile time (convert inside exec), booleans are bool, and multiple return values are a tuple. A value that does not convert is IsleError::Lua with LuaErrorKind::Conversion.

Typed errors (#11)

0.7 0.8 Migration
IsleError::Lua(String) IsleError::Lua(LuaFailure) use f.message (or f.to_string())
IsleError::Init(String) IsleError::Init(LuaFailure) use f.message
IsleError::ThreadPanic IsleError::ThreadPanic(Option<String>) ThreadPanic(_)
IsleError::RecvFailed(String) IsleError::RecvFailed drop the payload
Lua("function '<name>' not found: ...") IsleError::NotFound(String) match NotFound(name)
IsleError: PartialEq not implemented assert!(matches!(r, Err(IsleError::Cancelled)))

A cancel is now mlua::Error::external(Cancelled), recognised by downcast instead of the __isle_cancelled__ message. In Lua, use task.is_cancelled(err); in Rust, use e.downcast_ref::<Cancelled>() or IsleError::from(e).

The protected call captures xpcall when the VM is set up, so attach before sandboxing the globals.

See the CHANGELOG for the full list (chunk names, memory errors, cancel precedence in sync requests).

Added

  • runtime module: the in-thread layer for a host that owns the Lua and drives its own LocalSet. runtime::Vm::attach(&lua, Config), Vm::of, config / set_config, add_hook / remove_hook, and with tokio task_lib() and run(&token, f, args). The module docs state the layer's contracts, the hook, and the Lua task library.
  • runtime::Config (grace, preempt_every) and AsyncIsleBuilder::config(Config).
  • Host tasks in a request's scope (#8): runtime::current_scope() → ScopeHandle::spawn_local(fut) → ScopedTask<T> (await / keep / detach()), structured like task.spawn tasks.
  • LuaFailure (kind, message, traceback, and value with the new serde feature) and LuaErrorKind.
  • Cancelled, the value a cancel raises; task.is_cancelled(err) in the Lua task library.
  • impl From<IsleError> for mlua::Error: ? on an IsleError in an init closure or host function. IsleError::Cancelled stays a cancel across the boundary (task.is_cancelled(err) in Lua, IsleError::Cancelled back in Rust).

Changed

  • The cancel grace period is one deadline shared by a request or task and everything it spawned, transitively.
  • The actors attach a runtime::Vm to their VM and run coroutine requests through Vm::run (no behaviour change).

Deprecated

Each old name still compiles, warns, and forwards to its replacement. All of them will be removed in the release after 0.8.0.

0.7 0.8
mlua_isle::run_root(lua, token, f, args) Vm::attach(lua, config)? once, then vm.run(&token, f, args)
mlua_isle::cancellable runtime::cancellable
mlua_isle::current_token runtime::current_token
hooks::install(lua) Vm::attach(lua, config)
hooks::configure(lua, c) / hooks::config(lua) vm.set_config(c) / vm.config()
hooks::add_hook / hooks::remove_hook vm.add_hook / vm.remove_hook
hooks::CancelConfig runtime::Config (the old name is now an alias)
hooks::HookId runtime::HookId
tasks::install(lua) vm.task_lib()
modules hooks, tasks runtime

Behaviour of the forwarding names:

  • hooks::install, hooks::add_hook, tasks::install and run_root attach the VM (with its stored config) when it is not attached yet. In doing so they capture xpcall, so they fail on a VM whose globals were sandboxed before the first call.
  • tasks::install returns the VM's one task table, the same table on every call.

In an actor's init closure, attach the VM there: let vm = Vm::attach(lua, config)?; (? works through the new From<IsleError> for mlua::Error). The actor re-attaches after the closure and keeps the config, the hooks and the task table.

Fixed

  • Cancelling a coroutine request, a Vm::run / run_root call or a task now waits for the tasks it spawned, transitively, to finish or be dropped before it resolves. Previously those tasks could be dropped later, inside the next request on the same VM.