Made the impl_device macro more explicit about the implemented traits

This also converts impl_device into a procedural macro and get rid of a
lot of "magic" that was happening.
This commit is contained in:
2025-08-28 03:02:45 +02:00
parent c5262dcf35
commit d2b01123b8
26 changed files with 197 additions and 208 deletions

View File

@@ -0,0 +1,70 @@
use proc_macro::TokenStream;
use quote::quote;
use syn::parse::Parse;
use syn::punctuated::Punctuated;
use syn::{Path, Token, parse_macro_input};
struct ImplDevice {
ty: Path,
impls: Option<Punctuated<Path, Token![,]>>,
}
impl Parse for ImplDevice {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let ty = input.parse()?;
let impls = if input.peek(Token![->]) {
input.parse::<Token![->]>()?;
Some(input.parse_terminated(Path::parse, Token![,])?)
} else {
None
};
Ok(ImplDevice { ty, impls })
}
}
pub fn impl_device_macro(input: proc_macro::TokenStream) -> TokenStream {
let ImplDevice { ty, impls } = parse_macro_input!(input as ImplDevice);
let impls: Vec<_> = impls
.iter()
.flatten()
.map(|i| {
let ident = i
.segments
.last()
.expect("There should be at least one segment")
.ident
.clone();
quote! {
::automation_lib::lua::traits::#ident::add_methods(methods);
}
})
.collect();
quote! {
impl mlua::UserData for #ty {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
methods.add_async_function("new", |_lua, config| async {
let device: #ty = LuaDeviceCreate::create(config)
.await
.map_err(mlua::ExternalError::into_lua_err)?;
Ok(device)
});
methods.add_method("__box", |_lua, this, _: ()| {
let b: Box<dyn Device> = Box::new(this.clone());
Ok(b)
});
methods.add_async_method("get_id", |_lua, this, _: ()| async move { Ok(this.get_id()) });
#(
#impls
)*
}
}
}.into()
}

View File

@@ -1,12 +1,20 @@
#![feature(iter_intersperse)]
mod impl_device;
mod lua_device_config;
use lua_device_config::impl_lua_device_config_macro;
use syn::{DeriveInput, parse_macro_input};
use crate::impl_device::impl_device_macro;
#[proc_macro_derive(LuaDeviceConfig, attributes(device_config))]
pub fn lua_device_config_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
impl_lua_device_config_macro(&ast).into()
}
#[proc_macro]
pub fn impl_device(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
impl_device_macro(input)
}