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::ObjectInterface` trait";
9
10pub 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