Skip to main content

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// `send` + `async` now compose. The async bridge keeps its per-VM waker +
74// implicit-thread ownership map in a process-wide table keyed by the VM's
75// global-state pointer (a real `Mutex` under `send`, a thread-local otherwise),
76// so the state travels with the VM across thread moves; the type-erased async
77// callback / future boxes carry a `MaybeSend` bound (`+ Send` under `send`)
78// exactly like the synchronous callbacks. See `async.rs` + `sync.rs`.
79
80mod app_data;
81#[cfg(feature = "async")]
82#[path = "async.rs"]
83mod async_support;
84mod buffer;
85mod callback;
86mod chunk;
87mod compiler;
88mod conversion;
89mod debug;
90mod error;
91mod exec_raw;
92/// The public, mlua-style `ffi` surface (mounted from `ffi_public.rs`).
93#[path = "ffi_public.rs"]
94pub mod ffi;
95mod function;
96mod gc;
97mod interrupt;
98mod light_userdata;
99mod luau_ext;
100mod memory;
101mod metamethod;
102mod module;
103mod multi;
104mod options;
105mod registry;
106mod scope;
107#[cfg(feature = "serde")]
108mod serde;
109pub mod state;
110mod string;
111mod sync;
112/// The internal, crate-private luaur C API re-exports (mounted from `ffi.rs`).
113#[path = "ffi.rs"]
114mod sys;
115mod table;
116mod thread;
117mod traits;
118#[cfg(feature = "typecheck")]
119mod typecheck;
120mod userdata;
121mod value;
122mod vector;
123
124pub use buffer::Buffer;
125pub use chunk::{Chunk, ChunkMode};
126pub use compiler::Compiler;
127pub use debug::{Debug, DebugWhat};
128pub use error::{Error, ExternalError, ExternalResult, Result};
129pub use function::{Function, FunctionInfo, LuaNativeFn};
130pub use interrupt::VmState;
131pub use light_userdata::LightUserData;
132pub use luau_ext::TypeMetatable;
133pub use metamethod::MetaMethod;
134pub use multi::{MultiValue, Variadic};
135pub use options::{LuaOptions, StdLib};
136pub use registry::RegistryKey;
137pub use scope::Scope;
138pub use state::{Lua, WeakLua};
139pub use string::LuaString;
140pub use sync::{MaybeSend, MaybeSync};
141pub use table::{Table, TablePairs, TableSequence};
142pub use thread::{Thread, ThreadStatus};
143pub use traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti};
144
145/// Static type-checking surface (the `typecheck` feature): the structured
146/// [`TypeDiagnostic`] type plus the free [`check`] / [`check_with_definitions`]
147/// helpers. The `Lua`/`Chunk` objects gain `check` / `add_definitions` methods
148/// (see [`Lua::check`] / [`Chunk::check`]) that return
149/// [`Error::TypeError`](crate::Error::TypeError).
150#[cfg(feature = "typecheck")]
151#[cfg_attr(docsrs, doc(cfg(feature = "typecheck")))]
152pub use typecheck::{check, check_with_definitions, TypeDiagnostic};
153
154pub use app_data::{AppDataRef, AppDataRefMut};
155/// The [`AsyncThread`] driver — a coroutine being run to completion as a Rust
156/// `Future`/`Stream` (the `async` feature).
157#[cfg(feature = "async")]
158#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
159pub use async_support::AsyncThread;
160pub use userdata::{
161    AnyUserData, UserData, UserDataFields, UserDataMethods, UserDataRef, UserDataRefMut,
162};
163pub use value::{Integer, Number, Value};
164pub use vector::Vector;
165
166/// `Value::Nil`, re-exported as a bare name (the enum *variant*, so it works in
167/// both value and pattern position). Mirrors `mlua::Nil`.
168pub use value::Value::Nil;
169
170/// The `#[derive(UserData)]` / `#[derive(FromLua)]` procedural derive macros
171/// (mirroring mlua's `macros` feature), re-exported so users can write
172/// `#[derive(luaur_rt::UserData)]` / `#[derive(luaur_rt::FromLua)]`.
173#[cfg(feature = "macros")]
174pub use luaur_rt_derive::{FromLua, UserData};
175
176#[cfg(feature = "serde")]
177pub use serde::{
178    DeserializeOptions, Deserializer as LuaDeserializer, LuaSerdeExt, SerializableTable,
179    SerializableValue, SerializeOptions, Serializer as LuaSerializer,
180};
181
182/// Idiomatic glob-import prelude. Mirrors `mlua::prelude`, additionally
183/// re-exporting the short names so `use luaur_rt::prelude::*;` brings the whole
184/// ergonomic surface into scope.
185pub mod prelude {
186    pub use crate::{
187        AnyUserData, Buffer, Chunk, Error, ExternalError, ExternalResult, FromLua, FromLuaMulti,
188        Function, IntoLua, IntoLuaMulti, Lua, LuaString, MetaMethod, MultiValue, RegistryKey,
189        Result, Scope, Table, Thread, ThreadStatus, UserData, UserDataFields, UserDataMethods,
190        Value, Variadic, Vector,
191    };
192
193    // mlua-style `Lua*`-prefixed aliases for users coming from mlua's prelude.
194    pub use crate::AnyUserData as LuaAnyUserData;
195    pub use crate::Error as LuaError;
196    pub use crate::Function as LuaFunction;
197    pub use crate::MetaMethod as LuaMetaMethod;
198    pub use crate::MultiValue as LuaMultiValue;
199    pub use crate::RegistryKey as LuaRegistryKey;
200    pub use crate::Result as LuaResult;
201    pub use crate::Table as LuaTable;
202    pub use crate::Thread as LuaThread;
203    pub use crate::ThreadStatus as LuaThreadStatus;
204    pub use crate::UserData as LuaUserData;
205    pub use crate::UserDataFields as LuaUserDataFields;
206    pub use crate::UserDataMethods as LuaUserDataMethods;
207    pub use crate::Value as LuaValue;
208    pub use crate::Variadic as LuaVariadic;
209    // `LuaString` already carries the `Lua` prefix.
210}
211
212/// A raw `lua_State` pointer type alias, re-exported at the crate root for
213/// signature parity with `mlua::lua_State`.
214pub use luaur_vm::type_aliases::lua_state::lua_State;
215
216#[cfg(test)]
217mod tests;