From 84f21a7b82235ec7a65c9b6f819c5233100bb027 Mon Sep 17 00:00:00 2001 From: Jason Francis Date: Sun, 14 Nov 2021 15:04:57 -0600 Subject: [PATCH 1/3] Remove `impl trait` from ClosureExpression::with_closure --- gtk4/src/closure_expression.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/gtk4/src/closure_expression.rs b/gtk4/src/closure_expression.rs index e4755dbf9643..196dc5606308 100644 --- a/gtk4/src/closure_expression.rs +++ b/gtk4/src/closure_expression.rs @@ -50,12 +50,11 @@ impl ClosureExpression { } #[doc(alias = "gtk_closure_expression_new")] - pub fn with_closure( - params: impl IntoIterator>, - closure: glib::Closure, - ) -> Self + pub fn with_closure(params: I, closure: glib::Closure) -> Self where R: ValueType, + I: IntoIterator, + E: AsRef, { assert_initialized_main_thread!(); From 2654d288541531225e1d2756269eb1b9cbd4432b Mon Sep 17 00:00:00 2001 From: Jason Francis Date: Sun, 14 Nov 2021 15:05:25 -0600 Subject: [PATCH 2/3] Allow chaining expressions with Closure objects --- examples/expressions/main.rs | 13 ++++++----- gtk4/src/closure_expression.rs | 23 ++++++++++--------- gtk4/src/expression.rs | 41 ++++++++++++++++++++++++++++++---- 3 files changed, 58 insertions(+), 19 deletions(-) diff --git a/examples/expressions/main.rs b/examples/expressions/main.rs index 7c137eb223b2..646d8e7b912b 100644 --- a/examples/expressions/main.rs +++ b/examples/expressions/main.rs @@ -1,6 +1,8 @@ mod metadata; mod note; +use glib::closure; + use gtk::gio; use gtk::glib; use gtk::prelude::*; @@ -48,11 +50,12 @@ fn build_ui(app: >k::Application) { metadata_expression .chain_property::("last-modified") - .chain_closure(|args| { - let last_modified: glib::DateTime = args[1].get().unwrap(); - format!("Last Modified: {}", last_modified.format_iso8601().unwrap()) - }) - .bind(&last_modified_label, "label", gtk::Widget::NONE); + .chain_closure_obj::(closure!( + |_: gtk::ListItem, last_modified: glib::DateTime| { + format!("Last Modified: {}", last_modified.format_iso8601().unwrap()) + } + )) + .bind(&last_modified_label, "label", Some(list_item)); list_item.set_child(Some(&hbox)); }); diff --git a/gtk4/src/closure_expression.rs b/gtk4/src/closure_expression.rs index 196dc5606308..4ab32bf1eb71 100644 --- a/gtk4/src/closure_expression.rs +++ b/gtk4/src/closure_expression.rs @@ -23,16 +23,13 @@ define_expression!( impl ClosureExpression { #[doc(alias = "gtk_closure_expression_new")] - pub fn new(params: impl IntoIterator>, callback: F) -> Self + pub fn new(params: I, closure: glib::RustClosure) -> Self where - F: Fn(&[Value]) -> R + 'static, R: ValueType, + I: IntoIterator, + E: AsRef, { assert_initialized_main_thread!(); - let closure = glib::Closure::new_local(move |values| { - let ret = callback(values); - Some(ret.to_value()) - }); let params = params .into_iter() @@ -42,7 +39,7 @@ impl ClosureExpression { unsafe { from_glib_full(ffi::gtk_closure_expression_new( R::Type::static_type().into_glib(), - closure.to_glib_none().0, + closure.as_ref().to_glib_none().0, params.len() as u32, params.to_glib_full(), )) @@ -50,13 +47,19 @@ impl ClosureExpression { } #[doc(alias = "gtk_closure_expression_new")] - pub fn with_closure(params: I, closure: glib::Closure) -> Self + pub fn with_callback( + params: impl IntoIterator>, + callback: F, + ) -> Self where + F: Fn(&[Value]) -> R + 'static, R: ValueType, - I: IntoIterator, - E: AsRef, { assert_initialized_main_thread!(); + let closure = glib::Closure::new_local(move |values| { + let ret = callback(values); + Some(ret.to_value()) + }); let params = params .into_iter() diff --git a/gtk4/src/expression.rs b/gtk4/src/expression.rs index 72b67cec131a..20d789b4f015 100644 --- a/gtk4/src/expression.rs +++ b/gtk4/src/expression.rs @@ -171,14 +171,47 @@ impl Expression { } // rustdoc-stripper-ignore-next - /// Create a [`gtk::ClosureExpression`] with self as a parameter. This is useful in long - /// chains of [`gtk::Expression`]s. - pub fn chain_closure(&self, f: F) -> crate::ClosureExpression + /// Create a [`ClosureExpression`](crate::ClosureExpression) from a [`glib::Closure`] with self + /// as the second parameter and `R` as the return type. The return type is checked at run-time + /// and must always be specified. This is useful in long chains of + /// [`Expression`](crate::Expression)s when using the [`glib::closure!`] macro. + /// + /// Note that the first parameter will always be the `this` object bound to the expression. If + /// `None` is passed as `this` then the type of the first parameter must be + /// `Option` otherwise type checking will panic. + /// + /// ```no_run + /// # use gtk4 as gtk; + /// use gtk::prelude::*; + /// use gtk::glib; + /// use glib::{closure, Object}; + /// + /// let button = gtk::Button::new(); + /// button.set_label("Hello"); + /// let label = button + /// .property_expression("label") + /// .chain_closure::(closure!(|_: Option, label: &str| { + /// format!("{} World", label) + /// })) + /// .evaluate_as::(gtk::Widget::NONE); + /// assert_eq!(label.unwrap(), "Hello World"); + /// ``` + pub fn chain_closure(&self, closure: glib::RustClosure) -> crate::ClosureExpression + where + R: glib::value::ValueType, + { + crate::ClosureExpression::new::(&[self], closure) + } + + // rustdoc-stripper-ignore-next + /// Create a [`ClosureExpression`](crate::ClosureExpression) with self as the second parameter. + /// This is useful in long chains of [`Expression`](crate::Expression)s. + pub fn chain_closure_with_callback(&self, f: F) -> crate::ClosureExpression where F: Fn(&[glib::Value]) -> R + 'static, R: glib::value::ValueType, { - crate::ClosureExpression::new(&[self], f) + crate::ClosureExpression::with_callback(&[self], f) } } From e1931b61251cc7463e3d7f6a0ceecb90edb31d8e Mon Sep 17 00:00:00 2001 From: Jason Francis Date: Sun, 14 Nov 2021 15:05:49 -0600 Subject: [PATCH 3/3] Fix broken crate links in docs --- examples/expressions/main.rs | 4 ++-- gtk4/src/expression.rs | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/examples/expressions/main.rs b/examples/expressions/main.rs index 646d8e7b912b..49410c48e38e 100644 --- a/examples/expressions/main.rs +++ b/examples/expressions/main.rs @@ -42,7 +42,7 @@ fn build_ui(app: >k::Application) { metadata_expression .chain_property::("title") - .chain_closure(|args| { + .chain_closure_with_callback(|args| { let title: String = args[1].get().unwrap(); format!("Title: {}", title) }) @@ -50,7 +50,7 @@ fn build_ui(app: >k::Application) { metadata_expression .chain_property::("last-modified") - .chain_closure_obj::(closure!( + .chain_closure::(closure!( |_: gtk::ListItem, last_modified: glib::DateTime| { format!("Last Modified: {}", last_modified.format_iso8601().unwrap()) } diff --git a/gtk4/src/expression.rs b/gtk4/src/expression.rs index 20d789b4f015..952a8f75d455 100644 --- a/gtk4/src/expression.rs +++ b/gtk4/src/expression.rs @@ -161,8 +161,9 @@ impl Expression { } // rustdoc-stripper-ignore-next - /// Create a [`gtk::PropertyExpression`] that looks up for `property_name` - /// with self as parameter. This is useful in long chains of [`gtk::Expression`]s. + /// Create a [`PropertyExpression`](crate::PropertyExpression) that looks up for + /// `property_name` with self as parameter. This is useful in long chains of + /// [`Expression`](crate::Expression)s. pub fn chain_property>( &self, property_name: &str, @@ -250,12 +251,13 @@ impl glib::value::ToValueOptional for Expression { } // rustdoc-stripper-ignore-next -/// Trait containing convenience methods in creating [`gtk::PropertyExpression`] that +/// Trait containing convenience methods in creating +/// [`PropertyExpression`](crate::PropertyExpression) that /// looks up a property of a [`glib::Object`]. /// /// # Example /// -/// `label_expression` is a [`gtk::Expression`] that looks up at Button's `label` +/// `label_expression` is an [`Expression`](crate::Expression) that looks up at Button's `label` /// property. /// /// ```no_run