luaur_rt/lib.rs
1//! # luaur-rt
2//!
3//! A safe, ergonomic, **mlua-style** high-level API for
4//! [`luaur`](https://github.com/pjankiewicz/luaur) — a pure-Rust translation of
5//! Roblox's [Luau](https://github.com/luau-lang/luau).
6//!
7//! The public surface deliberately mirrors [`mlua`](https://docs.rs/mlua)'s
8//! interface — the same type names ([`Lua`], [`Value`], [`Table`],
9//! [`Function`], [`LuaString`], [`MultiValue`], [`Variadic`], [`Error`]), the
10//! same method names and call shapes (`Lua::new`, `lua.globals()`,
11//! `lua.create_function`, `lua.load(src).eval::<T>()`, `table.set/get`,
12//! `function.call::<R>(args)`), and the same conversion traits ([`FromLua`],
13//! [`IntoLua`], [`FromLuaMulti`], [`IntoLuaMulti`]) and userdata traits
14//! ([`UserData`], [`UserDataMethods`]). The *implementation*, however, is
15//! entirely original: it is written directly over luaur's pure-Rust C API
16//! (`lua_*`), not over a C FFI.
17//!
18//! ```
19//! use luaur_rt::prelude::*;
20//!
21//! let lua = Lua::new();
22//! let add = lua
23//! .create_function(|_, (a, b): (i64, i64)| Ok(a + b))
24//! .unwrap();
25//! lua.globals().set("add", add).unwrap();
26//! let sum: i64 = lua.load("return add(2, 3)").eval().unwrap();
27//! assert_eq!(sum, 5);
28//! ```
29//!
30//! ## Single-threaded
31//!
32//! Like mlua's default, [`Lua`] is single-threaded: it is built on `Rc`, so it
33//! is neither `Send` nor `Sync`. Clone a [`Lua`] to get another handle to the
34//! same VM.
35//!
36//! ## Deferred (not yet implemented)
37//!
38//! The following parts of mlua's surface are intentionally **out of scope** and
39//! are noted here rather than implemented:
40//!
41//! - Multi-VM `Send`/`Sync` (`WeakLua`, send-able handles) (P4).
42//! - Thread event callbacks (`ThreadEvent`/`ThreadTriggers`/
43//! `set_thread_event_callback`) and per-thread hooks.
44//! - The `chunk!` proc-macro.
45//! - Async userdata methods (`add_async_method*`) and the `ObjectLike`
46//! `call_async_method` surface (depend on the deferred userdata registry).
47//!
48//! Implemented in Phase 1: `Thread`/coroutine wrappers, public `RegistryKey`
49//! storage, `UserDataFields`, typed `AnyUserData::borrow`/`borrow_mut`/`take`/
50//! `is`, the `MetaMethod` enum, and `Function::info`/`environment`.
51//!
52//! Implemented in Phase 2: the Luau-specific runtime types [`Buffer`] (the
53//! `buffer` type) and [`Vector`] (the `vector` type), with their
54//! [`Value::Buffer`]/[`Value::Vector`] variants and `FromLua`/`IntoLua` impls.
55//!
56//! Implemented in Phase 4a (behind the `serde` cargo feature): serde
57//! (de)serialization between Rust types and Lua [`Value`]s — the `LuaSerdeExt`
58//! trait on [`Lua`], a serde `Serializer`/`Deserializer` over [`Value`]/
59//! [`Table`], `SerializeOptions`/`DeserializeOptions`, and `Serialize` impls
60//! for [`Value`]/[`Table`] with the `Value::to_serializable` wrapper.
61//!
62//! Implemented in Phase 4c (behind the `async` cargo feature): Rust `async`/
63//! `await` support — the Rust-`Future` ⟷ Lua-coroutine bridge.
64//! `Lua::create_async_function` / `Lua::yield_with`, `Function::call_async` /
65//! `Function::wrap_async` / `Function::wrap_raw_async`, `Chunk::call_async` /
66//! `Chunk::exec_async` / `Chunk::eval_async`, and `Thread::into_async`
67//! producing an `AsyncThread` that implements `Future` + `Stream`.
68//! Executor-agnostic, like mlua: the caller drives the returned futures on
69//! their own runtime.
70
71#![forbid(unsafe_op_in_unsafe_fn)]
72
73// The `send` and `async` features are currently mutually exclusive. luaur-rt's
74// async bridge relies on thread-local waker/ownership maps and non-`Send`
75// `Pin<Box<dyn Future>>` callbacks; making the `send`+`async` combination sound
76// is deferred (see `Cargo.toml`). `send` alone — the core `Send` handles that
77// `tests/send.rs` checks — is fully supported.
78#[cfg(all(feature = "send", feature = "async"))]
79compile_error!(
80 "the `send` and `async` features are mutually exclusive in luaur-rt for now: \
81 making the async bridge (thread-local wakers + non-Send futures) `Send` is deferred. \
82 Enable one or the other, not both."
83);
84
85mod app_data;
86#[cfg(feature = "async")]
87#[path = "async.rs"]
88mod async_support;
89mod buffer;
90mod callback;
91mod chunk;
92mod compiler;
93mod conversion;
94mod debug;
95mod error;
96mod exec_raw;
97/// The public, mlua-style `ffi` surface (mounted from `ffi_public.rs`).
98#[path = "ffi_public.rs"]
99pub mod ffi;
100mod function;
101mod gc;
102mod interrupt;
103mod light_userdata;
104mod luau_ext;
105mod memory;
106mod metamethod;
107mod module;
108mod multi;
109mod options;
110mod registry;
111mod scope;
112#[cfg(feature = "serde")]
113mod serde;
114pub mod state;
115mod string;
116mod sync;
117/// The internal, crate-private luaur C API re-exports (mounted from `ffi.rs`).
118#[path = "ffi.rs"]
119mod sys;
120mod table;
121mod thread;
122mod traits;
123#[cfg(feature = "typecheck")]
124mod typecheck;
125mod userdata;
126mod value;
127mod vector;
128
129pub use buffer::Buffer;
130pub use chunk::{Chunk, ChunkMode};
131pub use compiler::Compiler;
132pub use debug::{Debug, DebugWhat};
133pub use error::{Error, ExternalError, ExternalResult, Result};
134pub use function::{Function, FunctionInfo, LuaNativeFn};
135pub use interrupt::VmState;
136pub use light_userdata::LightUserData;
137pub use luau_ext::TypeMetatable;
138pub use metamethod::MetaMethod;
139pub use multi::{MultiValue, Variadic};
140pub use options::{LuaOptions, StdLib};
141pub use registry::RegistryKey;
142pub use scope::Scope;
143pub use state::{Lua, WeakLua};
144pub use string::LuaString;
145pub use sync::{MaybeSend, MaybeSync};
146pub use table::{Table, TablePairs, TableSequence};
147pub use thread::{Thread, ThreadStatus};
148pub use traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti};
149
150/// Static type-checking surface (the `typecheck` feature): the structured
151/// [`TypeDiagnostic`] type plus the free [`check`] / [`check_with_definitions`]
152/// helpers. The `Lua`/`Chunk` objects gain `check` / `add_definitions` methods
153/// (see [`Lua::check`] / [`Chunk::check`]) that return
154/// [`Error::TypeError`](crate::Error::TypeError).
155#[cfg(feature = "typecheck")]
156#[cfg_attr(docsrs, doc(cfg(feature = "typecheck")))]
157pub use typecheck::{check, check_with_definitions, TypeDiagnostic};
158
159pub use app_data::{AppDataRef, AppDataRefMut};
160/// The [`AsyncThread`] driver — a coroutine being run to completion as a Rust
161/// `Future`/`Stream` (the `async` feature).
162#[cfg(feature = "async")]
163#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
164pub use async_support::AsyncThread;
165pub use userdata::{
166 AnyUserData, UserData, UserDataFields, UserDataMethods, UserDataRef, UserDataRefMut,
167};
168pub use value::{Integer, Number, Value};
169pub use vector::Vector;
170
171/// `Value::Nil`, re-exported as a bare name (the enum *variant*, so it works in
172/// both value and pattern position). Mirrors `mlua::Nil`.
173pub use value::Value::Nil;
174
175/// The `#[derive(UserData)]` / `#[derive(FromLua)]` procedural derive macros
176/// (mirroring mlua's `macros` feature), re-exported so users can write
177/// `#[derive(luaur_rt::UserData)]` / `#[derive(luaur_rt::FromLua)]`.
178#[cfg(feature = "macros")]
179pub use luaur_rt_derive::{FromLua, UserData};
180
181#[cfg(feature = "serde")]
182pub use serde::{
183 DeserializeOptions, Deserializer as LuaDeserializer, LuaSerdeExt, SerializableTable,
184 SerializableValue, SerializeOptions, Serializer as LuaSerializer,
185};
186
187/// Idiomatic glob-import prelude. Mirrors `mlua::prelude`, additionally
188/// re-exporting the short names so `use luaur_rt::prelude::*;` brings the whole
189/// ergonomic surface into scope.
190pub mod prelude {
191 pub use crate::{
192 AnyUserData, Buffer, Chunk, Error, ExternalError, ExternalResult, FromLua, FromLuaMulti,
193 Function, IntoLua, IntoLuaMulti, Lua, LuaString, MetaMethod, MultiValue, RegistryKey,
194 Result, Scope, Table, Thread, ThreadStatus, UserData, UserDataFields, UserDataMethods,
195 Value, Variadic, Vector,
196 };
197
198 // mlua-style `Lua*`-prefixed aliases for users coming from mlua's prelude.
199 pub use crate::AnyUserData as LuaAnyUserData;
200 pub use crate::Error as LuaError;
201 pub use crate::Function as LuaFunction;
202 pub use crate::MetaMethod as LuaMetaMethod;
203 pub use crate::MultiValue as LuaMultiValue;
204 pub use crate::RegistryKey as LuaRegistryKey;
205 pub use crate::Result as LuaResult;
206 pub use crate::Table as LuaTable;
207 pub use crate::Thread as LuaThread;
208 pub use crate::ThreadStatus as LuaThreadStatus;
209 pub use crate::UserData as LuaUserData;
210 pub use crate::UserDataFields as LuaUserDataFields;
211 pub use crate::UserDataMethods as LuaUserDataMethods;
212 pub use crate::Value as LuaValue;
213 pub use crate::Variadic as LuaVariadic;
214 // `LuaString` already carries the `Lua` prefix.
215}
216
217/// A raw `lua_State` pointer type alias, re-exported at the crate root for
218/// signature parity with `mlua::lua_State`.
219pub use luaur_vm::type_aliases::lua_state::lua_State;
220
221#[cfg(test)]
222mod tests;