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// 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;