mirror of
https://github.com/mlua-rs/mlua
synced 2026-06-08 16:05:43 +00:00
mlua_derive: Switch from #[userdata] to [derive(UserData)]
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
use mlua::{Lua, Result, chunk};
|
||||
use mlua::{Lua, Result, UserData, chunk};
|
||||
|
||||
#[derive(Default)]
|
||||
#[mlua::userdata]
|
||||
#[derive(Default, UserData)]
|
||||
struct Rectangle {
|
||||
length: u32,
|
||||
width: u32,
|
||||
|
||||
@@ -33,11 +33,11 @@ pub fn from_lua(input: TokenStream) -> TokenStream {
|
||||
from_lua::from_lua(input)
|
||||
}
|
||||
|
||||
/// Attribute macro for exposing a Rust type as a Lua userdata.
|
||||
/// Derive macro for implementing `UserData` for a Rust type.
|
||||
#[cfg(feature = "macros")]
|
||||
#[proc_macro_attribute]
|
||||
pub fn userdata(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
userdata::userdata_type(attr, item)
|
||||
#[proc_macro_derive(UserData, attributes(lua))]
|
||||
pub fn userdata(item: TokenStream) -> TokenStream {
|
||||
userdata::userdata_type(item)
|
||||
}
|
||||
|
||||
/// Attribute macro for exposing impl block methods to Lua userdata.
|
||||
|
||||
@@ -34,35 +34,18 @@ fn parse_field_lua_attr(attrs: &[Attribute]) -> syn::Result<LuaAttr> {
|
||||
Ok(lua_attr)
|
||||
}
|
||||
|
||||
/// Strip `#[lua(...)]` attributes from a field, keeping all others.
|
||||
fn strip_lua_attrs(attrs: &[Attribute]) -> Vec<Attribute> {
|
||||
(attrs.iter())
|
||||
.filter(|attr| !attr.path().is_ident("lua"))
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn userdata_type(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
if !attr.is_empty() {
|
||||
return Error::new_spanned(
|
||||
proc_macro2::TokenStream::from(attr),
|
||||
"`#[userdata]` does not accept arguments",
|
||||
)
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
|
||||
let mut input = parse_macro_input!(item as DeriveInput);
|
||||
pub fn userdata_type(item: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(item as DeriveInput);
|
||||
let type_name = &input.ident;
|
||||
|
||||
let mut named_fields: Option<&mut FieldsNamed> = match &mut input.data {
|
||||
Data::Struct(data) => match &mut data.fields {
|
||||
let named_fields: Option<&FieldsNamed> = match &input.data {
|
||||
Data::Struct(data) => match &data.fields {
|
||||
Fields::Named(fields) => Some(fields),
|
||||
Fields::Unnamed(_) | Fields::Unit => None,
|
||||
},
|
||||
Data::Enum(_) => None,
|
||||
Data::Union(_) => {
|
||||
return Error::new_spanned(&input, "`#[userdata]` cannot be applied to unions")
|
||||
return Error::new_spanned(&input, "`#[derive(UserData)]` cannot be applied to unions")
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
@@ -73,14 +56,14 @@ pub fn userdata_type(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
if has_type_params {
|
||||
return Error::new_spanned(
|
||||
&input.generics,
|
||||
"`#[userdata]` does not support generic type parameters. Wrap the generic type in a concrete newtype instead."
|
||||
"`#[derive(UserData)]` does not support generic type parameters. Wrap the generic type in a concrete newtype instead."
|
||||
)
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
|
||||
let mut field_registrations = Vec::new();
|
||||
if let Some(fields) = &mut named_fields {
|
||||
if let Some(fields) = &named_fields {
|
||||
for field in &fields.named {
|
||||
let field_name = field.ident.as_ref().unwrap();
|
||||
|
||||
@@ -114,19 +97,12 @@ pub fn userdata_type(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
field_registrations.push(with_cfg(tokens, &field.attrs));
|
||||
}
|
||||
}
|
||||
|
||||
// Strip mlua-specific attributes from fields before re-emitting
|
||||
for field in &mut fields.named {
|
||||
field.attrs = strip_lua_attrs(&field.attrs);
|
||||
}
|
||||
}
|
||||
|
||||
let registration_type_name = format_ident!("__MluaUserDataRegistration_{type_name}");
|
||||
let register_fields_fn_name = format_ident!("__mlua_register_{type_name}_fields");
|
||||
|
||||
let output = quote! {
|
||||
#input
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(non_camel_case_types)]
|
||||
struct #registration_type_name {
|
||||
|
||||
+3
-5
@@ -233,16 +233,14 @@ pub use mlua_derive::chunk;
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
|
||||
pub use mlua_derive::FromLua;
|
||||
|
||||
/// Attribute macro for exposing a struct as Lua userdata.
|
||||
/// Derive macro for implementing [`UserData`] for a Rust type.
|
||||
///
|
||||
/// All fields are auto-exposed as get/set.
|
||||
/// Named fields are auto-exposed as get/set.
|
||||
///
|
||||
/// Use `#[lua(...)]` to customize.
|
||||
///
|
||||
/// This generates a [`UserData`] trait implementation.
|
||||
#[cfg(feature = "macros")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
|
||||
pub use mlua_derive::userdata;
|
||||
pub use mlua_derive::UserData;
|
||||
|
||||
/// Attribute macro for exposing impl block methods to Lua userdata.
|
||||
///
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#[derive(Default)]
|
||||
#[mlua::userdata]
|
||||
#[derive(Default, mlua::UserData)]
|
||||
struct Foo;
|
||||
|
||||
#[mlua::userdata_impl]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error: const items do not support `getter` or `setter`
|
||||
--> tests/compile/userdata_const_getter.rs:8:11
|
||||
--> tests/compile/userdata_const_getter.rs:7:11
|
||||
|
|
||||
8 | const X: u32 = 42;
|
||||
7 | const X: u32 = 42;
|
||||
| ^
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use mlua::Result;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[mlua::userdata]
|
||||
#[derive(Clone, Debug, mlua::UserData)]
|
||||
struct Foo;
|
||||
|
||||
#[mlua::userdata_impl]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
error: async field function is not supported
|
||||
--> tests/compile/userdata_field_async.rs:10:5
|
||||
|
|
||||
10 | async fn description() -> Result<String> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
--> tests/compile/userdata_field_async.rs:9:5
|
||||
|
|
||||
9 | async fn description() -> Result<String> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: unused import: `mlua::Result`
|
||||
--> tests/compile/userdata_field_async.rs:1:5
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#[derive(Default)]
|
||||
#[mlua::userdata]
|
||||
#[derive(Default, mlua::UserData)]
|
||||
struct Foo {
|
||||
x: u32,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error: field function must not take arguments
|
||||
--> tests/compile/userdata_field_with_args.rs:10:5
|
||||
|
|
||||
10 | fn as_name(name: &str) -> String {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
--> tests/compile/userdata_field_with_args.rs:9:5
|
||||
|
|
||||
9 | fn as_name(name: &str) -> String {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#[derive(Default)]
|
||||
#[mlua::userdata]
|
||||
#[derive(Default, mlua::UserData)]
|
||||
struct Foo;
|
||||
|
||||
#[mlua::userdata_impl]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error: `meta` can only be combined with `field`
|
||||
--> tests/compile/userdata_getter_and_meta.rs:8:5
|
||||
--> tests/compile/userdata_getter_and_meta.rs:7:5
|
||||
|
|
||||
8 | fn bar(&self) -> mlua::Result<u32> {
|
||||
7 | fn bar(&self) -> mlua::Result<u32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#[derive(Default)]
|
||||
#[mlua::userdata]
|
||||
#[derive(Default, mlua::UserData)]
|
||||
struct Foo {
|
||||
x: u32,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error: at most one of `getter`, `setter`, `field` can be specified
|
||||
--> tests/compile/userdata_getter_and_setter.rs:10:5
|
||||
|
|
||||
10 | fn x(&self) -> mlua::Result<u32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
--> tests/compile/userdata_getter_and_setter.rs:9:5
|
||||
|
|
||||
9 | fn x(&self) -> mlua::Result<u32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use mlua::Result;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[mlua::userdata]
|
||||
#[derive(Clone, Debug, mlua::UserData)]
|
||||
struct Foo(u64);
|
||||
|
||||
#[mlua::userdata_impl]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
error: async field getter is not supported
|
||||
--> tests/compile/userdata_getter_async.rs:10:5
|
||||
|
|
||||
10 | async fn value(&self) -> Result<u64> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
--> tests/compile/userdata_getter_async.rs:9:5
|
||||
|
|
||||
9 | async fn value(&self) -> Result<u64> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: unused import: `mlua::Result`
|
||||
--> tests/compile/userdata_getter_async.rs:1:5
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#[derive(Default)]
|
||||
#[mlua::userdata]
|
||||
#[derive(Default, mlua::UserData)]
|
||||
struct Foo {
|
||||
x: u32,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error: field getter must not take additional arguments
|
||||
--> tests/compile/userdata_getter_extra_arg.rs:10:5
|
||||
|
|
||||
10 | fn x(&self, extra: u32) -> mlua::Result<u32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
--> tests/compile/userdata_getter_extra_arg.rs:9:5
|
||||
|
|
||||
9 | fn x(&self, extra: u32) -> mlua::Result<u32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#[derive(Default)]
|
||||
#[mlua::userdata]
|
||||
#[derive(Default, mlua::UserData)]
|
||||
struct Foo {
|
||||
x: u32,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error: field getter must take `&self`
|
||||
--> tests/compile/userdata_getter_mut_self.rs:10:5
|
||||
|
|
||||
10 | fn x(&mut self) -> mlua::Result<u32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
--> tests/compile/userdata_getter_mut_self.rs:9:5
|
||||
|
|
||||
9 | fn x(&mut self) -> mlua::Result<u32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#[derive(Default)]
|
||||
#[mlua::userdata]
|
||||
#[derive(Default, mlua::UserData)]
|
||||
struct Foo;
|
||||
|
||||
#[mlua::userdata_impl]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error: meta methods cannot take `self`, use `&[mut] self` instead
|
||||
--> tests/compile/userdata_meta_owned_self.rs:8:5
|
||||
--> tests/compile/userdata_meta_owned_self.rs:7:5
|
||||
|
|
||||
8 | fn __gc(self) -> mlua::Result<()> {
|
||||
7 | fn __gc(self) -> mlua::Result<()> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#[derive(Default)]
|
||||
#[mlua::userdata]
|
||||
#[derive(Default, mlua::UserData)]
|
||||
struct Foo(Vec<u8>);
|
||||
|
||||
#[mlua::userdata_impl]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error: this reference type is not supported as a callback parameter
|
||||
--> tests/compile/userdata_mut_slice_arg.rs:7:27
|
||||
--> tests/compile/userdata_mut_slice_arg.rs:6:27
|
||||
|
|
||||
7 | fn first(&self, data: &mut [u8]) -> mlua::Result<u8> {
|
||||
6 | fn first(&self, data: &mut [u8]) -> mlua::Result<u8> {
|
||||
| ^^^^^^^^^
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use mlua::Result;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[mlua::userdata]
|
||||
#[derive(Clone, Debug, mlua::UserData)]
|
||||
struct Foo(u64);
|
||||
|
||||
#[mlua::userdata_impl]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
error: async field setter is not supported
|
||||
--> tests/compile/userdata_setter_async.rs:10:5
|
||||
|
|
||||
10 | async fn set_value(&mut self, val: u64) -> Result<()> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
--> tests/compile/userdata_setter_async.rs:9:5
|
||||
|
|
||||
9 | async fn set_value(&mut self, val: u64) -> Result<()> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: unused import: `mlua::Result`
|
||||
--> tests/compile/userdata_setter_async.rs:1:5
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#[derive(Default)]
|
||||
#[mlua::userdata]
|
||||
#[derive(Default, mlua::UserData)]
|
||||
struct Foo {
|
||||
x: u32,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error: field setter must take exactly one value argument
|
||||
--> tests/compile/userdata_setter_no_value.rs:10:5
|
||||
|
|
||||
10 | fn set_x(&mut self) -> mlua::Result<()> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
--> tests/compile/userdata_setter_no_value.rs:9:5
|
||||
|
|
||||
9 | fn set_x(&mut self) -> mlua::Result<()> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#[derive(Default)]
|
||||
#[mlua::userdata]
|
||||
#[derive(Default, mlua::UserData)]
|
||||
struct Foo {
|
||||
x: u32,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error: field setter must take `&[mut] self`
|
||||
--> tests/compile/userdata_setter_ref_self.rs:10:5
|
||||
|
|
||||
10 | fn set_x(self, val: u32) -> mlua::Result<()> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
--> tests/compile/userdata_setter_ref_self.rs:9:5
|
||||
|
|
||||
9 | fn set_x(self, val: u32) -> mlua::Result<()> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#[derive(Default)]
|
||||
#[mlua::userdata]
|
||||
#[derive(Default, mlua::UserData)]
|
||||
struct Foo {
|
||||
x: u32,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error: field function must not take `self`
|
||||
--> tests/compile/userdata_static_with_self.rs:10:5
|
||||
|
|
||||
10 | fn get_x(&self) -> mlua::Result<u32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
--> tests/compile/userdata_static_with_self.rs:9:5
|
||||
|
|
||||
9 | fn get_x(&self) -> mlua::Result<u32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
+7
-12
@@ -1,9 +1,8 @@
|
||||
#![cfg(feature = "macros")]
|
||||
|
||||
use mlua::{Lua, Result};
|
||||
use mlua::{Lua, Result, UserData};
|
||||
|
||||
#[derive(Default, Clone, Debug)]
|
||||
#[mlua::userdata]
|
||||
#[derive(Default, Clone, Debug, UserData)]
|
||||
struct Rectangle {
|
||||
length: u32,
|
||||
#[lua]
|
||||
@@ -208,8 +207,7 @@ fn test_rectangle() {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[mlua::userdata]
|
||||
#[derive(Clone, Debug, UserData)]
|
||||
enum Color {
|
||||
Red,
|
||||
Green,
|
||||
@@ -274,8 +272,7 @@ fn test_color() {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[mlua::userdata]
|
||||
#[derive(Clone, Debug, UserData)]
|
||||
struct Point(i32, i32);
|
||||
|
||||
fn make_lua_point() -> Lua {
|
||||
@@ -328,8 +325,7 @@ fn test_point() {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[mlua::userdata]
|
||||
#[derive(Clone, Debug, UserData)]
|
||||
struct Bytes(Vec<u8>);
|
||||
|
||||
#[mlua::userdata_impl]
|
||||
@@ -375,10 +371,9 @@ fn test_known_borrow_wrappers() -> Result<()> {
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
mod async_tests {
|
||||
use mlua::{Lua, Result};
|
||||
use mlua::{Lua, Result, UserData};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[mlua::userdata]
|
||||
#[derive(Clone, Debug, UserData)]
|
||||
struct AsyncCounter(u64);
|
||||
|
||||
#[mlua::userdata_impl]
|
||||
|
||||
Reference in New Issue
Block a user