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
160impl std::fmt::Debug for Expression {
161    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
162        f.debug_struct("Expression")
163            .field("value_type", &self.value_type())
164            .field("is_static", &self.is_static())
165            .finish()
166    }
167}
168
169impl glib::value::ValueType for Expression {
170    type Type = Self;
171}
172
173unsafe impl<'a> glib::value::FromValue<'a> for Expression {
174    type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
175
176    #[inline]
177    unsafe fn from_value(value: &'a glib::Value) -> Self {
178        unsafe {
179            skip_assert_initialized!();
180            from_glib_full(crate::ffi::gtk_value_dup_expression(value.to_glib_none().0))
181        }
182    }
183}
184
185impl glib::value::ToValue for Expression {
186    #[inline]
187    fn to_value(&self) -> glib::Value {
188        let mut value = glib::Value::for_value_type::<Self>();
189        unsafe {
190            crate::ffi::gtk_value_set_expression(value.to_glib_none_mut().0, self.to_glib_none().0)
191        }
192        value
193    }
194
195    #[inline]
196    fn value_type(&self) -> glib::Type {
197        Self::static_type()
198    }
199}
200
201impl glib::value::ToValueOptional for Expression {
202    fn to_value_optional(s: Option<&Self>) -> glib::Value {
203        skip_assert_initialized!();
204        let mut value = glib::Value::for_value_type::<Self>();
205        unsafe {
206            crate::ffi::gtk_value_set_expression(value.to_glib_none_mut().0, s.to_glib_none().0)
207        }
208        value
209    }
210}
211
212impl From<Expression> for glib::Value {
213    fn from(e: Expression) -> Self {
214        skip_assert_initialized!();
215        let mut value = glib::Value::for_value_type::<Expression>();
216        unsafe {
217            crate::ffi::gtk_value_take_expression(value.to_glib_none_mut().0, e.into_glib_ptr())
218        }
219        value
220    }
221}
222
223// rustdoc-stripper-ignore-next
224/// Trait containing convenience methods in creating
225/// [`PropertyExpression`](crate::PropertyExpression) that
226/// looks up a property of a [`glib::Object`].
227///
228/// # Example
229///
230/// `label_expression` is an [`Expression`](crate::Expression) that looks up at
231/// Button's `label` property.
232///
233/// ```no_run
234/// # use gtk4 as gtk;
235/// use gtk::prelude::*;
236///
237/// let button = gtk::Button::new();
238/// button.set_label("Label property");
239///
240/// let label_expression = button.property_expression("label");
241/// ```
242pub trait GObjectPropertyExpressionExt: IsA<glib::Object> {
243    // rustdoc-stripper-ignore-next
244    /// Create an expression looking up an object's property.
245    fn property_expression(&self, property_name: &str) -> crate::PropertyExpression {
246        let obj_expr = crate::ConstantExpression::new(self);
247        crate::PropertyExpression::new(Self::static_type(), Some(&obj_expr), property_name)
248    }
249
250    // rustdoc-stripper-ignore-next
251    /// Create an expression looking up an object's property with a weak
252    /// reference.
253    fn property_expression_weak(&self, property_name: &str) -> crate::PropertyExpression {
254        let obj_expr = crate::ObjectExpression::new(self);
255        crate::PropertyExpression::new(Self::static_type(), Some(&obj_expr), property_name)
256    }
257
258    // rustdoc-stripper-ignore-next
259    /// Create an expression looking up a property in the bound `this` object.
260    fn this_expression(property_name: &str) -> crate::PropertyExpression {
261        skip_assert_initialized!();
262        crate::PropertyExpression::new(Self::static_type(), Expression::NONE, property_name)
263    }
264}
265
266impl<O: IsA<glib::Object>> GObjectPropertyExpressionExt for O {}
267
268macro_rules! define_expression {
269    ($rust_type:ident, $ffi_type:path) => {
270        impl std::ops::Deref for $rust_type {
271            type Target = crate::Expression;
272
273            #[inline]
274            fn deref(&self) -> &Self::Target {
275                unsafe { &*(self as *const $rust_type as *const crate::Expression) }
276            }
277        }
278
279        impl AsRef<crate::Expression> for $rust_type {
280            #[inline]
281            fn as_ref(&self) -> &crate::Expression {
282                self.upcast_ref()
283            }
284        }
285
286        impl $rust_type {
287            #[inline]
288            pub fn upcast(self) -> crate::Expression {
289                unsafe { std::mem::transmute(self) }
290            }
291
292            #[inline]
293            pub fn upcast_ref(&self) -> &crate::Expression {
294                self
295            }
296        }
297
298        #[doc(hidden)]
299        impl<'a> ToGlibPtr<'a, *const crate::ffi::GtkExpression> for $rust_type {
300            type Storage =
301                ::std::marker::PhantomData<&'a $crate::glib::shared::Shared<$ffi_type, $rust_type>>;
302
303            #[inline]
304            fn to_glib_none(
305                &'a self,
306            ) -> $crate::glib::translate::Stash<'a, *const crate::ffi::GtkExpression, Self> {
307                let stash =
308                    $crate::glib::translate::ToGlibPtr::<*const $ffi_type>::to_glib_none(self);
309                $crate::glib::translate::Stash(stash.0 as *const _, stash.1)
310            }
311
312            #[inline]
313            fn to_glib_full(&self) -> *const crate::ffi::GtkExpression {
314                $crate::glib::translate::ToGlibPtr::<*const $ffi_type>::to_glib_full(self)
315                    as *const _
316            }
317        }
318
319        #[doc(hidden)]
320        impl<'a> ToGlibPtr<'a, *mut crate::ffi::GtkExpression> for $rust_type {
321            type Storage =
322                ::std::marker::PhantomData<&'a $crate::glib::shared::Shared<$ffi_type, $rust_type>>;
323
324            #[inline]
325            fn to_glib_none(
326                &'a self,
327            ) -> $crate::glib::translate::Stash<'a, *mut crate::ffi::GtkExpression, Self> {
328                let stash =
329                    $crate::glib::translate::ToGlibPtr::<*mut $ffi_type>::to_glib_none(self);
330                $crate::glib::translate::Stash(stash.0 as *mut _, stash.1)
331            }
332
333            #[inline]
334            fn to_glib_full(&self) -> *mut crate::ffi::GtkExpression {
335                $crate::glib::translate::ToGlibPtr::<*mut $ffi_type>::to_glib_full(self) as *mut _
336            }
337        }
338
339        #[doc(hidden)]
340        impl IntoGlibPtr<*mut crate::ffi::GtkExpression> for $rust_type {
341            #[inline]
342            fn into_glib_ptr(self) -> *mut crate::ffi::GtkExpression {
343                let s = std::mem::ManuallyDrop::new(self);
344                s.to_glib_none().0
345            }
346        }
347
348        #[doc(hidden)]
349        impl IntoGlibPtr<*const crate::ffi::GtkExpression> for $rust_type {
350            #[inline]
351            fn into_glib_ptr(self) -> *const crate::ffi::GtkExpression {
352                let s = std::mem::ManuallyDrop::new(self);
353                s.to_glib_none().0
354            }
355        }
356
357        #[doc(hidden)]
358        impl FromGlibPtrFull<*mut crate::ffi::GtkExpression> for $rust_type {
359            #[inline]
360            unsafe fn from_glib_full(ptr: *mut crate::ffi::GtkExpression) -> Self {
361                unsafe { from_glib_full(ptr as *mut $ffi_type) }
362            }
363        }
364
365        unsafe impl crate::expression::IsExpression for $rust_type {}
366
367        impl glib::value::ValueType for $rust_type {
368            type Type = Self;
369        }
370
371        unsafe impl<'a> glib::value::FromValue<'a> for $rust_type {
372            type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
373
374            #[inline]
375            unsafe fn from_value(value: &'a glib::Value) -> Self {
376                unsafe {
377                    skip_assert_initialized!();
378                    from_glib_full(crate::ffi::gtk_value_dup_expression(value.to_glib_none().0))
379                }
380            }
381        }
382
383        impl glib::value::ToValue for $rust_type {
384            #[inline]
385            fn to_value(&self) -> glib::Value {
386                let mut value = glib::Value::for_value_type::<Self>();
387                unsafe {
388                    crate::ffi::gtk_value_set_expression(
389                        value.to_glib_none_mut().0,
390                        self.as_ptr() as *mut _,
391                    )
392                }
393                value
394            }
395
396            #[inline]
397            fn value_type(&self) -> glib::Type {
398                use glib::prelude::StaticType;
399                Self::static_type()
400            }
401        }
402
403        impl glib::value::ToValueOptional for $rust_type {
404            #[inline]
405            fn to_value_optional(s: Option<&Self>) -> glib::Value {
406                skip_assert_initialized!();
407                let mut value = glib::Value::for_value_type::<Self>();
408                unsafe {
409                    crate::ffi::gtk_value_set_expression(
410                        value.to_glib_none_mut().0,
411                        s.map(|s| s.as_ptr()).unwrap_or(std::ptr::null_mut()) as *mut _,
412                    )
413                }
414                value
415            }
416        }
417
418        impl From<$rust_type> for glib::Value {
419            fn from(e: $rust_type) -> Self {
420                skip_assert_initialized!();
421                let mut value = glib::Value::for_value_type::<$rust_type>();
422                unsafe {
423                    crate::ffi::gtk_value_take_expression(
424                        value.to_glib_none_mut().0,
425                        e.into_glib_ptr(),
426                    )
427                }
428                value
429            }
430        }
431
432        impl glib::HasParamSpec for $rust_type {
433            type ParamSpec = crate::ParamSpecExpression;
434
435            type SetValue = $rust_type;
436
437            type BuilderFn = for<'a> fn(&'a str) -> crate::builders::ParamSpecExpressionBuilder<'a>;
438
439            fn param_spec_builder() -> Self::BuilderFn {
440                Self::ParamSpec::builder
441            }
442        }
443    };
444}