1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use proc_macro2::TokenStream;
4use proc_macro_error::abort_call_site;
5use quote::quote;
6
7pub const WRONG_PLACE_MSG: &str =
8 "This macro should be used on `impl` block for `glib::ObjectImpl` trait";
9
10pub fn impl_derived_properties(input: &syn::ItemImpl) -> TokenStream {
11 let syn::ItemImpl {
12 attrs,
13 generics,
14 trait_,
15 self_ty,
16 items,
17 ..
18 } = input;
19
20 let trait_path = match &trait_ {
21 Some(path) => &path.1,
22 None => abort_call_site!(WRONG_PLACE_MSG),
23 };
24
25 let mut has_property = false;
26 let mut has_properties = false;
27 let mut has_set_property = false;
28
29 for item in items {
30 if let syn::ImplItem::Fn(method) = item {
31 let ident = &method.sig.ident;
32
33 if ident == "properties" {
34 has_properties = true;
35 } else if ident == "set_property" {
36 has_set_property = true;
37 } else if ident == "property" {
38 has_property = true;
39 }
40 }
41 }
42
43 let crate_ident = crate::utils::crate_ident_new();
44
45 let properties = quote!(
46 fn properties() -> &'static [#crate_ident::ParamSpec] {
47 Self::derived_properties()
48 }
49 );
50
51 let set_property = quote!(
52 fn set_property(&self, id: usize, value: &#crate_ident::Value, pspec: &#crate_ident::ParamSpec) {
53 Self::derived_set_property(self, id, value, pspec)
54 }
55 );
56
57 let property = quote!(
58 fn property(&self, id: usize, pspec: &#crate_ident::ParamSpec) -> #crate_ident::Value {
59 Self::derived_property(self, id, pspec)
60 }
61 );
62
63 let generated = [
64 (!has_properties).then_some(properties),
65 (!has_set_property).then_some(set_property),
66 (!has_property).then_some(property),
67 ];
68
69 quote!(
70 #(#attrs)*
71 impl #generics #trait_path for #self_ty {
72 #(#items)*
73 #(#generated)*
74 }
75 )
76}
77