Skip to content

Commit 0670577

Browse files
committed
glib-macros: Refactor parsing code of object_subclass/object_interface
Separates the parsing code from codegen, and unifies the parsing code to one implementation.
1 parent dc264f6 commit 0670577

File tree

4 files changed

+184
-128
lines changed

4 files changed

+184
-128
lines changed

glib-macros/src/lib.rs

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ mod downgrade_derive;
88
mod enum_derive;
99
mod error_domain_derive;
1010
mod flags_attribute;
11-
mod object_interface_attribute;
12-
mod object_subclass_attribute;
11+
mod object_impl_attributes;
1312
mod properties;
1413
mod shared_boxed_derive;
1514
mod value_delegate_derive;
@@ -906,16 +905,8 @@ pub fn shared_boxed_derive(input: TokenStream) -> TokenStream {
906905
/// [`TypePluginExt::unuse`]: ../glib/gobject/type_plugin/trait.TypePluginExt.html#method.unuse
907906
#[proc_macro_attribute]
908907
pub fn object_subclass(_attr: TokenStream, item: TokenStream) -> TokenStream {
909-
syn::parse::<syn::ItemImpl>(item)
910-
.map_err(|_| {
911-
syn::Error::new(
912-
Span::call_site(),
913-
object_subclass_attribute::WRONG_PLACE_MSG,
914-
)
915-
})
916-
.and_then(|mut input| object_subclass_attribute::impl_object_subclass(&mut input))
917-
.unwrap_or_else(syn::Error::into_compile_error)
918-
.into()
908+
let input = parse_macro_input!(item with object_impl_attributes::Input::parse_subclass);
909+
object_impl_attributes::subclass::impl_object_subclass(input).into()
919910
}
920911

921912
/// Macro for boilerplate of [`ObjectInterface`] implementations.
@@ -1024,16 +1015,8 @@ pub fn object_subclass(_attr: TokenStream, item: TokenStream) -> TokenStream {
10241015
/// [`TypePluginExt::unuse`]: ../glib/gobject/type_plugin/trait.TypePluginExt.html#method.unuse///
10251016
#[proc_macro_attribute]
10261017
pub fn object_interface(_attr: TokenStream, item: TokenStream) -> TokenStream {
1027-
syn::parse::<syn::ItemImpl>(item)
1028-
.map_err(|_| {
1029-
syn::Error::new(
1030-
Span::call_site(),
1031-
object_interface_attribute::WRONG_PLACE_MSG,
1032-
)
1033-
})
1034-
.and_then(|mut input| object_interface_attribute::impl_object_interface(&mut input))
1035-
.unwrap_or_else(syn::Error::into_compile_error)
1036-
.into()
1018+
let input = parse_macro_input!(item with object_impl_attributes::Input::parse_interface);
1019+
object_impl_attributes::interface::impl_object_interface(input).into()
10371020
}
10381021

10391022
/// Macro for deriving implementations of [`glib::clone::Downgrade`] and
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
// Take a look at the license at the top of the repository in the LICENSE file.
2+
3+
pub mod interface;
4+
pub mod subclass;
5+
6+
use proc_macro2::Span;
7+
8+
use crate::utils::{parse_optional_nested_meta_items, NestedMetaItem};
9+
10+
/// The parsing of `#[object_subclass]` and `#[object_interface]` is subtly different.
11+
enum AttrKind {
12+
Interface,
13+
Subclass,
14+
}
15+
16+
/// The parsed input for the object impl attributes..
17+
///
18+
/// This is used for both the `#[object_subclass]` and `#[object_interface]` attributes.
19+
pub 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+
29+
impl Input {
30+
/// Parse an `#[object_interface]` attribute.
31+
pub fn parse_interface(input: syn::parse::ParseStream) -> syn::Result<Self> {
32+
Self::parse(AttrKind::Interface, input)
33+
}
34+
35+
/// Parse an `#[object_subclass]` attribute.
36+
pub fn parse_subclass(input: syn::parse::ParseStream) -> syn::Result<Self> {
37+
Self::parse(AttrKind::Subclass, input)
38+
}
39+
40+
/// Parse an `#[object_subclass]` or `#[object_interface]` depending on the attribute kind.
41+
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+
// The type must be a path
64+
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+
92+
/// A meta attribute to indicate that the class / interface is dynamic.
93+
///
94+
/// Depending on the object kind this can be either
95+
/// - `#[object_subclass_dynamic]`
96+
/// - `#[object_interface_dynamic]`
97+
struct MetaDynamic {
98+
plugin_type: Option<syn::Path>,
99+
lazy_registration: bool,
100+
}
101+
102+
impl MetaDynamic {
103+
/// Parse `#[object_subclass_dynamic]` / `#[object_interface_dynamic]`
104+
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+
// remove attribute from the attribute list because it is not a real proc_macro_attribute
126+
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+
}

glib-macros/src/object_interface_attribute.rs renamed to glib-macros/src/object_impl_attributes/interface.rs

Lines changed: 20 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,34 @@
11
// Take a look at the license at the top of the repository in the LICENSE file.
22

33
use heck::ToShoutySnakeCase;
4-
use proc_macro2::{Span, TokenStream};
4+
use proc_macro2::TokenStream;
55
use quote::{format_ident, quote, ToTokens};
66

7-
use crate::utils::{parse_optional_nested_meta_items, NestedMetaItem};
8-
9-
pub const WRONG_PLACE_MSG: &str =
10-
"This macro should be used on `impl` block for `glib::ObjectInterface` trait";
11-
12-
pub fn impl_object_interface(input: &mut syn::ItemImpl) -> syn::Result<TokenStream> {
7+
pub fn impl_object_interface(input: super::Input) -> TokenStream {
138
let crate_ident = crate::utils::crate_ident_new();
14-
let syn::ItemImpl {
9+
let super::Input {
1510
attrs,
1611
generics,
17-
trait_,
12+
trait_path,
1813
self_ty,
1914
unsafety,
2015
items,
21-
..
16+
meta_dynamic,
2217
} = input;
2318

24-
let self_ty_as_ident = match &**self_ty {
25-
syn::Type::Path(syn::TypePath { path, .. }) => path.require_ident(),
26-
_ => Err(syn::Error::new_spanned(
19+
let register_object_interface = if let Some(dynamic) = meta_dynamic {
20+
let plugin_ty = dynamic
21+
.plugin_type
22+
.map(|p| p.into_token_stream())
23+
.unwrap_or(quote!(#crate_ident::TypeModule));
24+
register_object_interface_as_dynamic(
25+
&crate_ident,
2726
&self_ty,
28-
"expected this path to be an identifier",
29-
)),
30-
}?;
31-
32-
let mut plugin_type = NestedMetaItem::<syn::Path>::new("plugin_type").value_required();
33-
let mut lazy_registration =
34-
NestedMetaItem::<syn::LitBool>::new("lazy_registration").value_required();
35-
36-
let found = parse_optional_nested_meta_items(
37-
&*attrs,
38-
"object_interface_dynamic",
39-
&mut [&mut plugin_type, &mut lazy_registration],
40-
)?;
41-
42-
let register_object_interface = match found {
43-
None => register_object_interface_as_static(&crate_ident, self_ty_as_ident),
44-
Some(_) => {
45-
// remove attribute 'object_interface_dynamic' from the attribute list because it is not a real proc_macro_attribute
46-
attrs.retain(|attr| !attr.path().is_ident("object_interface_dynamic"));
47-
let plugin_ty = plugin_type
48-
.value
49-
.map(|p| p.into_token_stream())
50-
.unwrap_or(quote!(#crate_ident::TypeModule));
51-
let lazy_registration = lazy_registration.value.map(|b| b.value).unwrap_or_default();
52-
register_object_interface_as_dynamic(
53-
&crate_ident,
54-
self_ty_as_ident,
55-
plugin_ty,
56-
lazy_registration,
57-
)
58-
}
27+
&plugin_ty,
28+
dynamic.lazy_registration,
29+
)
30+
} else {
31+
register_object_interface_as_static(&crate_ident, &self_ty)
5932
};
6033

6134
let mut has_prerequisites = false;
@@ -76,12 +49,7 @@ pub fn impl_object_interface(input: &mut syn::ItemImpl) -> syn::Result<TokenStre
7649
))
7750
};
7851

79-
let trait_path = &trait_
80-
.as_ref()
81-
.ok_or_else(|| syn::Error::new(Span::call_site(), WRONG_PLACE_MSG))?
82-
.1;
83-
84-
Ok(quote! {
52+
quote! {
8553
#(#attrs)*
8654
#unsafety impl #generics #trait_path for #self_ty {
8755
#prerequisites_opt
@@ -96,7 +64,7 @@ pub fn impl_object_interface(input: &mut syn::ItemImpl) -> syn::Result<TokenStre
9664
}
9765

9866
#register_object_interface
99-
})
67+
}
10068
}
10169

10270
// Registers the object interface as a static type.
@@ -124,7 +92,7 @@ fn register_object_interface_as_static(
12492
fn register_object_interface_as_dynamic(
12593
crate_ident: &TokenStream,
12694
self_ty: &syn::Ident,
127-
plugin_ty: TokenStream,
95+
plugin_ty: &TokenStream,
12896
lazy_registration: bool,
12997
) -> TokenStream {
13098
// The following implementations follows the lifecycle of plugins and of dynamic types (see [`TypePluginExt`] and [`TypeModuleExt`]).

0 commit comments

Comments
 (0)