Skip to content

Commit b7c98ad

Browse files
committed
mlua_derive: Switch from #[userdata] to [derive(UserData)]
1 parent 1f3dafa commit b7c98ad

33 files changed

Lines changed: 85 additions & 131 deletions

examples/userdata.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
use mlua::{Lua, Result, chunk};
1+
use mlua::{Lua, Result, UserData, chunk};
22

3-
#[derive(Default)]
4-
#[mlua::userdata]
3+
#[derive(Default, UserData)]
54
struct Rectangle {
65
length: u32,
76
width: u32,

mlua_derive/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ pub fn from_lua(input: TokenStream) -> TokenStream {
3333
from_lua::from_lua(input)
3434
}
3535

36-
/// Attribute macro for exposing a Rust type as a Lua userdata.
36+
/// Derive macro for implementing `UserData` for a Rust type.
3737
#[cfg(feature = "macros")]
38-
#[proc_macro_attribute]
39-
pub fn userdata(attr: TokenStream, item: TokenStream) -> TokenStream {
40-
userdata::userdata_type(attr, item)
38+
#[proc_macro_derive(UserData, attributes(lua))]
39+
pub fn userdata(item: TokenStream) -> TokenStream {
40+
userdata::userdata_type(item)
4141
}
4242

4343
/// Attribute macro for exposing impl block methods to Lua userdata.

mlua_derive/src/userdata/mod.rs

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -34,35 +34,18 @@ fn parse_field_lua_attr(attrs: &[Attribute]) -> syn::Result<LuaAttr> {
3434
Ok(lua_attr)
3535
}
3636

37-
/// Strip `#[lua(...)]` attributes from a field, keeping all others.
38-
fn strip_lua_attrs(attrs: &[Attribute]) -> Vec<Attribute> {
39-
(attrs.iter())
40-
.filter(|attr| !attr.path().is_ident("lua"))
41-
.cloned()
42-
.collect()
43-
}
44-
45-
pub fn userdata_type(attr: TokenStream, item: TokenStream) -> TokenStream {
46-
if !attr.is_empty() {
47-
return Error::new_spanned(
48-
proc_macro2::TokenStream::from(attr),
49-
"`#[userdata]` does not accept arguments",
50-
)
51-
.to_compile_error()
52-
.into();
53-
}
54-
55-
let mut input = parse_macro_input!(item as DeriveInput);
37+
pub fn userdata_type(item: TokenStream) -> TokenStream {
38+
let input = parse_macro_input!(item as DeriveInput);
5639
let type_name = &input.ident;
5740

58-
let mut named_fields: Option<&mut FieldsNamed> = match &mut input.data {
59-
Data::Struct(data) => match &mut data.fields {
41+
let named_fields: Option<&FieldsNamed> = match &input.data {
42+
Data::Struct(data) => match &data.fields {
6043
Fields::Named(fields) => Some(fields),
6144
Fields::Unnamed(_) | Fields::Unit => None,
6245
},
6346
Data::Enum(_) => None,
6447
Data::Union(_) => {
65-
return Error::new_spanned(&input, "`#[userdata]` cannot be applied to unions")
48+
return Error::new_spanned(&input, "`#[derive(UserData)]` cannot be applied to unions")
6649
.to_compile_error()
6750
.into();
6851
}
@@ -73,14 +56,14 @@ pub fn userdata_type(attr: TokenStream, item: TokenStream) -> TokenStream {
7356
if has_type_params {
7457
return Error::new_spanned(
7558
&input.generics,
76-
"`#[userdata]` does not support generic type parameters. Wrap the generic type in a concrete newtype instead."
59+
"`#[derive(UserData)]` does not support generic type parameters. Wrap the generic type in a concrete newtype instead."
7760
)
7861
.to_compile_error()
7962
.into();
8063
}
8164

8265
let mut field_registrations = Vec::new();
83-
if let Some(fields) = &mut named_fields {
66+
if let Some(fields) = &named_fields {
8467
for field in &fields.named {
8568
let field_name = field.ident.as_ref().unwrap();
8669

@@ -114,19 +97,12 @@ pub fn userdata_type(attr: TokenStream, item: TokenStream) -> TokenStream {
11497
field_registrations.push(with_cfg(tokens, &field.attrs));
11598
}
11699
}
117-
118-
// Strip mlua-specific attributes from fields before re-emitting
119-
for field in &mut fields.named {
120-
field.attrs = strip_lua_attrs(&field.attrs);
121-
}
122100
}
123101

124102
let registration_type_name = format_ident!("__MluaUserDataRegistration_{type_name}");
125103
let register_fields_fn_name = format_ident!("__mlua_register_{type_name}_fields");
126104

127105
let output = quote! {
128-
#input
129-
130106
#[doc(hidden)]
131107
#[allow(non_camel_case_types)]
132108
struct #registration_type_name {

src/lib.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -233,16 +233,14 @@ pub use mlua_derive::chunk;
233233
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
234234
pub use mlua_derive::FromLua;
235235

236-
/// Attribute macro for exposing a struct as Lua userdata.
236+
/// Derive macro for implementing [`UserData`] for a Rust type.
237237
///
238-
/// All fields are auto-exposed as get/set.
238+
/// Named fields are auto-exposed as get/set.
239239
///
240240
/// Use `#[lua(...)]` to customize.
241-
///
242-
/// This generates a [`UserData`] trait implementation.
243241
#[cfg(feature = "macros")]
244242
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
245-
pub use mlua_derive::userdata;
243+
pub use mlua_derive::UserData;
246244

247245
/// Attribute macro for exposing impl block methods to Lua userdata.
248246
///

tests/compile/userdata_const_getter.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
#[derive(Default)]
2-
#[mlua::userdata]
1+
#[derive(Default, mlua::UserData)]
32
struct Foo;
43

54
#[mlua::userdata_impl]
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: const items do not support `getter` or `setter`
2-
--> tests/compile/userdata_const_getter.rs:8:11
2+
--> tests/compile/userdata_const_getter.rs:7:11
33
|
4-
8 | const X: u32 = 42;
4+
7 | const X: u32 = 42;
55
| ^

tests/compile/userdata_field_async.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use mlua::Result;
22

3-
#[derive(Clone, Debug)]
4-
#[mlua::userdata]
3+
#[derive(Clone, Debug, mlua::UserData)]
54
struct Foo;
65

76
#[mlua::userdata_impl]

tests/compile/userdata_field_async.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error: async field function is not supported
2-
--> tests/compile/userdata_field_async.rs:10:5
3-
|
4-
10 | async fn description() -> Result<String> {
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2+
--> tests/compile/userdata_field_async.rs:9:5
3+
|
4+
9 | async fn description() -> Result<String> {
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66

77
warning: unused import: `mlua::Result`
88
--> tests/compile/userdata_field_async.rs:1:5

tests/compile/userdata_field_with_args.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
#[derive(Default)]
2-
#[mlua::userdata]
1+
#[derive(Default, mlua::UserData)]
32
struct Foo {
43
x: u32,
54
}
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: field function must not take arguments
2-
--> tests/compile/userdata_field_with_args.rs:10:5
3-
|
4-
10 | fn as_name(name: &str) -> String {
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2+
--> tests/compile/userdata_field_with_args.rs:9:5
3+
|
4+
9 | fn as_name(name: &str) -> String {
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

0 commit comments

Comments
 (0)