Skip to content

Commit 0743c00

Browse files
committed
glib-macros: add ObjectImpl derive
1 parent 402a127 commit 0743c00

File tree

5 files changed

+202
-35
lines changed

5 files changed

+202
-35
lines changed

glib-macros/src/lib.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod downgrade_derive;
88
mod enum_derive;
99
mod error_domain_derive;
1010
mod flags_attribute;
11+
mod object_impl_derive;
1112
mod object_interface_attribute;
1213
mod object_subclass_attribute;
1314
mod properties;
@@ -965,7 +966,6 @@ pub fn derive_props(input: TokenStream) -> TokenStream {
965966
}
966967

967968
#[proc_macro_attribute]
968-
#[proc_macro_error::proc_macro_error]
969969
pub fn clone_block(_attr: TokenStream, item: TokenStream) -> TokenStream {
970970
let mut item = syn::parse_macro_input!(item as syn::Item);
971971
let errors = deluxe::Errors::new();
@@ -975,11 +975,17 @@ pub fn clone_block(_attr: TokenStream, item: TokenStream) -> TokenStream {
975975
}
976976

977977
#[proc_macro_attribute]
978-
#[proc_macro_error]
979978
pub fn wrapper(attr: TokenStream, item: TokenStream) -> TokenStream {
980979
let input = parse_macro_input!(item as syn::ItemStruct);
981980
match wrapper_attribute::impl_wrapper(attr.into(), input) {
982981
Ok(gen) => gen.into(),
983982
Err(e) => e.into_compile_error().into(),
984983
}
985984
}
985+
986+
#[proc_macro_derive(ObjectImpl, attributes(object_impl))]
987+
pub fn object_impl_derive(input: TokenStream) -> TokenStream {
988+
let input = parse_macro_input!(input as utils::DeriveHeader);
989+
let gen = object_impl_derive::impl_object_impl(input);
990+
gen.into()
991+
}

glib-macros/src/object_impl_derive.rs

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
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 quote::quote;
5+
6+
use crate::utils::DeriveHeader;
7+
8+
#[derive(Default, deluxe::ExtractAttributes)]
9+
#[deluxe(attributes(object_impl))]
10+
struct ObjectImpl {
11+
derived_properties: deluxe::Flag,
12+
#[deluxe(map(|e| FlagOrExpr::into_expr(e, "signals")))]
13+
signals: Option<syn::Expr>,
14+
#[deluxe(map(|e| FlagOrExpr::into_expr(e, "constructed")))]
15+
constructed: Option<syn::Expr>,
16+
#[deluxe(map(|e| FlagOrExpr::into_expr(e, "dispose")))]
17+
dispose: Option<syn::Expr>,
18+
}
19+
20+
enum FlagOrExpr {
21+
Flag,
22+
Expr(syn::Expr),
23+
}
24+
25+
impl deluxe::ParseMetaItem for FlagOrExpr {
26+
#[inline]
27+
fn parse_meta_item(
28+
input: syn::parse::ParseStream,
29+
_mode: deluxe::ParseMode,
30+
) -> deluxe::Result<Self> {
31+
Ok(Self::Expr(input.parse()?))
32+
}
33+
#[inline]
34+
fn parse_meta_item_flag(_span: proc_macro2::Span) -> deluxe::Result<Self> {
35+
Ok(Self::Flag)
36+
}
37+
}
38+
39+
impl FlagOrExpr {
40+
#[inline]
41+
fn into_expr(e: Option<Self>, default_name: &str) -> Option<syn::Expr> {
42+
e.map(|e| match e {
43+
Self::Flag => {
44+
let func = syn::Ident::new(default_name, proc_macro2::Span::call_site());
45+
syn::parse_quote! { Self::#func }
46+
}
47+
Self::Expr(expr) => expr,
48+
})
49+
}
50+
}
51+
52+
pub fn impl_object_impl(mut input: DeriveHeader) -> TokenStream {
53+
let errors = deluxe::Errors::new();
54+
let ObjectImpl {
55+
derived_properties,
56+
signals,
57+
constructed,
58+
dispose,
59+
} = deluxe::extract_attributes_optional(&mut input, &errors);
60+
61+
let glib = crate::utils::crate_ident_new();
62+
let ident = &input.ident;
63+
let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();
64+
65+
let properties = derived_properties.is_set().then(|| {
66+
quote! {
67+
fn properties() -> &'static [#glib::ParamSpec] {
68+
Self::derived_properties()
69+
}
70+
fn property(&self, id: ::std::primitive::usize, pspec: &#glib::ParamSpec) -> #glib::Value {
71+
Self::derived_property(self, id, pspec)
72+
}
73+
fn set_property(&self, id: ::std::primitive::usize, value: &#glib::Value, pspec: &#glib::ParamSpec) {
74+
Self::derived_set_property(self, id, value, pspec)
75+
}
76+
}
77+
});
78+
let signals = signals.map(|signals| {
79+
quote! {
80+
fn signals() -> &'static [#glib::subclass::Signal] {
81+
(#signals)()
82+
}
83+
}
84+
});
85+
let constructed = constructed.map(|constructed| {
86+
quote! {
87+
fn constructed(&self) {
88+
(#constructed)(self)
89+
}
90+
}
91+
});
92+
let dispose = dispose.map(|dispose| {
93+
quote! {
94+
fn dispose(&self) {
95+
(#dispose)(self)
96+
}
97+
}
98+
});
99+
quote! {
100+
#errors
101+
impl #impl_generics #glib::subclass::object::ObjectImpl for #ident #type_generics #where_clause {
102+
#properties
103+
#signals
104+
#constructed
105+
#dispose
106+
}
107+
}
108+
}

glib-macros/src/utils.rs

+70
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,73 @@ pub fn gen_enum_from_glib(
5858
None
5959
}
6060
}
61+
62+
// Simplified DeriveInput without fields, for faster parsing
63+
pub struct DeriveHeader {
64+
pub attrs: Vec<syn::Attribute>,
65+
pub vis: syn::Visibility,
66+
pub ident: syn::Ident,
67+
pub generics: syn::Generics,
68+
pub data: DeriveData,
69+
}
70+
71+
pub enum DeriveData {
72+
Struct,
73+
Enum,
74+
Union,
75+
}
76+
77+
impl syn::parse::Parse for DeriveHeader {
78+
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
79+
let attrs = input.call(syn::Attribute::parse_outer)?;
80+
let vis = input.parse()?;
81+
let data = input.parse()?;
82+
let ident = input.parse()?;
83+
let mut generics = input.parse::<syn::Generics>()?;
84+
if input.peek(syn::Token![where]) {
85+
generics.where_clause = Some(input.parse()?);
86+
} else if input.peek(syn::token::Paren) {
87+
let _content;
88+
syn::parenthesized!(_content in input);
89+
if input.peek(syn::Token![where]) {
90+
generics.where_clause = Some(input.parse()?);
91+
}
92+
}
93+
Ok(Self {
94+
attrs,
95+
vis,
96+
ident,
97+
generics,
98+
data,
99+
})
100+
}
101+
}
102+
103+
impl syn::parse::Parse for DeriveData {
104+
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
105+
let lookahead = input.lookahead1();
106+
if lookahead.peek(syn::Token![struct]) {
107+
input.parse::<syn::Token![struct]>()?;
108+
Ok(Self::Struct)
109+
} else if lookahead.peek(syn::Token![enum]) {
110+
input.parse::<syn::Token![enum]>()?;
111+
Ok(Self::Enum)
112+
} else if lookahead.peek(syn::Token![union]) {
113+
input.parse::<syn::Token![union]>()?;
114+
Ok(Self::Union)
115+
} else {
116+
Err(lookahead.error())
117+
}
118+
}
119+
}
120+
121+
impl deluxe::HasAttributes for DeriveHeader {
122+
#[inline]
123+
fn attrs(&self) -> &[syn::Attribute] {
124+
&self.attrs
125+
}
126+
#[inline]
127+
fn attrs_mut(&mut self) -> deluxe::Result<&mut Vec<syn::Attribute>> {
128+
Ok(&mut self.attrs)
129+
}
130+
}

