Skip to content

Commit

Permalink
glib-macros: add ObjectImpl derive
Browse files Browse the repository at this point in the history
  • Loading branch information
jf2048 committed Feb 15, 2023
1 parent 402a127 commit 287aebf
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 35 deletions.
10 changes: 8 additions & 2 deletions glib-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod downgrade_derive;
mod enum_derive;
mod error_domain_derive;
mod flags_attribute;
mod object_impl_derive;
mod object_interface_attribute;
mod object_subclass_attribute;
mod properties;
Expand Down Expand Up @@ -965,7 +966,6 @@ pub fn derive_props(input: TokenStream) -> TokenStream {
}

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

#[proc_macro_attribute]
#[proc_macro_error]
pub fn wrapper(attr: TokenStream, item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as syn::ItemStruct);
match wrapper_attribute::impl_wrapper(attr.into(), input) {
Ok(gen) => gen.into(),
Err(e) => e.into_compile_error().into(),
}
}

#[proc_macro_derive(ObjectImpl, attributes(object_impl))]
pub fn object_impl_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let gen = object_impl_derive::impl_object_impl(input);
gen.into()
}
104 changes: 104 additions & 0 deletions glib-macros/src/object_impl_derive.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use proc_macro2::TokenStream;
use quote::quote;

#[derive(Default, deluxe::ExtractAttributes)]
#[deluxe(attributes(object_impl))]
struct ObjectImpl {
derived_properties: deluxe::Flag,
#[deluxe(map(|e| FlagOrExpr::into_expr(e, "signals")))]
signals: Option<syn::Expr>,
#[deluxe(map(|e| FlagOrExpr::into_expr(e, "constructed")))]
constructed: Option<syn::Expr>,
#[deluxe(map(|e| FlagOrExpr::into_expr(e, "dispose")))]
dispose: Option<syn::Expr>,
}

enum FlagOrExpr {
Flag,
Expr(syn::Expr),
}

impl deluxe::ParseMetaItem for FlagOrExpr {
#[inline]
fn parse_meta_item(
input: syn::parse::ParseStream,
_mode: deluxe::ParseMode,
) -> deluxe::Result<Self> {
Ok(Self::Expr(input.parse()?))
}
#[inline]
fn parse_meta_item_flag(_span: proc_macro2::Span) -> deluxe::Result<Self> {
Ok(Self::Flag)
}
}

