dbus_async_derive/
lib.rs

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
24/// Try to derive
25fn 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/// The derive method.
103#[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}