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:
70
automation_macro/src/impl_device.rs
Normal file
70
automation_macro/src/impl_device.rs
Normal 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()
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user