Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

glib-macros: Add use_derived_properties macro #1127

Merged
merged 3 commits into from Jul 7, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
@@ -1,6 +1,8 @@
# Change Log

## [Unreleased]
Yuri Izmer:
bilelmoussaoui marked this conversation as resolved.
Show resolved Hide resolved
- glib-macros: Add `derived_properties` macro

## [0.17.10]
Ben Kimock:
Expand Down
79 changes: 79 additions & 0 deletions glib-macros/src/derived_properties_attribute.rs
@@ -0,0 +1,79 @@
// Take a look at the license at the top of the repository in the LICENSE file.

use proc_macro2::TokenStream;
use proc_macro_error::abort_call_site;
use quote::quote;

pub const WRONG_PLACE_MSG: &str =
"This macro should be used on `impl` block for `glib::ObjectImpl` trait";

pub fn impl_derived_properties(input: &syn::ItemImpl) -> TokenStream {
let syn::ItemImpl {
attrs,
generics,
trait_,
self_ty,
items,
..
} = input;

let trait_path = match &trait_ {
Some(path) => &path.1,
None => abort_call_site!(WRONG_PLACE_MSG),
};

let mut has_property = false;
let mut has_properties = false;
let mut has_set_property = false;

for item in items {
if let syn::ImplItem::Fn(method) = item {
let ident = &method.sig.ident;

if ident == "properties" {
has_properties = true;
} else if ident == "set_property" {
has_set_property = true;
} else if ident == "property" {
has_property = true;
}
}
}

let crate_ident = crate::utils::crate_ident_new();

let properties = quote!(
fn properties() -> &'static [#crate_ident::ParamSpec] {
Self::derived_properties()
}
);

let set_property = quote!(
fn set_property(&self, id: usize, value: &#crate_ident::Value, pspec: &#crate_ident::ParamSpec) {
Self::derived_set_property(self, id, value, pspec)
}
);

let property = quote!(
fn property(&self, id: usize, pspec: &#crate_ident::ParamSpec) -> #crate_ident::Value {
Self::derived_property(self, id, pspec)
}
);

let generated: Vec<_> = vec![
yuraiz marked this conversation as resolved.
Show resolved Hide resolved
(has_properties, properties),
(has_set_property, set_property),
(has_property, property),
]
.into_iter()
.filter_map(|(has_method, method)| (!has_method).then_some(method))
.collect();

quote!(
#(#attrs)*
impl #generics #trait_path for #self_ty {
#(#items)*
#(#generated)*
}
)
}
42 changes: 29 additions & 13 deletions glib-macros/src/lib.rs
Expand Up @@ -3,6 +3,7 @@
mod boxed_derive;
mod clone;
mod closure;
mod derived_properties_attribute;
mod downgrade_derive;
mod enum_derive;
mod error_domain_derive;
Expand Down Expand Up @@ -882,7 +883,7 @@
///
/// ## Using Rust keywords as property names
/// You might hit a roadblock when declaring properties with this macro because you want to use a name that happens to be a Rust keyword. This may happen with names like `loop`, which is a pretty common name when creating things like animation handlers.
/// To use those names, you can make use of the raw identifier feature of Rust. Simply prefix the identifier name with `r#` in the struct declaration. Internally, those `r#`s are stripped so you can use its expected name in [`ObjectExt::property`] or within GtkBuilder template files.

Check warning on line 886 in glib-macros/src/lib.rs

View workflow job for this annotation

GitHub Actions / build

unresolved link to `ObjectExt::property`
///
/// # Generated wrapper methods
/// The following methods are generated on the wrapper type specified on `#[properties(wrapper_type = ...)]`:
Expand Down Expand Up @@ -942,7 +943,6 @@
/// }
///
/// pub mod imp {
/// use glib::{ParamSpec, Value};
/// use std::rc::Rc;
///
/// use super::*;
Expand All @@ -966,18 +966,9 @@
/// #[property(get, set)]
/// smart_pointer: Rc<RefCell<String>>,
/// }
///
/// 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(id, value, pspec)
/// }
/// fn property(&self, id: usize, pspec: &ParamSpec) -> Value {
/// self.derived_property(id, pspec)
/// }
/// }
///
/// #[glib::derived_properties]
/// impl ObjectImpl for Foo {}
///
/// #[glib::object_subclass]
/// impl ObjectSubclass for Foo {
Expand Down Expand Up @@ -1010,6 +1001,31 @@
properties::impl_derive_props(input)
}

