Skip to main content

gtk4/
expression.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::{Object, Type, Value, translate::*, value::FromValue};
4
5use crate::{Expression, ffi, prelude::*};
6
7#[doc(hidden)]
8impl AsRef<Expression> for Expression {
9    #[inline]
10    fn as_ref(&self) -> &Expression {
11        self
12    }
13}
14
15// rustdoc-stripper-ignore-next
16/// A common trait implemented by the various [`Expression`](crate::Expression)
17/// types.
18///
19/// # Safety
20///
21/// The user is not supposed to implement this trait.
22pub unsafe trait IsExpression:
23    StaticType + FromGlibPtrFull<*mut ffi::GtkExpression> + 'static
24{
25}
26
27impl Expression {
28    #[inline]
29    pub fn upcast(self) -> Self {
30        self
31    }
32
33    #[inline]
34    pub fn upcast_ref(&self) -> &Self {
35        self
36    }
37
38    #[inline]
39    pub fn is<E: IsExpression>(&self) -> bool {
40        self.type_().is_a(E::static_type())
41    }
42
43    #[inline]
44    pub fn downcast<E: IsExpression>(self) -> Result<E, Expression> {
45        unsafe {
46            if self.is::<E>() {
47                Ok(from_glib_full(self.into_glib_ptr()))
48            } else {
49                Err(self)
50            }
51        }
52    }
53
54    #[inline]
55    pub fn downcast_ref<E: IsExpression>(&self) -> Option<&E> {
56        unsafe {
57            if self.is::<E>() {
58                Some(&*(self as *const Expression as *const E))
59            } else {
60                None
61            }
62        }
63    }
64
65    #[inline]
66    pub fn type_(&self) -> Type {
67        unsafe {
68            let ptr = self.as_ptr();
69            from_glib((*(*(ptr as *mut glib::gobject_ffi::GTypeInstance)).g_class).g_type)
70        }
71    }
72
73    #[doc(alias = "gtk_expression_evaluate")]
74    pub fn evaluate(&self, this: Option<&impl IsA<Object>>) -> Option<Value> {
75        assert_initialized_main_thread!();
76        unsafe {
77            let mut value = Value::uninitialized();
78            let ret = ffi::gtk_expression_evaluate(
79                self.to_glib_none().0,
80                this.map(|t| t.as_ref()).to_glib_none().0,
81                value.to_glib_none_mut().0,
82            );
83            if from_glib(ret) { Some(value) } else { None }
84        }
85    }
86
87    // rustdoc-stripper-ignore-next
88    /// Similar to [`Self::evaluate`] but panics if the value is of a different
89    /// type.
90    #[doc(alias = "gtk_expression_evaluate")]
91    pub fn evaluate_as<V: for<'b> FromValue<'b> + 'static, T: IsA<Object>>(
92        &self,
93        this: Option<&T>,
94    ) -> Option<V> {
95        self.evaluate(this).map(|v| {
96            v.get_owned::<V>()
97                .expect("Failed to evaluate to this value type")
98        })
99    }
100
101    // rustdoc-stripper-ignore-next
102    /// Create a [`PropertyExpression`](crate::PropertyExpression) that looks up
103    /// for `property_name` with self as parameter. This is useful in long
104    /// chains of [`Expression`](crate::Expression)s.
105    pub fn chain_property<T: IsA<glib::Object>>(
106        &self,
107        property_name: &str,
108    ) -> crate::PropertyExpression {
109        crate::PropertyExpression::new(T::static_type(), Some(self), property_name)
110    }
111
112    // rustdoc-stripper-ignore-next
113    /// Create a [`ClosureExpression`](crate::ClosureExpression) from a
114    /// [`glib::Closure`] with self as the second parameter and `R` as the
115    /// return type. The return type is checked at run-time and must always
116    /// be specified. This is useful in long chains of
117    /// [`Expression`](crate::Expression)s when using the [`glib::closure!`]
118    /// macro.
119    ///
120    /// Note that the first parameter will always be the `this` object bound to
121    /// the expression. If `None` is passed as `this` then the type of the
122    /// first parameter must be `Option<glib::Object>` otherwise type
123    /// checking will panic.
124    ///
125    /// ```no_run
126    /// # use gtk4 as gtk;
127    /// use glib::{closure, Object};
128    /// use gtk::{glib, prelude::*};
129    ///
130    /// let button = gtk::Button::new();
131    /// button.set_label("Hello");
132    /// let label = button
133    ///     .property_expression("label")
134    ///     .chain_closure::<String>(closure!(|_: Option<Object>, label: &str| {
135    ///         format!("{} World", label)
136    ///     }))
137    ///     .evaluate_as::<String, _>(gtk::Widget::NONE);
138    /// assert_eq!(label.unwrap(), "Hello World");
139    /// ```
140    pub fn chain_closure<R>(&self, closure: glib::RustClosure) -> crate::ClosureExpression
141    where
142        R: glib::value::ValueType,
143    {
144        crate::ClosureExpression::new::<R>([self], closure)
145    }
146
147    // rustdoc-stripper-ignore-next
148    /// Create a [`ClosureExpression`](crate::ClosureExpression) with self as
149    /// the second parameter. This is useful in long chains of
150    /// [`Expression`](crate::Expression)s.
151    pub fn chain_closure_with_callback<F, R>(&self, f: F) -> crate::ClosureExpression
152    where
153        F: Fn(&[glib::Value]) -> R + 'static,
154        R: glib::value::ValueType,
155    {
156        crate::ClosureExpression::with_callback([self], f)
157    }
158
159    #[cfg(feature = "v4_22")]
160    #[cfg_attr(docsrs, doc(cfg(feature = "v4_22")))]
161    // rustdoc-stripper-ignore-next
162    /// Create a [`TryExpression`](crate::TryExpression) with self as the first
163    /// parameter and `fallback` as the second parameter. This is useful in long
164    /// chains of [`Expression`](crate::Expression)s.
165    pub fn chain_try(&self, fallback: impl AsRef<Expression>) -> crate::TryExpression {
166        crate::TryExpression::new([self, fallback.as_ref()])
167    }
168}
169
170impl std::fmt::Debug for Expression {
171    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172        f.debug_struct("Expression")
173            .field("value_type", &self.value_type())
174            .field("is_static", &self.is_static())
175            .finish()
176    }
177}
178
179impl glib::value::ValueType for Expression {
180    type Type = Self;
181}
182
183unsafe impl<'a> glib::value::FromValue<'a> for Expression {
184    type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
185
186    #[inline]
187    unsafe fn from_value(value: &'a glib::Value) -> Self {
188        unsafe {
189            skip_assert_initialized!();
190            from_glib_full(crate::ffi::gtk_value_dup_expression(value.to_glib_none().0))
191        }
192    }
193}
194
195impl glib::value::ToValue for Expression {
196    #[inline]
197    fn to_value(&self) -> glib::Value {
198        let mut value = glib::Value::for_value_type::<Self>();
199        unsafe {
200            crate::ffi::gtk_value_set_expression(value.to_glib_none_mut().0, self.to_glib_none().0)
201        }
202        value
203    }
204
205    #[inline]
206    fn value_type(&self) -> glib::Type {
207        Self::static_type()
208    }
209}
210
211impl glib::value::ToValueOptional for Expression {
212    fn to_value_optional(s: Option<&Self>) -> glib::Value {
213        skip_assert_initialized!();
214        let mut value = glib::Value::for_value_type::<Self>();
215        unsafe {
216            crate::ffi::gtk_value_set_expression(value.to_glib_none_mut().0, s.to_glib_none().0)
217        }
218        value
219    }
220}
221
222impl From<Expression> for glib::Value {
223    fn from(e: Expression) -> Self {
224        skip_assert_initialized!();
225        let mut value = glib::Value::for_value_type::<Expression>();
226        unsafe {
227            crate::ffi::gtk_value_take_expression(value.to_glib_none_mut().0, e.into_glib_ptr())
228        }
229        value
230    }
231}
232
233// rustdoc-stripper-ignore-next
234/// Trait containing convenience methods in creating
235/// [`PropertyExpression`](crate::PropertyExpression) that
236/// looks up a property of a [`glib::Object`].
237///
238/// # Example
239///
240/// `label_expression` is an [`Expression`](crate::Expression) that looks up at
241/// Button's `label` property.
242///
243/// ```no_run
244/// # use gtk4 as gtk;
245/// use gtk::prelude::*;
246///
247/// let button = gtk::Button::new();
248/// button.set_label("Label property");
249///
250/// let label_expression = button.property_expression("label");
251/// ```
252pub trait GObjectPropertyExpressionExt: IsA<glib::Object> {
253    // rustdoc-stripper-ignore-next
254    /// Create an expression looking up an object's property.
255    fn property_expression(&self, property_name: &str) -> crate::PropertyExpression {
256        let obj_expr = crate::ConstantExpression::new(self);
257        crate::PropertyExpression::new(Self::static_type(), Some(&obj_expr), property_name)
258    }
259
260    // rustdoc-stripper-ignore-next
261    /// Create an expression looking up an object's property with a weak
262    /// reference.
263    fn property_expression_weak(&self, property_name: &str) -> crate::PropertyExpression {
264        let obj_expr = crate::ObjectExpression::new(self);
265        crate::PropertyExpression::new(Self::static_type(), Some(&obj_expr), property_name)
266    }
267
268    // rustdoc-stripper-ignore-next
269    /// Create an expression looking up a property in the bound `this` object.
270    fn this_expression(property_name: &str) -> crate::PropertyExpression {
271        skip_assert_initialized!();
272        crate::PropertyExpression::new(Self::static_type(), Expression::NONE, property_name)
273    }
274}
275
276impl<O: IsA<glib::Object>> GObjectPropertyExpressionExt for O {}
277
278macro_rules! define_expression {
279    ($rust_type:ident, $ffi_type:path) => {
280        impl std::ops::Deref for $rust_type {
281            type Target = crate::Expression;
282
283            #[inline]
284            fn deref(&self) -> &Self::Target {
285                unsafe { &*(self as *const $rust_type as *const crate::Expression) }
286            }
287        }
288
289        impl AsRef<crate::Expression> for $rust_type {
290            #[inline]
291            fn as_ref(&self) -> &crate::Expression {
292                self.upcast_ref()
293            }
294        }
295
296        impl $rust_type {
297            #[inline]
298            pub fn upcast(self) -> crate::Expression {
299                unsafe { std::mem::transmute(self) }
300            }
301
302            #[inline]
303            pub fn upcast_ref(&self) -> &crate::Expression {
304                self
305            }
306        }
307
308        #[doc(hidden)]
309        impl<'a> ToGlibPtr<'a, *const crate::ffi::GtkExpression> for $rust_type {
310            type Storage =
311                ::std::marker::PhantomData<&'a $crate::glib::shared::Shared<$ffi_type, $rust_type>>;
312
313            #[inline]
314            fn to_glib_none(
315                &'a self,
316            ) -> $crate::glib::translate::Stash<'a, *const crate::ffi::GtkExpression, Self> {
317                let stash =
318                    $crate::glib::translate::ToGlibPtr::<*const $ffi_type>::to_glib_none(self);
319                $crate::glib::translate::Stash(stash.0 as *const _, stash.1)
320            }
321
322            #[inline]
323            fn to_glib_full(&self) -> *const crate::ffi::GtkExpression {
324                $crate::glib::translate::ToGlibPtr::<*const $ffi_type>::to_glib_full(self)
325                    as *const _
326            }
327        }
328
329        #[doc(hidden)]
330        impl<'a> ToGlibPtr<'a, *mut crate::ffi::GtkExpression> for $rust_type {
331            type Storage =
332                ::std::marker::PhantomData<&'a $crate::glib::shared::Shared<$ffi_type, $rust_type>>;
333
334            #[inline]
335            fn to_glib_none(
336                &'a self,
337            ) -> $crate::glib::translate::Stash<'a, *mut crate::ffi::GtkExpression, Self> {
338                let stash =
339                    $crate::glib::translate::ToGlibPtr::<*mut $ffi_type>::to_glib_none(self);
340                $crate::glib::translate::Stash(stash.0 as *mut _, stash.1)
341            }
342
343            #[inline]
344            fn to_glib_full(&self) -> *mut crate::ffi::GtkExpression {
345                $crate::glib::translate::ToGlibPtr::<*mut $ffi_type>::to_glib_full(self) as *mut _
346            }
347        }
348
349        #[doc(hidden)]
350        impl IntoGlibPtr<*mut crate::ffi::GtkExpression> for $rust_type {
351            #[inline]
352            fn into_glib_ptr(self) -> *mut crate::ffi::GtkExpression {
353                let s = std::mem::ManuallyDrop::new(self);
354                s.to_glib_none().0
355            }
356        }
357
358        #[doc(hidden)]
359        impl IntoGlibPtr<*const crate::ffi::GtkExpression> for $rust_type {
360            #[inline]
361            fn into_glib_ptr(self) -> *const crate::ffi::GtkExpression {
362                let s = std::mem::ManuallyDrop::new(self);
363                s.to_glib_none().0
364            }
365        }
366
367        #[doc(hidden)]
368        impl FromGlibPtrFull<*mut crate::ffi::GtkExpression> for $rust_type {
369            #[inline]
370            unsafe fn from_glib_full(ptr: *mut crate::ffi::GtkExpression) -> Self {
371                unsafe { from_glib_full(ptr as *mut $ffi_type) }
372            }
373        }
374
375        unsafe impl crate::expression::IsExpression for $rust_type {}
376
377        impl glib::value::ValueType for $rust_type {
378            type Type = Self;
379        }
380
381        unsafe impl<'a> glib::value::FromValue<'a> for $rust_type {
382            type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
383
384            #[inline]
385            unsafe fn from_value(value: &'a glib::Value) -> Self {
386                unsafe {
387                    skip_assert_initialized!();
388                    from_glib_full(crate::ffi::gtk_value_dup_expression(value.to_glib_none().0))
389                }
390            }
391        }
392
393        impl glib::value::ToValue for $rust_type {
394            #[inline]
395            fn to_value(&self) -> glib::Value {
396                let mut value = glib::Value::for_value_type::<Self>();
397                unsafe {
398                    crate::ffi::gtk_value_set_expression(
399                        value.to_glib_none_mut().0,
400                        self.as_ptr() as *mut _,
401                    )
402                }
403                value
404            }
405
406            #[inline]
407            fn value_type(&self) -> glib::Type {
408                use glib::prelude::StaticType;
409                Self::static_type()
410            }
411        }
412
413        impl glib::value::ToValueOptional for $rust_type {
414            #[inline]
415            fn to_value_optional(s: Option<&Self>) -> glib::Value {
416                skip_assert_initialized!();
417                let mut value = glib::Value::for_value_type::<Self>();
418                unsafe {
419                    crate::ffi::gtk_value_set_expression(
420                        value.to_glib_none_mut().0,
421                        s.map(|s| s.as_ptr()).unwrap_or(std::ptr::null_mut()) as *mut _,
422                    )
423                }
424                value
425            }
426        }
427
428        impl From<$rust_type> for glib::Value {
429            fn from(e: $rust_type) -> Self {
430                skip_assert_initialized!();
431                let mut value = glib::Value::for_value_type::<$rust_type>();
432                unsafe {
433                    crate::ffi::gtk_value_take_expression(
434                        value.to_glib_none_mut().0,
435                        e.into_glib_ptr(),
436                    )
437                }
438                value
439            }
440        }
441
442        impl glib::HasParamSpec for $rust_type {
443            type ParamSpec = crate::ParamSpecExpression;
444
445            type SetValue = $rust_type;
446
447            type BuilderFn = for<'a> fn(&'a str) -> crate::builders::ParamSpecExpressionBuilder<'a>;
448
449            fn param_spec_builder() -> Self::BuilderFn {
450                Self::ParamSpec::builder
451            }
452        }
453    };
454}