glib_macros/
object_impl_attributes.rs1pub mod interface;
4pub mod subclass;
5
6use proc_macro2::Span;
7
8use crate::utils::{parse_optional_nested_meta_items, NestedMetaItem};
9
10enum AttrKind {
12    Interface,
13    Subclass,
14}
15
16pub struct Input {
20    attrs: Vec<syn::Attribute>,
21    generics: syn::Generics,
22    trait_path: syn::Path,
23    self_ty: syn::Ident,
24    unsafety: Option<syn::token::Unsafe>,
25    items: Vec<syn::ImplItem>,
26    meta_dynamic: Option<MetaDynamic>,
27}
28
29impl Input {
30    pub fn parse_interface(input: syn::parse::ParseStream) -> syn::Result<Self> {
32        Self::parse(AttrKind::Interface, input)
33    }
34
35    pub fn parse_subclass(input: syn::parse::ParseStream) -> syn::Result<Self> {
37        Self::parse(AttrKind::Subclass, input)
38    }
39
40    fn parse(kind: AttrKind, input: syn::parse::ParseStream) -> syn::Result<Self> {
42        let wrong_place_msg = match kind {
43            AttrKind::Interface => {
44                "This macro should be used on `impl` block for `glib::ObjectInterface` trait"
45            }
46            AttrKind::Subclass => {
47                "This macro should be used on `impl` block for `glib::ObjectSubclass` trait"
48            }
49        };
50
51        let syn::ItemImpl {
52            mut attrs,
53            generics,
54            trait_,
55            self_ty,
56            unsafety,
57            items,
58            ..
59        } = input
60            .parse()
61            .map_err(|_| syn::Error::new(Span::call_site(), wrong_place_msg))?;
62
63        let self_ty = match *self_ty {
65            syn::Type::Path(syn::TypePath { path, .. }) => path.require_ident().cloned(),
66            _ => Err(syn::Error::new(
67                syn::spanned::Spanned::span(&self_ty),
68                "expected this path to be an identifier",
69            )),
70        }?;
71
72        let meta_dynamic = MetaDynamic::parse_and_remove(kind, &mut attrs)?;
73
74        let trait_path = trait_
75            .as_ref()
76            .ok_or_else(|| syn::Error::new(Span::call_site(), wrong_place_msg))?
77            .1
78            .clone();
79
80        Ok(Self {
81            attrs,
82            generics,
83            trait_path,
84            self_ty,
85            unsafety,
86            items,
87            meta_dynamic,
88        })
89    }
90}
91
92struct MetaDynamic {
98    plugin_type: Option<syn::Path>,
99    lazy_registration: bool,
100}
101
102impl MetaDynamic {
103    fn parse_and_remove(
105        kind: AttrKind,
106        attrs: &mut Vec<syn::Attribute>,
107    ) -> syn::Result<Option<Self>> {
108        let attr_name = match kind {
109            AttrKind::Interface => "object_interface_dynamic",
110            AttrKind::Subclass => "object_subclass_dynamic",
111        };
112
113        let mut plugin_type = NestedMetaItem::<syn::Path>::new("plugin_type").value_required();
114        let mut lazy_registration =
115            NestedMetaItem::<syn::LitBool>::new("lazy_registration").value_required();
116
117        let found = parse_optional_nested_meta_items(
118            &*attrs,
119            attr_name,
120            &mut [&mut plugin_type, &mut lazy_registration],
121        )?
122        .is_some();
123
124        if found {
125            attrs.retain(|attr| !attr.path().is_ident(attr_name));
127
128            Ok(Some(Self {
129                plugin_type: plugin_type.value,
130                lazy_registration: lazy_registration.value.map(|b| b.value).unwrap_or_default(),
131            }))
132        } else {
133            Ok(None)
134        }
135    }
136}