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