diff --git a/examples/userdata.rs b/examples/userdata.rs index 986e546..25b70a8 100644 --- a/examples/userdata.rs +++ b/examples/userdata.rs @@ -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, diff --git a/mlua_derive/src/lib.rs b/mlua_derive/src/lib.rs index 0a4f8af..8fc6dd4 100644 --- a/mlua_derive/src/lib.rs +++ b/mlua_derive/src/lib.rs @@ -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. diff --git a/mlua_derive/src/userdata/mod.rs b/mlua_derive/src/userdata/mod.rs index ff87bfc..83d91e3 100644 --- a/mlua_derive/src/userdata/mod.rs +++ b/mlua_derive/src/userdata/mod.rs @@ -34,35 +34,18 @@ fn parse_field_lua_attr(attrs: &[Attribute]) -> syn::Result { Ok(lua_attr) } -/// Strip `#[lua(...)]` attributes from a field, keeping all others. -fn strip_lua_attrs(attrs: &[Attribute]) -> Vec { - (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 { diff --git a/src/lib.rs b/src/lib.rs index bf06d47..95e67c7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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. /// diff --git a/tests/compile/userdata_const_getter.rs b/tests/compile/userdata_const_getter.rs index 6394ed8..1258410 100644 --- a/tests/compile/userdata_const_getter.rs +++ b/tests/compile/userdata_const_getter.rs @@ -1,5 +1,4 @@ -#[derive(Default)] -#[mlua::userdata] +#[derive(Default, mlua::UserData)] struct Foo; #[mlua::userdata_impl] diff --git a/tests/compile/userdata_const_getter.stderr b/tests/compile/userdata_const_getter.stderr index 6b7ef6a..b29f21a 100644 --- a/tests/compile/userdata_const_getter.stderr +++ b/tests/compile/userdata_const_getter.stderr @@ -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; | ^ diff --git a/tests/compile/userdata_field_async.rs b/tests/compile/userdata_field_async.rs index 004b412..fd2b533 100644 --- a/tests/compile/userdata_field_async.rs +++ b/tests/compile/userdata_field_async.rs @@ -1,7 +1,6 @@ use mlua::Result; -#[derive(Clone, Debug)] -#[mlua::userdata] +#[derive(Clone, Debug, mlua::UserData)] struct Foo; #[mlua::userdata_impl] diff --git a/tests/compile/userdata_field_async.stderr b/tests/compile/userdata_field_async.stderr index 13d7c68..a41d49f 100644 --- a/tests/compile/userdata_field_async.stderr +++ b/tests/compile/userdata_field_async.stderr @@ -1,8 +1,8 @@ error: async field function is not supported - --> tests/compile/userdata_field_async.rs:10:5 - | -10 | async fn description() -> Result { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> tests/compile/userdata_field_async.rs:9:5 + | +9 | async fn description() -> Result { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused import: `mlua::Result` --> tests/compile/userdata_field_async.rs:1:5 diff --git a/tests/compile/userdata_field_with_args.rs b/tests/compile/userdata_field_with_args.rs index 5394eaf..8757548 100644 --- a/tests/compile/userdata_field_with_args.rs +++ b/tests/compile/userdata_field_with_args.rs @@ -1,5 +1,4 @@ -#[derive(Default)] -#[mlua::userdata] +#[derive(Default, mlua::UserData)] struct Foo { x: u32, } diff --git a/tests/compile/userdata_field_with_args.stderr b/tests/compile/userdata_field_with_args.stderr index c7ccf45..a750138 100644 --- a/tests/compile/userdata_field_with_args.stderr +++ b/tests/compile/userdata_field_with_args.stderr @@ -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 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/compile/userdata_getter_and_meta.rs b/tests/compile/userdata_getter_and_meta.rs index 1c78f30..4da3688 100644 --- a/tests/compile/userdata_getter_and_meta.rs +++ b/tests/compile/userdata_getter_and_meta.rs @@ -1,5 +1,4 @@ -#[derive(Default)] -#[mlua::userdata] +#[derive(Default, mlua::UserData)] struct Foo; #[mlua::userdata_impl] diff --git a/tests/compile/userdata_getter_and_meta.stderr b/tests/compile/userdata_getter_and_meta.stderr index 9b7e219..68bd1bd 100644 --- a/tests/compile/userdata_getter_and_meta.stderr +++ b/tests/compile/userdata_getter_and_meta.stderr @@ -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 { +7 | fn bar(&self) -> mlua::Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/compile/userdata_getter_and_setter.rs b/tests/compile/userdata_getter_and_setter.rs index d6f33da..2232ded 100644 --- a/tests/compile/userdata_getter_and_setter.rs +++ b/tests/compile/userdata_getter_and_setter.rs @@ -1,5 +1,4 @@ -#[derive(Default)] -#[mlua::userdata] +#[derive(Default, mlua::UserData)] struct Foo { x: u32, } diff --git a/tests/compile/userdata_getter_and_setter.stderr b/tests/compile/userdata_getter_and_setter.stderr index 910ebc5..1f15a33 100644 --- a/tests/compile/userdata_getter_and_setter.stderr +++ b/tests/compile/userdata_getter_and_setter.stderr @@ -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 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> tests/compile/userdata_getter_and_setter.rs:9:5 + | +9 | fn x(&self) -> mlua::Result { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/compile/userdata_getter_async.rs b/tests/compile/userdata_getter_async.rs index 3591f0b..8d99f81 100644 --- a/tests/compile/userdata_getter_async.rs +++ b/tests/compile/userdata_getter_async.rs @@ -1,7 +1,6 @@ use mlua::Result; -#[derive(Clone, Debug)] -#[mlua::userdata] +#[derive(Clone, Debug, mlua::UserData)] struct Foo(u64); #[mlua::userdata_impl] diff --git a/tests/compile/userdata_getter_async.stderr b/tests/compile/userdata_getter_async.stderr index 8b8866e..fb8184d 100644 --- a/tests/compile/userdata_getter_async.stderr +++ b/tests/compile/userdata_getter_async.stderr @@ -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 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> tests/compile/userdata_getter_async.rs:9:5 + | +9 | async fn value(&self) -> Result { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused import: `mlua::Result` --> tests/compile/userdata_getter_async.rs:1:5 diff --git a/tests/compile/userdata_getter_extra_arg.rs b/tests/compile/userdata_getter_extra_arg.rs index 5e61ebc..fd218f0 100644 --- a/tests/compile/userdata_getter_extra_arg.rs +++ b/tests/compile/userdata_getter_extra_arg.rs @@ -1,5 +1,4 @@ -#[derive(Default)] -#[mlua::userdata] +#[derive(Default, mlua::UserData)] struct Foo { x: u32, } diff --git a/tests/compile/userdata_getter_extra_arg.stderr b/tests/compile/userdata_getter_extra_arg.stderr index 34adb6e..0e1b206 100644 --- a/tests/compile/userdata_getter_extra_arg.stderr +++ b/tests/compile/userdata_getter_extra_arg.stderr @@ -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 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> tests/compile/userdata_getter_extra_arg.rs:9:5 + | +9 | fn x(&self, extra: u32) -> mlua::Result { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/compile/userdata_getter_mut_self.rs b/tests/compile/userdata_getter_mut_self.rs index b48c2e6..96d977c 100644 --- a/tests/compile/userdata_getter_mut_self.rs +++ b/tests/compile/userdata_getter_mut_self.rs @@ -1,5 +1,4 @@ -#[derive(Default)] -#[mlua::userdata] +#[derive(Default, mlua::UserData)] struct Foo { x: u32, } diff --git a/tests/compile/userdata_getter_mut_self.stderr b/tests/compile/userdata_getter_mut_self.stderr index 79aa08f..db16094 100644 --- a/tests/compile/userdata_getter_mut_self.stderr +++ b/tests/compile/userdata_getter_mut_self.stderr @@ -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 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> tests/compile/userdata_getter_mut_self.rs:9:5 + | +9 | fn x(&mut self) -> mlua::Result { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/compile/userdata_meta_owned_self.rs b/tests/compile/userdata_meta_owned_self.rs index ef85b80..438d917 100644 --- a/tests/compile/userdata_meta_owned_self.rs +++ b/tests/compile/userdata_meta_owned_self.rs @@ -1,5 +1,4 @@ -#[derive(Default)] -#[mlua::userdata] +#[derive(Default, mlua::UserData)] struct Foo; #[mlua::userdata_impl] diff --git a/tests/compile/userdata_meta_owned_self.stderr b/tests/compile/userdata_meta_owned_self.stderr index 5cb10a1..b0157f2 100644 --- a/tests/compile/userdata_meta_owned_self.stderr +++ b/tests/compile/userdata_meta_owned_self.stderr @@ -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<()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/compile/userdata_mut_slice_arg.rs b/tests/compile/userdata_mut_slice_arg.rs index 1ecc505..4ef8ec7 100644 --- a/tests/compile/userdata_mut_slice_arg.rs +++ b/tests/compile/userdata_mut_slice_arg.rs @@ -1,5 +1,4 @@ -#[derive(Default)] -#[mlua::userdata] +#[derive(Default, mlua::UserData)] struct Foo(Vec); #[mlua::userdata_impl] diff --git a/tests/compile/userdata_mut_slice_arg.stderr b/tests/compile/userdata_mut_slice_arg.stderr index 43780fc..2b763cd 100644 --- a/tests/compile/userdata_mut_slice_arg.stderr +++ b/tests/compile/userdata_mut_slice_arg.stderr @@ -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 { +6 | fn first(&self, data: &mut [u8]) -> mlua::Result { | ^^^^^^^^^ diff --git a/tests/compile/userdata_setter_async.rs b/tests/compile/userdata_setter_async.rs index 4d50e96..180f425 100644 --- a/tests/compile/userdata_setter_async.rs +++ b/tests/compile/userdata_setter_async.rs @@ -1,7 +1,6 @@ use mlua::Result; -#[derive(Clone, Debug)] -#[mlua::userdata] +#[derive(Clone, Debug, mlua::UserData)] struct Foo(u64); #[mlua::userdata_impl] diff --git a/tests/compile/userdata_setter_async.stderr b/tests/compile/userdata_setter_async.stderr index 46ac54b..3125c1a 100644 --- a/tests/compile/userdata_setter_async.stderr +++ b/tests/compile/userdata_setter_async.stderr @@ -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 diff --git a/tests/compile/userdata_setter_no_value.rs b/tests/compile/userdata_setter_no_value.rs index 8334dc7..5218c8d 100644 --- a/tests/compile/userdata_setter_no_value.rs +++ b/tests/compile/userdata_setter_no_value.rs @@ -1,5 +1,4 @@ -#[derive(Default)] -#[mlua::userdata] +#[derive(Default, mlua::UserData)] struct Foo { x: u32, } diff --git a/tests/compile/userdata_setter_no_value.stderr b/tests/compile/userdata_setter_no_value.stderr index b6ce7dc..4b52141 100644 --- a/tests/compile/userdata_setter_no_value.stderr +++ b/tests/compile/userdata_setter_no_value.stderr @@ -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<()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/compile/userdata_setter_ref_self.rs b/tests/compile/userdata_setter_ref_self.rs index afc7572..b88ea1e 100644 --- a/tests/compile/userdata_setter_ref_self.rs +++ b/tests/compile/userdata_setter_ref_self.rs @@ -1,5 +1,4 @@ -#[derive(Default)] -#[mlua::userdata] +#[derive(Default, mlua::UserData)] struct Foo { x: u32, } diff --git a/tests/compile/userdata_setter_ref_self.stderr b/tests/compile/userdata_setter_ref_self.stderr index 49d85cf..d15604f 100644 --- a/tests/compile/userdata_setter_ref_self.stderr +++ b/tests/compile/userdata_setter_ref_self.stderr @@ -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<()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/compile/userdata_static_with_self.rs b/tests/compile/userdata_static_with_self.rs index c97fa4d..ad2ea1d 100644 --- a/tests/compile/userdata_static_with_self.rs +++ b/tests/compile/userdata_static_with_self.rs @@ -1,5 +1,4 @@ -#[derive(Default)] -#[mlua::userdata] +#[derive(Default, mlua::UserData)] struct Foo { x: u32, } diff --git a/tests/compile/userdata_static_with_self.stderr b/tests/compile/userdata_static_with_self.stderr index adc552e..56b4b41 100644 --- a/tests/compile/userdata_static_with_self.stderr +++ b/tests/compile/userdata_static_with_self.stderr @@ -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 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> tests/compile/userdata_static_with_self.rs:9:5 + | +9 | fn get_x(&self) -> mlua::Result { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/userdata_macro.rs b/tests/userdata_macro.rs index b0c5e85..169c924 100644 --- a/tests/userdata_macro.rs +++ b/tests/userdata_macro.rs @@ -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); #[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]