/// This macro is shorteng for:
///
/// ```ignore
/// fn properties() -> &'static [glib::ParamSpec] {
/// Self::derived_properties()
/// }
/// fn set_property(&self, id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
/// self.derived_set_property(id, value, pspec)
/// }
/// fn property(&self, id: usize, pspec: &glib::ParamSpec) -> glib::Value {
/// self.derived_property(id, pspec)
/// }
/// ```
///
/// for ObjectImpl trait implementation
#[proc_macro_attribute]
#[proc_macro_error]
pub fn derived_properties(_attr: TokenStream, item: TokenStream) -> TokenStream {
use proc_macro_error::abort_call_site;
match syn::parse::<syn::ItemImpl>(item) {
Ok(input) => derived_properties_attribute::impl_derived_properties(&input).into(),
Err(_) => abort_call_site!(derived_properties_attribute::WRONG_PLACE_MSG),
}
}

/// # Example
/// ```
/// use glib::prelude::*;
Expand Down
49 changes: 8 additions & 41 deletions glib-macros/tests/properties.rs
Expand Up @@ -11,8 +11,6 @@ mod base {
use std::marker::PhantomData;

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

use super::*;

#[derive(Properties, Default)]
Expand All @@ -24,17 +22,8 @@ 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::derived_properties]
impl ObjectImpl for Base {}

#[glib::object_subclass]
impl ObjectSubclass for Base {
Expand Down Expand Up @@ -90,7 +79,6 @@ mod foo {
}

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

use super::*;
Expand Down Expand Up @@ -166,25 +154,16 @@ mod foo {
construct_only_custom_setter: OnceCell<Option<String>>,
}

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";
type Type = super::Foo;
type ParentType = Base;
}

#[glib::derived_properties]
impl ObjectImpl for Foo {}

impl Foo {
fn set_author_name(&self, value: String) {
self.author.borrow_mut().name = value;
Expand Down Expand Up @@ -417,10 +396,7 @@ mod kw_names {
use glib::ObjectExt;
use std::cell::Cell;

use glib::{
subclass::{prelude::ObjectImpl, types::ObjectSubclass},
ParamSpec, Value,
};
use glib::subclass::{prelude::ObjectImpl, types::ObjectSubclass};
use glib_macros::Properties;

#[derive(Properties, Default)]
Expand Down Expand Up @@ -461,17 +437,8 @@ mod kw_names {
type Type = super::KwNames;
}

impl ObjectImpl for KwNames {
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::derived_properties]
impl ObjectImpl for KwNames {}
}

glib::wrapper! {
Expand Down
4 changes: 2 additions & 2 deletions glib/src/lib.rs
Expand Up @@ -10,8 +10,8 @@
#[doc(hidden)]
pub use glib_macros::cstr_bytes;
pub use glib_macros::{
clone, closure, closure_local, flags, object_interface, object_subclass, Boxed, Downgrade,
Enum, ErrorDomain, Properties, SharedBoxed, ValueDelegate, Variant,
clone, closure, closure_local, derived_properties, flags, object_interface, object_subclass,
Boxed, Downgrade, Enum, ErrorDomain, Properties, SharedBoxed, ValueDelegate, Variant,
};
pub use gobject_ffi;
#[doc(hidden)]
Expand Down Expand Up @@ -131,7 +131,7 @@
mod convert;
pub use self::convert::*;
mod enums;
mod functions;

Check warning on line 134 in glib/src/lib.rs

View workflow job for this annotation

GitHub Actions / build

private item shadows public glob re-export
pub use self::functions::*;
mod key_file;
pub mod prelude;
Expand Down