1#![recursion_limit = "256"]
2extern crate proc_macro;
3
4mod code;
5mod helper;
6mod interface;
7mod introspectable;
8mod method;
9mod properties;
10mod property;
11mod signal;
12mod signature;
13
14use crate::code::{get_interface_from_header, unknown_interface_from_header};
15use crate::helper::{get_ident_from_path, get_meta_list_from_meta};
16use crate::interface::Interface;
17use crate::introspectable::{create_introspectable_code, parse_introspectable};
18use crate::properties::create_properties_code;
19use proc_macro::TokenStream;
20use quote::quote;
21use std::convert::TryFrom;
22use syn::{parse_macro_input, DeriveInput, Error as SynError, Result as SynResult};
23
24fn try_derive(ast: DeriveInput) -> SynResult<TokenStream> {
26 let struct_name = ast.ident;
27 let mut introspectable = None;
28 let mut interfaces = Vec::new();
29 for attribute in ast.attrs {
30 let meta = attribute.parse_meta()?;
31 let meta_list = get_meta_list_from_meta(&meta)?;
32 let meta_list_type = get_ident_from_path(&meta_list.path)?;
33 match meta_list_type.to_string().as_ref() {
34 "interface" => interfaces.push(Interface::try_from(meta_list)?),
35 "introspectable" => {
36 if introspectable.is_some() {
37 return Err(SynError::new(
38 meta_list_type.span(),
39 "Introspectable is defined multiple times",
40 ));
41 } else {
42 let boolean = parse_introspectable(meta_list)?;
43 introspectable = Some(boolean);
44 }
45 }
46 attribute => {
47 return Err(SynError::new(
48 meta_list_type.span(),
49 format!("Unknown attribute: {}", attribute),
50 ))
51 }
52 }
53 }
54
55 let introspectable = if let Some(introspectable) = introspectable {
56 introspectable
57 } else {
58 true
59 };
60
61 let mut interfaces_code = Vec::new();
62
63 let have_properties = match create_properties_code(&interfaces) {
64 Some(code) => {
65 interfaces_code.push(code);
66 true
67 }
68 None => false,
69 };
70
71 if introspectable {
72 interfaces_code.push(create_introspectable_code(&interfaces, have_properties));
73 }
74
75 for interface in &interfaces {
76 if let Some(code) = interface.create_methods_code() {
77 interfaces_code.push(code);
78 }
79 }
80
81 let get_interface_from_header = get_interface_from_header();
82 let unknown_interface_from_header = unknown_interface_from_header();
83 let code = quote! {
84 #[async_trait::async_trait]
85 impl dbus_async::Handler for #struct_name {
86 async fn handle(&mut self, dbus: &dbus_async::DBus, msg: dbus_message_parser::Message) -> dbus_async::DBusResult<()> {
87 if msg.get_type() != dbus_message_parser::MessageType::MethodCall {
88 return Ok(())
89 }
90 let (header, body) = msg.split();
91 let mut body_iter = body.into_iter();
92 match #get_interface_from_header {
93 #(#interfaces_code)*
94 _ => #unknown_interface_from_header
95 }
96 }
97 }
98 };
99 Ok(code.into())
100}
101
102#[proc_macro_derive(Handler, attributes(interface, introspectable))]
104pub fn derive(input: TokenStream) -> TokenStream {
105 let ast = parse_macro_input!(input as DeriveInput);
106 match try_derive(ast) {
107 Ok(token) => token,
108 Err(e) => e.to_compile_error().into(),
109 }
110}