luau 0.732.0

Safe lifetime-bound Rust embedding API for the Luau runtime
//! Safe, idiomatic embedding APIs for the Luau runtime.
//!
//! Compiler, syntax, bytecode, code generation, and VM internals remain in
//! their owning crates. This crate exposes the safe lifetime-bound embedding
//! surface.
//!
//! ```
//! # fn main() -> luau::Result<()> {
//! let lua = luau::Lua::new()?;
//! let answer: i32 = lua.load("return 40 + 2").call(())?;
//! assert_eq!(answer, 42);
//! # Ok(())
//! # }
//! ```
//!
//! Use [`callback!`] or [`function!`] to expose typed Rust callbacks. Luau
//! strings, tables, functions, threads, and userdata borrow their [`Lua`]
//! state and cannot outlive it.

#![deny(missing_docs)]

extern crate self as luau;

mod buffer;
mod callback;
mod class;
mod error;
mod function;
mod hooks;
mod light_userdata;
mod lua;
mod macros;
mod object;
mod string;
mod table;
mod thread;
mod userdata;
mod value;
mod vector;

#[cfg(feature = "macros")]
#[doc(hidden)]
pub mod __private {
    pub use inventory;

    pub use crate::lua::{CaptureEnvironment, CapturedChunk, captured_chunk};
    pub use crate::userdata::{
        UserdataMacroRegistry, UserdataRegistration, register_userdata_impls,
    };

    /// Adds callback argument position information to a generated conversion
    /// error.
    pub fn callback_argument_error(position: usize, error: crate::Error) -> crate::Error {
        crate::Error::bad_argument(position, error)
    }
}

/// Derives [`FromLua`] by borrowing matching typed [`AnyUserdata`] and cloning
/// its Rust payload.
///
/// This does not perform structural conversion from tables or other Luau
/// values. The derived type must implement [`Clone`] and be `'static`.
#[cfg(feature = "macros")]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
pub use luau_derive::FromLua;
/// Derives [`Userdata`] and exposes named struct fields to Luau.
///
/// Fields are readable and writable by default. Use `#[luau(...)]` to change
/// their Luau-facing behavior:
///
/// | Attribute | Effect |
/// | --- | --- |
/// | `get` | Expose only the field getter. |
/// | `set` | Expose only the field setter. |
/// | `skip` | Do not expose the field. |
/// | `name = "..."` | Use a different Luau name. |
///
/// Readable fields must implement [`Clone`].
///
/// Apply [`userdata_impl`] to inherent impl blocks to register their associated
/// constants and functions. Multiple attributed impl blocks for the same type
/// compose, including impl blocks in different modules.
/// Every associated constant and function is registered unless it has
/// `#[luau(skip)]`.
///
/// ```
/// # use luau::{AnyUserdata, Lua, Result};
/// #[derive(luau::Userdata)]
/// struct Counter {
///     value: i32,
/// }
///
/// #[luau::userdata_impl]
/// impl Counter {
///     #[luau(infallible)]
///     fn new(value: i32) -> Self {
///         Self { value }
///     }
///
///     #[luau(infallible)]
///     fn increment(&mut self, amount: Option<i32>) -> i32 {
///         self.value += amount.unwrap_or(1);
///         self.value
///     }
///
///     #[luau(meta, infallible)]
///     fn __call(_proxy: AnyUserdata<'_>, value: i32) -> Self {
///         Self { value }
///     }
/// }
///
/// # fn main() -> Result<()> {
/// let lua = Lua::new()?;
/// lua.globals()?.set("Counter", lua.create_proxy::<Counter>()?)?;
/// let value: i32 = lua.load("return Counter(40):increment(2)").call(())?;
/// assert_eq!(value, 42);
/// # Ok(())
/// # }
/// ```
///
/// The receiver selects the registration kind:
///
/// | Receiver | Registration |
/// | --- | --- |
/// | `&self` | Immutable method |
/// | `&mut self` | Mutable method |
/// | `self` | Consuming method |
/// | None | Type function |
///
/// A first typed parameter of [`LuaRef`] is supplied by the callback and is not
/// read from Luau arguments. Other parameters are converted normally, with
/// these borrowed forms handled directly:
///
/// | Parameter | Value borrowed for the call |
/// | --- | --- |
/// | `&str` | Luau string text |
/// | `&[u8]` | Luau string bytes |
/// | `&T` | Typed userdata |
/// | `&mut T` | Mutably borrowed typed userdata |
///
/// These forms may also be wrapped in [`Option`]. The final non-reference
/// parameter is converted through [`FromLuaMulti`] and can consume the
/// remaining arguments.
///
/// Items in a [`userdata_impl`] block support:
///
/// | Attribute | Applies to | Effect |
/// | --- | --- | --- |
/// | `skip` | Functions, constants | Do not register the item. |
/// | `name = "..."` | Functions, constants | Use a different Luau name. |
/// | `infallible` | Functions | Treat the Rust return value as successful. |
/// | `get` | Functions | Register an `&self` function as a field getter. |
/// | `set` | Functions | Register an `&self` or `&mut self` function as a field setter. |
/// | `field` | Functions | Register a receiver-free function as a type field. |
/// | `meta` | Functions, constants | Register a metamethod or meta field. |
///
/// A `field` function is evaluated once when the userdata type is registered.
/// It takes no Luau arguments, but may receive [`LuaRef`] and return a
/// lifetime-bound value. Combine `field` with `meta` to register a computed
/// metatable field.
///
/// Associated constants are type fields by default. A receiver-free
/// metamethod receives every argument Luau passes; for `__call` on a type
/// proxy, this includes the proxy itself.
///
/// Generic userdata derives and generic impl blocks are not supported.
/// Unions are not supported. Tuple structs, unit structs, and enums derive the
/// trait without fields and can define their surface through
/// [`userdata_impl`]. Lifetime parameters on exposed methods are supported.
#[cfg(feature = "macros")]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
pub use luau_derive::Userdata;
/// Creates a source chunk that may capture Rust values.
///
/// Prefix a Rust identifier with `$` to place its value in the chunk
/// environment. Captured values are moved into the chunk and converted through
/// [`IntoLua`] when the chunk is passed to [`Lua::load`].
///
/// ```
/// # use luau::{Lua, Result};
/// # fn main() -> Result<()> {
/// let lua = Lua::new()?;
/// let name = String::from("Luau");
/// let greeting: String = lua
///     .load(luau::chunk! {
///         return "hello, " .. $name
///     })
///     .call(())?;
/// assert_eq!(greeting, "hello, Luau");
/// # Ok(())
/// # }
/// ```
///
/// The capture environment preserves `nil`: a captured `None` shadows a
/// global with the same name. Assignments to captured names remain in that
/// environment; other global reads and writes use the current global table.
///
/// `chunk!` uses Rust's tokenizer, so Luau source must also be valid Rust
/// tokens. Notable restrictions are:
///
/// - Multi-character single-quoted strings are not valid Rust literals; use
///   double quotes.
/// - Luau escapes that Rust string literals do not accept, such as `\a`, `\b`,
///   `\f`, `\v`, `\z`, and decimal escapes other than `\0`, cannot be written
///   directly.
/// - Backtick interpolated strings are not valid Rust tokens.
/// - The `//` floor-division operator starts a Rust comment.
///
/// Captured chunks use an explicit environment. Calling
/// [`Chunk::set_environment`] replaces it, and sandbox behavior for custom
/// environments remains under the embedder's control.
#[cfg(feature = "macros")]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
pub use luau_derive::chunk;
/// Registers an inherent `impl` block as part of a derived [`Userdata`] type.
///
/// See the [`Userdata`](derive@Userdata) derive macro for supported receivers,
/// parameters, and attributes.
#[cfg(feature = "macros")]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
pub use luau_derive::userdata_impl;

