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