impl FlagOrExpr {
#[inline]
fn into_expr(e: Option<Self>, default_name: &str) -> Option<syn::Expr> {
e.map(|e| match e {
Self::Flag => {
let func = syn::Ident::new(default_name, proc_macro2::Span::call_site());
syn::parse_quote! { Self::#func }
}
Self::Expr(expr) => expr,
})
}
}

pub fn impl_object_impl(mut input: syn::DeriveInput) -> TokenStream {
let errors = deluxe::Errors::new();
let ObjectImpl {
derived_properties,
signals,
constructed,
dispose,
} = deluxe::extract_attributes_optional(&mut input, &errors);

let glib = crate::utils::crate_ident_new();
let ident = &input.ident;
let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();

let properties = derived_properties.is_set().then(|| {
quote! {
fn properties() -> &'static [#glib::ParamSpec] {
Self::derived_properties()
}
fn property(&self, id: ::std::primitive::usize, pspec: &#glib::ParamSpec) -> #glib::Value {
Self::derived_property(self, id, pspec)
}
fn set_property(&self, id: ::std::primitive::usize, value: &#glib::Value, pspec: &#glib::ParamSpec) {
Self::derived_set_property(self, id, value, pspec)
}
}
});
let signals = signals.map(|signals| {
quote! {
fn signals() -> &'static [#glib::subclass::Signal] {
(#signals)()
}
}
});
let constructed = constructed.map(|constructed| {
quote! {
fn constructed(&self) {
(#constructed)(self)
}
}
});
let dispose = dispose.map(|dispose| {
quote! {
fn dispose(&self) {
(#dispose)(self)
}
}
});
quote! {
#errors
impl #impl_generics #glib::subclass::object::ObjectImpl for #ident #type_generics #where_clause {
#properties
#signals
#constructed
#dispose
}
}
}
46 changes: 14 additions & 32 deletions glib-macros/tests/properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@ use glib::ParamFlags;
mod base {
use glib::prelude::*;
use glib::subclass::prelude::*;
use glib_macros::Properties;
use glib_macros::{ObjectImpl, Properties};
use std::marker::PhantomData;

pub mod imp {
use glib::{ParamSpec, Value};

use super::*;

#[derive(Properties, Default)]
#[derive(Default, ObjectImpl, Properties)]
#[object_impl(derived_properties)]
#[properties(wrapper_type = super::Base)]
pub struct Base {
#[property(get = Self::not_overridden)]
Expand All @@ -24,18 +23,6 @@ mod base {
not_overridden: PhantomData<u32>,
}

impl ObjectImpl for Base {
fn properties() -> &'static [ParamSpec] {
Self::derived_properties()
}
fn set_property(&self, _id: usize, _value: &Value, _pspec: &ParamSpec) {
Self::derived_set_property(self, _id, _value, _pspec)
}
fn property(&self, id: usize, _pspec: &ParamSpec) -> Value {
Self::derived_property(self, id, _pspec)
}
}

#[glib::object_subclass]
impl ObjectSubclass for Base {
const NAME: &'static str = "MyBase";
Expand All @@ -60,7 +47,7 @@ mod base {
mod foo {
use glib::prelude::*;
use glib::subclass::prelude::*;
use glib_macros::Properties;
use glib_macros::{ObjectImpl, Properties};
use once_cell::sync::OnceCell;
use std::cell::Cell;
use std::cell::RefCell;
Expand All @@ -87,12 +74,14 @@ mod foo {
}

pub mod imp {
use glib::{ParamSpec, Value};
use std::rc::Rc;

use glib::subclass::Signal;

use super::*;

#[derive(Properties, Default)]
#[derive(Default, ObjectImpl, Properties)]
#[object_impl(derived_properties, signals, constructed = Self::my_constructed, dispose)]
#[properties(wrapper_type = super::Foo)]
pub struct Foo {
#[property(get, set)]
Expand Down Expand Up @@ -155,18 +144,6 @@ mod foo {
send_weak_ref_prop: glib::SendWeakRef<glib::Object>,
}

impl ObjectImpl for Foo {
fn properties() -> &'static [ParamSpec] {
Self::derived_properties()
}
fn set_property(&self, _id: usize, _value: &Value, _pspec: &ParamSpec) {
Self::derived_set_property(self, _id, _value, _pspec)
}
fn property(&self, id: usize, _pspec: &ParamSpec) -> Value {
Self::derived_property(self, id, _pspec)
}
}

#[glib::object_subclass]
impl ObjectSubclass for Foo {
const NAME: &'static str = "MyFoo";
Expand All @@ -182,11 +159,16 @@ mod foo {
String::from("Hello world!")
}
fn set_fizz(&self, value: String) {
*self.fizz.borrow_mut() = format!("custom set: {}", value);
*self.fizz.borrow_mut() = format!("custom set: {value}");
}
fn overridden(&self) -> u32 {
43
}
fn signals() -> &'static [Signal] {
&[]
}
fn my_constructed(&self) {}
fn dispose(&self) {}
}
}

Expand Down
3 changes: 2 additions & 1 deletion glib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ pub use ffi;
pub use glib_macros::cstr_bytes;
pub use glib_macros::{
clone, clone_block, closure, closure_local, flags, object_interface, object_subclass,
wrapper as wrapper_attr, Boxed, Downgrade, Enum, ErrorDomain, Properties, SharedBoxed, Variant,
wrapper as wrapper_attr, Boxed, Downgrade, Enum, ErrorDomain, ObjectImpl, Properties,
SharedBoxed, Variant,
};
pub use gobject_ffi;
#[doc(hidden)]
Expand Down

0 comments on commit 287aebf

Please sign in to comment.