1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use proc_macro2::TokenStream; |
4 | use proc_macro_error::abort_call_site; |
5 | use quote::quote; |
6 | |
7 | pub const WRONG_PLACE_MSG: &str = |
8 | "This macro should be used on `impl` block for `glib::ObjectInterface` trait" ; |
9 | |
10 | pub fn impl_object_interface(input: &syn::ItemImpl) -> TokenStream { |
11 | let mut has_prerequisites = false; |
12 | for item in &input.items { |
13 | if let syn::ImplItem::Type(type_) = item { |
14 | let name = type_.ident.to_string(); |
15 | if name == "Prerequisites" { |
16 | has_prerequisites = true; |
17 | } |
18 | } |
19 | } |
20 | |
21 | let syn::ItemImpl { |
22 | attrs, |
23 | generics, |
24 | trait_, |
25 | self_ty, |
26 | unsafety, |
27 | items, |
28 | .. |
29 | } = &input; |
30 | |
31 | let prerequisites_opt = if has_prerequisites { |
32 | None |
33 | } else { |
34 | Some(quote!( |
35 | type Prerequisites = (); |
36 | )) |
37 | }; |
38 | |
39 | let crate_ident = crate::utils::crate_ident_new(); |
40 | |
41 | let trait_path = match &trait_ { |
42 | Some(path) => &path.1, |
43 | None => abort_call_site!(WRONG_PLACE_MSG), |
44 | }; |
45 | |
46 | quote! { |
47 | #(#attrs)* |
48 | #unsafety impl #generics #trait_path for #self_ty { |
49 | #prerequisites_opt |
50 | #(#items)* |
51 | } |
52 | |
53 | unsafe impl #crate_ident::subclass::interface::ObjectInterfaceType for #self_ty { |
54 | #[inline] |
55 | fn type_() -> #crate_ident::Type { |
56 | static ONCE: ::std::sync::Once = ::std::sync::Once::new(); |
57 | static mut TYPE: #crate_ident::Type = #crate_ident::Type::INVALID; |
58 | |
59 | ONCE.call_once(|| { |
60 | let type_ = #crate_ident::subclass::register_interface::<Self>(); |
61 | unsafe { |
62 | TYPE = type_; |
63 | } |
64 | }); |
65 | |
66 | unsafe { |
67 | TYPE |
68 | } |
69 | } |
70 | } |
71 | } |
72 | } |
73 | |