Skip to main content

luars_derive/
lib.rs

1//! Procedural macros for luars userdata system.
2//!
3//! # Macros provided
4//!
5//! - `#[derive(LuaUserData)]` — auto-generate `UserDataTrait` for structs and enums
6//!   (field access via `get_field`/`set_field`, metamethods via `#[lua_impl(...)]`,
7//!   and `IntoLua` for owned Rust → Lua userdata conversion)
8//!
9//! - `#[lua_methods]` — attribute macro on impl blocks, generates static C wrapper
10//!   functions for each `pub fn`, accessible from Lua via `obj:method(...)` calls
11//!
12//! # Architecture
13//!
14//! - `derive_userdata.rs` — `#[derive(LuaUserData)]` implementation
15//! - `lua_methods.rs` — `#[lua_methods]` implementation
16//! - `type_utils.rs` — shared type conversion helpers (Rust ↔ UdValue ↔ LuaValue)
17
18mod derive_userdata;
19mod lua_methods;
20mod type_utils;
21
22use proc_macro::TokenStream;
23use syn::parse_macro_input;
24
25/// Derive `UserDataTrait` for a struct or enum.
26///
27/// # Supported field types (auto-converted to/from UdValue)
28/// - `i8`..`i64`, `isize` → `UdValue::Integer`
29/// - `u8`..`u64`, `usize` → `UdValue::Integer`
30/// - `f32`, `f64` → `UdValue::Number`
31/// - `bool` → `UdValue::Boolean`
32/// - `String` → `UdValue::Str`
33///
34/// # Field attributes
35/// - `#[lua(skip)]` — exclude from Lua
36/// - `#[lua(readonly)]` — get only, no set
37/// - `#[lua(name = "...")]` — custom Lua name
38///
39/// # Struct attributes
40/// - `#[lua_impl(Display, PartialEq, PartialOrd)]` — metamethods from Rust traits
41///
42/// # Enum behavior
43/// - C-like enums also implement `LuaEnum`, so they can be exported with `register_enum::<T>()`
44/// - Enums with payloads are treated as fieldless userdata and can expose methods via `#[lua_methods]`
45///
46/// # Conversion behavior
47/// - `IntoLua` is auto-implemented, so derived userdata values can be passed directly into typed APIs
48/// - Owned `FromLua` is intentionally not auto-implemented, because userdata lives in Lua GC storage and
49///   implicit extraction by value would blur ownership semantics
50///
51/// # Example
52/// ```ignore
53/// #[derive(LuaUserData, PartialEq, PartialOrd)]
54/// #[lua_impl(Display, PartialEq, PartialOrd)]
55/// struct Point {
56///     pub x: f64,
57///     pub y: f64,
58///     #[lua(skip)]
59///     internal_id: u32,
60/// }
61/// ```
62#[proc_macro_derive(LuaUserData, attributes(lua, lua_impl))]
63pub fn derive_lua_userdata(input: TokenStream) -> TokenStream {
64    let input = parse_macro_input!(input as syn::DeriveInput);
65    derive_userdata::derive_lua_userdata_impl(input)
66}
67
68/// Attribute macro on impl blocks — exposes public methods to Lua.
69///
70/// For each `pub fn` with a `&self` or `&mut self` receiver, generates:
71/// 1. A static `fn(l: &mut LuaState) -> LuaResult<usize>` wrapper
72/// 2. Automatic parameter extraction from Lua stack
73/// 3. Automatic return value conversion to Lua
74///
75/// Methods are accessible from Lua via `obj:method(args)` syntax.
76///
77/// # Example
78/// ```ignore
79/// #[lua_methods]
80/// impl Point {
81///     pub fn distance(&self) -> f64 {
82///         (self.x * self.x + self.y * self.y).sqrt()
83///     }
84///     pub fn translate(&mut self, dx: f64, dy: f64) {
85///         self.x += dx;
86///         self.y += dy;
87///     }
88/// }
89/// ```
90#[proc_macro_attribute]
91pub fn lua_methods(_attr: TokenStream, input: TokenStream) -> TokenStream {
92    lua_methods::lua_methods_impl(input)
93}