pub use bstr::{BStr, BString};
pub use buffer::Buffer;
pub use callback::{Arguments, CallbackReturn, Varargs};
pub use class::{Class, Object};
pub use error::{Error, ExternalError, ExternalResult, Result};
pub use function::{CoverageInfo, Function, FunctionInfo};
pub use hooks::{
    DebugAction, DebugContext, DebugHandler, DebugHooks, ExecutionInterruptContext,
    GcInterruptContext, GcInterruptStage, GcPhase, InterruptAction, InterruptHandle,
    InterruptHandler, InterruptHooks, InterruptMode, PatternInterruptContext,
    ProtectedErrorContext,
};
pub use light_userdata::LightUserdata;
pub use lua::{
    AppDataRef, AppDataRefMut, AsChunk, Chunk, ChunkMode, CompileConstant, Compiler, Lua, LuaRef,
    RegistryKey, SandboxedChunk, Scope, StackInfo, StdLib,
};
pub use luau_compiler::CompilerError;
pub use object::ObjectLike;
pub use string::LuaString;
pub use table::{Table, TablePairs, TableSequence};
pub use thread::{Thread, ThreadStatus};
pub use userdata::{
    AnyUserdata, MetaMethod, Userdata, UserdataFields, UserdataMetatable, UserdataMetatablePairs,
    UserdataMethods, UserdataRef, UserdataRefMut, UserdataRegistry,
};
pub use value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, MultiValue, Value, Variadic};
pub use vector::Vector;

/// Allocators accepted by [`Lua::new_with_allocator`].
pub mod allocator {
    pub use luau_vm::state::{LuaAllocator, SystemLuaAllocator};
}