glib_macros/
derived_properties_attribute.rs

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
// Take a look at the license at the top of the repository in the LICENSE file.

use proc_macro2::{Span, TokenStream};
use quote::quote;

pub const WRONG_PLACE_MSG: &str =
    "This macro should be used on `impl` block for `glib::ObjectImpl` trait";

pub fn impl_derived_properties(input: &syn::ItemImpl) -> syn::Result<TokenStream> {
    let syn::ItemImpl {
        attrs,
        generics,
        trait_,
        self_ty,
        items,
        ..
    } = input;

    let trait_path = &trait_
        .as_ref()
        .ok_or_else(|| syn::Error::new(Span::call_site(), WRONG_PLACE_MSG))?
        .1;

    let mut has_property = false;
    let mut has_properties = false;
    let mut has_set_property = false;

    for item in items {
        if let syn::ImplItem::Fn(method) = item {
            let ident = &method.sig.ident;

            if ident == "properties" {
                has_properties = true;
            } else if ident == "set_property" {
                has_set_property = true;
            } else if ident == "property" {
                has_property = true;
            }
        }
    }

    let crate_ident = crate::utils::crate_ident_new();

    let properties = quote!(
        fn properties() -> &'static [#crate_ident::ParamSpec] {
            Self::derived_properties()
        }
    );

    let set_property = quote!(
        fn set_property(&self, id: usize, value: &#crate_ident::Value, pspec: &#crate_ident::ParamSpec) {
            Self::derived_set_property(self, id, value, pspec)
        }
    );

    let property = quote!(
        fn property(&self, id: usize, pspec: &#crate_ident::ParamSpec) -> #crate_ident::Value {
            Self::derived_property(self, id, pspec)
        }
    );

    let generated = [
        (!has_properties).then_some(properties),
        (!has_set_property).then_some(set_property),
        (!has_property).then_some(property),
    ];

    Ok(quote!(
        #(#attrs)*
        impl #generics #trait_path for #self_ty {
            #(#items)*
            #(#generated)*
        }
    ))
}