Skip to content

Commit e9c8665

Browse files
committed
impl getters/setters directly on concrete type
1 parent 4a8a870 commit e9c8665

File tree

3 files changed

+44
-62
lines changed

3 files changed

+44
-62
lines changed

glib-macros/src/lib.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,7 @@ pub fn cstr_bytes(item: TokenStream) -> TokenStream {
843843
/// use super::*;
844844
///
845845
/// #[derive(Properties, Default)]
846+
/// #[properties(wrapper_type = super::Foo)]
846847
/// pub struct Foo {
847848
/// #[property(get, set = Self::set_fizz)]
848849
/// fizz: RefCell<String>,
@@ -896,8 +897,6 @@ pub fn cstr_bytes(item: TokenStream) -> TokenStream {
896897
/// pub struct Foo(ObjectSubclass<imp::Foo>);
897898
/// }
898899
///
899-
/// use imp::FooPropertiesExt;
900-
///
901900
/// fn main() {
902901
/// let myfoo: Foo = glib::object::Object::new(&[]).unwrap();
903902
///
@@ -906,7 +905,7 @@ pub fn cstr_bytes(item: TokenStream) -> TokenStream {
906905
/// }
907906
/// ```
908907
#[allow(clippy::needless_doctest_main)]
909-
#[proc_macro_derive(Properties, attributes(property))]
908+
#[proc_macro_derive(Properties, attributes(properties, property))]
910909
pub fn derive_props(input: TokenStream) -> TokenStream {
911910
let input = parse_macro_input!(input as properties::PropsMacroInput);
912911
properties::impl_derive_props(input)

glib-macros/src/properties.rs

Lines changed: 41 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,36 @@ use syn::spanned::Spanned;
1414
use syn::Token;
1515

1616
pub struct PropsMacroInput {
17+
wrapper_ty: syn::Path,
1718
ident: syn::Ident,
1819
props: Vec<PropDesc>,
1920
}
2021

22+
pub struct PropertiesAttr {
23+
_wrapper_ty_token: syn::Ident,
24+
_eq: Token![=],
25+
wrapper_ty: syn::Path,
26+
}
27+
28+
impl Parse for PropertiesAttr {
29+
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
30+
Ok(Self {
31+
_wrapper_ty_token: input.parse()?,
32+
_eq: input.parse()?,
33+
wrapper_ty: input.parse()?,
34+
})
35+
}
36+
}
37+
2138
impl Parse for PropsMacroInput {
2239
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
2340
let derive_input: syn::DeriveInput = input.parse()?;
41+
let wrapper_ty = derive_input
42+
.attrs
43+
.iter()
44+
.find(|x| x.path.is_ident("properties"))
45+
.expect("missing #[properties(wrapper_type = ...)]");
46+
let wrapper_ty: PropertiesAttr = wrapper_ty.parse_args()?;
2447
let props: Vec<_> = match derive_input.data {
2548
syn::Data::Struct(struct_data) => parse_fields(struct_data.fields)?,
2649
_ => {
@@ -31,6 +54,7 @@ impl Parse for PropsMacroInput {
3154
}
3255
};
3356
Ok(Self {
57+
wrapper_ty: wrapper_ty.wrapper_ty,
3458
ident: derive_input.ident,
3559
props,
3660
})
@@ -454,28 +478,6 @@ fn name_to_ident(name: &syn::LitStr) -> syn::Ident {
454478
format_ident!("{}", name.value().replace('-', "_"))
455479
}
456480

457-
fn getter_prototype(ident: &syn::Ident, ty: &syn::Type) -> TokenStream2 {
458-
let crate_ident = crate_ident_new();
459-
quote!(fn #ident(&self) -> <#ty as #crate_ident::Property>::Value)
460-
}
461-
fn setter_prototype(ident: &syn::Ident, ty: &syn::Type) -> TokenStream2 {
462-
let crate_ident = crate_ident_new();
463-
let ident = format_ident!("set_{}", ident);
464-
quote!(fn #ident(&self, value: &<<#ty as #crate_ident::Property>::Value as #crate_ident::HasParamSpec>::SetValue))
465-
}
466-
fn expand_getset_properties_def(props: &[PropDesc]) -> TokenStream2 {
467-
let defs = props
468-
.iter()
469-
.flat_map(|p| {
470-
let ident = name_to_ident(&p.name);
471-
let getter = p.get.is_some().then(|| getter_prototype(&ident, &p.ty));
472-
let setter = p.set.is_some().then(|| setter_prototype(&ident, &p.ty));
473-
[getter, setter]
474-
})
475-
.flatten();
476-
quote!(#(#defs;)*)
477-
}
478-
479481
fn expand_getset_properties_impl(props: &[PropDesc]) -> TokenStream2 {
480482
let crate_ident = crate_ident_new();
481483
let defs = props.iter().map(|p| {
@@ -485,12 +487,16 @@ fn expand_getset_properties_impl(props: &[PropDesc]) -> TokenStream2 {
485487

486488
let getter = p.get.is_some().then(|| {
487489
let body = quote!(self.property::<<#ty as #crate_ident::Property>::Value>(#name));
488-
let fn_prototype = getter_prototype(&ident, ty);
490+
let fn_prototype =
491+
{ quote!(pub fn #ident(&self) -> <#ty as #crate_ident::Property>::Value) };
489492
quote!(#fn_prototype { #body })
490493
});
491494
let setter = (p.set.is_some() && !p.flags.contains(&"construct_only")).then(|| {
492495
let body = quote!(self.set_property_from_value(#name, &value.to_value()));
493-
let fn_prototype = setter_prototype(&ident, ty);
496+
let fn_prototype = {
497+
let ident = format_ident!("set_{}", ident);
498+
quote!(pub fn #ident(&self, value: &<<#ty as #crate_ident::Property>::Value as #crate_ident::HasParamSpec>::SetValue))
499+
};
494500
quote!(#fn_prototype { #body })
495501
});
496502
let span = p.attrs_span;
@@ -502,20 +508,14 @@ fn expand_getset_properties_impl(props: &[PropDesc]) -> TokenStream2 {
502508
quote!(#(#defs)*)
503509
}
504510

505-
fn connect_prop_notify_prototype(p: &PropDesc) -> TokenStream2 {
506-
let name = &p.name;
507-
let crate_ident = crate_ident_new();
508-
let fn_ident = format_ident!("connect_{}_notify", name_to_ident(name));
509-
quote!(fn #fn_ident<F: Fn(&Self) + 'static>(&self, f: F) -> #crate_ident::SignalHandlerId)
510-
}
511-
fn expand_connect_prop_notify_def(props: &[PropDesc]) -> TokenStream2 {
512-
let connection_fns = props.iter().map(connect_prop_notify_prototype);
513-
quote!(#(#connection_fns;)*)
514-
}
515511
fn expand_connect_prop_notify_impl(props: &[PropDesc]) -> TokenStream2 {
512+
let crate_ident = crate_ident_new();
516513
let connection_fns = props.iter().map(|p| {
517514
let name = &p.name;
518-
let fn_prototype = connect_prop_notify_prototype(p);
515+
let fn_prototype = {
516+
let fn_ident = format_ident!("connect_{}_notify", name_to_ident(name));
517+
quote!(pub fn #fn_ident<F: Fn(&Self) + 'static>(&self, f: F) -> #crate_ident::SignalHandlerId)
518+
};
519519
let span = p.attrs_span;
520520
quote_spanned!(span=> #fn_prototype {
521521
self.connect_notify_local(Some(#name), move |this, _| {
@@ -526,19 +526,13 @@ fn expand_connect_prop_notify_impl(props: &[PropDesc]) -> TokenStream2 {
526526
quote!(#(#connection_fns)*)
527527
}
528528

529-
fn emit_prototype(p: &PropDesc) -> TokenStream2 {
530-
let name = &p.name;
531-
let fn_ident = format_ident!("emit_{}", name_to_ident(name));
532-
quote!(fn #fn_ident(&self))
533-
}
534-
fn expand_emit_def(props: &[PropDesc]) -> TokenStream2 {
535-
let emit_fns = props.iter().map(emit_prototype);
536-
quote!(#(#emit_fns;)*)
537-
}
538529
fn expand_emit_impl(props: &[PropDesc]) -> TokenStream2 {
539530
let emit_fns = props.iter().map(|p| {
540531
let name = &p.name;
541-
let fn_prototype = emit_prototype(p);
532+
let fn_prototype = {
533+
let fn_ident = format_ident!("emit_{}", name_to_ident(name));
534+
quote!(fn #fn_ident(&self))
535+
};
542536
let span = p.attrs_span;
543537
quote_spanned!(span=> #fn_prototype {
544538
self.notify(#name);
@@ -549,18 +543,13 @@ fn expand_emit_impl(props: &[PropDesc]) -> TokenStream2 {
549543

550544
pub fn impl_derive_props(input: PropsMacroInput) -> TokenStream {
551545
let struct_ident = &input.ident;
552-
let struct_ident_ext = format_ident!("{}PropertiesExt", &input.ident);
553546
let crate_ident = crate_ident_new();
554-
let wrapper_type =
555-
quote!(<#struct_ident as #crate_ident::subclass::types::ObjectSubclass>::Type);
547+
let wrapper_type = input.wrapper_ty;
556548
let fn_properties = expand_properties_fn(&input.props);
557549
let fn_property = expand_property_fn(&input.props);
558550
let fn_set_property = expand_set_property_fn(&input.props);
559-
let getset_properties_def = expand_getset_properties_def(&input.props);
560551
let getset_properties_impl = expand_getset_properties_impl(&input.props);
561-
let connect_prop_notify_def = expand_connect_prop_notify_def(&input.props);
562552
let connect_prop_notify_impl = expand_connect_prop_notify_impl(&input.props);
563-
let emit_def = expand_emit_def(&input.props);
564553
let emit_impl = expand_emit_impl(&input.props);
565554
let expanded = quote! {
566555
use #crate_ident::{PropertyGet, PropertySet, ToValue};
@@ -571,12 +560,7 @@ pub fn impl_derive_props(input: PropsMacroInput) -> TokenStream {
571560
#fn_set_property
572561
}
573562

574-
pub trait #struct_ident_ext {
575-
#getset_properties_def
576-
#connect_prop_notify_def
577-
#emit_def
578-
}
579-
impl<T: #crate_ident::IsA<#wrapper_type>> #struct_ident_ext for T {
563+
impl #wrapper_type {
580564
#getset_properties_impl
581565
#connect_prop_notify_impl
582566
#emit_impl

glib-macros/tests/properties.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ fn props() {
4444
use super::*;
4545

4646
#[derive(Properties, Default)]
47+
#[properties(wrapper_type = super::Foo)]
4748
pub struct Foo {
4849
#[property(get, set)]
4950
bar: Mutex<String>,
@@ -129,8 +130,6 @@ fn props() {
129130
}
130131
}
131132

132-
use foo::imp::FooPropertiesExt;
133-
134133
let myfoo: foo::Foo = glib::object::Object::new(&[]).unwrap();
135134

136135
// Read bar

0 commit comments

Comments
 (0)