glib-macros/tests/properties.rs

+14-32
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,14 @@ use glib::ParamFlags;
77
mod base {
88
use glib::prelude::*;
99
use glib::subclass::prelude::*;
10-
use glib_macros::Properties;
10+
use glib_macros::{ObjectImpl, Properties};
1111
use std::marker::PhantomData;
1212

1313
pub mod imp {
14-
use glib::{ParamSpec, Value};
15-
1614
use super::*;
1715

18-
#[derive(Properties, Default)]
16+
#[derive(Default, ObjectImpl, Properties)]
17+
#[object_impl(derived_properties)]
1918
#[properties(wrapper_type = super::Base)]
2019
pub struct Base {
2120
#[property(get = Self::not_overridden)]
@@ -24,18 +23,6 @@ mod base {
2423
not_overridden: PhantomData<u32>,
2524
}
2625

27-
impl ObjectImpl for Base {
28-
fn properties() -> &'static [ParamSpec] {
29-
Self::derived_properties()
30-
}
31-
fn set_property(&self, _id: usize, _value: &Value, _pspec: &ParamSpec) {
32-
Self::derived_set_property(self, _id, _value, _pspec)
33-
}
34-
fn property(&self, id: usize, _pspec: &ParamSpec) -> Value {
35-
Self::derived_property(self, id, _pspec)
36-
}
37-
}
38-
3926
#[glib::object_subclass]
4027
impl ObjectSubclass for Base {
4128
const NAME: &'static str = "MyBase";
@@ -60,7 +47,7 @@ mod base {
6047
mod foo {
6148
use glib::prelude::*;
6249
use glib::subclass::prelude::*;
63-
use glib_macros::Properties;
50+
use glib_macros::{ObjectImpl, Properties};
6451
use once_cell::sync::OnceCell;
6552
use std::cell::Cell;
6653
use std::cell::RefCell;
@@ -87,12 +74,14 @@ mod foo {
8774
}
8875

8976
pub mod imp {
90-
use glib::{ParamSpec, Value};
9177
use std::rc::Rc;
9278

79+
use glib::subclass::Signal;
80+
9381
use super::*;
9482

95-
#[derive(Properties, Default)]
83+
#[derive(Default, ObjectImpl, Properties)]
84+
#[object_impl(derived_properties, signals, constructed = Self::my_constructed, dispose)]
9685
#[properties(wrapper_type = super::Foo)]
9786
pub struct Foo {
9887
#[property(get, set)]
@@ -155,18 +144,6 @@ mod foo {
155144
send_weak_ref_prop: glib::SendWeakRef<glib::Object>,
156145
}
157146

158-
impl ObjectImpl for Foo {
159-
fn properties() -> &'static [ParamSpec] {
160-
Self::derived_properties()
161-
}
162-
fn set_property(&self, _id: usize, _value: &Value, _pspec: &ParamSpec) {
163-
Self::derived_set_property(self, _id, _value, _pspec)
164-
}
165-
fn property(&self, id: usize, _pspec: &ParamSpec) -> Value {
166-
Self::derived_property(self, id, _pspec)
167-
}
168-
}
169-
170147
#[glib::object_subclass]
171148
impl ObjectSubclass for Foo {
172149
const NAME: &'static str = "MyFoo";
@@ -182,11 +159,16 @@ mod foo {
182159
String::from("Hello world!")
183160
}
184161
fn set_fizz(&self, value: String) {
185-
*self.fizz.borrow_mut() = format!("custom set: {}", value);
162+
*self.fizz.borrow_mut() = format!("custom set: {value}");
186163
}
187164
fn overridden(&self) -> u32 {
188165
43
189166
}
167+
fn signals() -> &'static [Signal] {
168+
&[]
169+
}
170+
fn my_constructed(&self) {}
171+
fn dispose(&self) {}
190172
}
191173
}
192174

glib/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ pub use ffi;
1111
pub use glib_macros::cstr_bytes;
1212
pub use glib_macros::{
1313
clone, clone_block, closure, closure_local, flags, object_interface, object_subclass,
14-
wrapper as wrapper_attr, Boxed, Downgrade, Enum, ErrorDomain, Properties, SharedBoxed, Variant,
14+
wrapper as wrapper_attr, Boxed, Downgrade, Enum, ErrorDomain, ObjectImpl, Properties,
15+
SharedBoxed, Variant,
1516
};
1617
pub use gobject_ffi;
1718
#[doc(hidden)]

0 commit comments

Comments
 (0)