Add #[derive(FromLua)] macro to opt-in into FromLua<T> where T: 'static + Clone (userdata type).

Future macro implementations will allow making T from Lua tables/other values.
Relates to #291.
This commit is contained in:
Alex Orlenko
2023-07-16 01:57:28 +01:00
parent 355a0606c3
commit 0e030d21b0
4 changed files with 84 additions and 0 deletions
+32
View File
@@ -0,0 +1,32 @@
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
pub fn from_lua(input: TokenStream) -> TokenStream {
let DeriveInput {
ident, generics, ..
} = parse_macro_input!(input as DeriveInput);
let where_clause = match &generics.where_clause {
Some(where_clause) => quote! { #where_clause, Self: 'static + Clone },
None => quote! { where Self: 'static + Clone },
};
let ident_str = ident.to_string();
quote! {
impl #generics ::mlua::FromLua<'_> for #ident #generics #where_clause {
#[inline]
fn from_lua(value: ::mlua::Value<'_>, lua: &'_ ::mlua::Lua) -> ::mlua::Result<Self> {
match value {
::mlua::Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
_ => Err(::mlua::Error::FromLuaConversionError {
from: value.type_name(),
to: #ident_str,
message: None,
}),
}
}
}
}
.into()
}
+8
View File
@@ -148,7 +148,15 @@ pub fn chunk(input: TokenStream) -> TokenStream {
wrapped_code.into()
}
#[cfg(feature = "macros")]
#[proc_macro_derive(FromLua)]
pub fn from_lua(input: TokenStream) -> TokenStream {
from_lua::from_lua(input)
}
#[cfg(feature = "macros")]
mod chunk;
#[cfg(feature = "macros")]
mod from_lua;
#[cfg(feature = "macros")]
mod token;
+8
View File
@@ -216,6 +216,14 @@ pub use crate::{
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
pub use mlua_derive::chunk;
/// Derive [`FromLua`] for a Rust type.
///
/// Current implementation generate code that takes [`UserData`] value, borrow it (of the Rust type)
/// and clone.
#[cfg(feature = "macros")]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
pub use mlua_derive::FromLua;
/// Registers Lua module entrypoint.
///
/// You can register multiple entrypoints as required.
+36
View File
@@ -908,3 +908,39 @@ fn test_owned_userdata() -> Result<()> {
Ok(())
}
#[cfg(feature = "macros")]
#[test]
fn test_userdata_derive() -> Result<()> {
let lua = Lua::new();
// Simple struct
#[derive(Clone, Copy, mlua::FromLua)]
struct MyUserData(i32);
lua.register_userdata_type::<MyUserData>(|reg| {
reg.add_function("val", |_, this: MyUserData| Ok(this.0));
})?;
lua.globals()
.set("ud", AnyUserData::wrap(MyUserData(123)))?;
lua.load("assert(ud:val() == 123)").exec()?;
// More complex struct where generics and where clause
#[derive(Clone, Copy, mlua::FromLua)]
struct MyUserData2<'a, T>(&'a T)
where
T: ?Sized;
lua.register_userdata_type::<MyUserData2<'static, i32>>(|reg| {
reg.add_function("val", |_, this: MyUserData2<'static, i32>| Ok(*this.0));
})?;
lua.globals()
.set("ud", AnyUserData::wrap(MyUserData2(&321)))?;
lua.load("assert(ud:val() == 321)").exec()?;
Ok(())
}