gio/
initable.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::marker::PhantomData;
4
5use glib::{object::IsClass, prelude::*, Object, Type};
6
7use crate::{prelude::*, Cancellable, Initable};
8
9impl Initable {
10    // rustdoc-stripper-ignore-next
11    /// Create a new instance of an object with the default property values.
12    ///
13    /// Similar to [`Object::new`] but can fail because the object initialization in
14    /// `Initable::init` failed.
15    // rustdoc-stripper-ignore-next-stop
16    /// Helper function for constructing #GInitable object. This is
17    /// similar to g_object_new() but also initializes the object
18    /// and returns [`None`], setting an error on failure.
19    /// ## `object_type`
20    /// a #GType supporting #GInitable.
21    /// ## `cancellable`
22    /// optional #GCancellable object, [`None`] to ignore.
23    /// ## `first_property_name`
24    /// the name of the first property, or [`None`] if no
25    ///     properties
26    ///
27    /// # Returns
28    ///
29    /// a newly allocated
30    ///      #GObject, or [`None`] on error
31    #[track_caller]
32    #[allow(clippy::new_ret_no_self)]
33    pub fn new<T: IsA<Object> + IsClass + IsA<Initable>>(
34        cancellable: Option<&impl IsA<Cancellable>>,
35    ) -> Result<T, glib::Error> {
36        let object = Self::with_type(T::static_type(), cancellable)?;
37        Ok(unsafe { object.unsafe_cast() })
38    }
39
40    // rustdoc-stripper-ignore-next
41    /// Create a new instance of an object with the default property values.
42    ///
43    /// Similar to [`Object::with_type`] but can fail because the object initialization in
44    /// `Initable::init` failed.
45    #[track_caller]
46    pub fn with_type(
47        type_: Type,
48        cancellable: Option<&impl IsA<Cancellable>>,
49    ) -> Result<Object, glib::Error> {
50        if !type_.is_a(Initable::static_type()) {
51            panic!("Type '{type_}' is not initable");
52        }
53
54        unsafe {
55            let object = Object::new_internal(type_, &mut []);
56            object.unsafe_cast_ref::<Self>().init(cancellable)?;
57            Ok(object)
58        }
59    }
60
61    // rustdoc-stripper-ignore-next
62    /// Create a new instance of an object of the given type with the given properties as mutable
63    /// values.
64    ///
65    /// # Panics
66    ///
67    /// This panics if the object is not instantiable, doesn't have all the given properties or
68    /// property values of the wrong type are provided.
69    #[track_caller]
70    pub fn with_mut_values(
71        type_: Type,
72        properties: &mut [(&str, glib::Value)],
73        cancellable: Option<&impl IsA<Cancellable>>,
74    ) -> Result<Object, glib::Error> {
75        if !type_.is_a(Initable::static_type()) {
76            panic!("Type '{type_}' is not initable");
77        }
78
79        unsafe {
80            let object = Object::new_internal(type_, properties);
81            object.unsafe_cast_ref::<Self>().init(cancellable)?;
82            Ok(object)
83        }
84    }
85
86    // rustdoc-stripper-ignore-next
87    /// Create a new object builder for a specific type.
88    pub fn builder<'a, O: IsA<Object> + IsClass + IsA<Initable>>() -> InitableBuilder<'a, O> {
89        InitableBuilder::new(O::static_type())
90    }
91
92    // rustdoc-stripper-ignore-next
93    /// Create a new object builder for a specific type.
94    pub fn builder_with_type<'a>(type_: Type) -> InitableBuilder<'a, Object> {
95        if !type_.is_a(Initable::static_type()) {
96            panic!("Type '{type_}' is not initable");
97        }
98
99        InitableBuilder::new(type_)
100    }
101}
102
103#[must_use = "builder doesn't do anything unless built"]
104pub struct InitableBuilder<'a, O> {
105    type_: Type,
106    properties: smallvec::SmallVec<[(&'a str, glib::Value); 16]>,
107    phantom: PhantomData<O>,
108}
109
110impl<'a, O: IsA<Object> + IsClass> InitableBuilder<'a, O> {
111    #[inline]
112    fn new(type_: Type) -> Self {
113        InitableBuilder {
114            type_,
115            properties: smallvec::SmallVec::new(),
116            phantom: PhantomData,
117        }
118    }
119
120    // rustdoc-stripper-ignore-next
121    /// Gets the type of this builder.
122    #[inline]
123    pub fn type_(&self) -> Type {
124        self.type_
125    }
126
127    // rustdoc-stripper-ignore-next
128    /// Set property `name` to the given value `value`.
129    #[inline]
130    pub fn property(self, name: &'a str, value: impl Into<glib::Value>) -> Self {
131        let InitableBuilder {
132            type_,
133            mut properties,
134            ..
135        } = self;
136        properties.push((name, value.into()));
137
138        InitableBuilder {
139            type_,
140            properties,
141            phantom: PhantomData,
142        }
143    }
144
145    // rustdoc-stripper-ignore-next
146    /// Build the object with the provided properties.
147    ///
148    /// # Panics
149    ///
150    /// This panics if the object is not instantiable, doesn't have all the given properties or
151    /// property values of the wrong type are provided.
152    #[track_caller]
153    #[inline]
154    pub fn build(mut self, cancellable: Option<&impl IsA<Cancellable>>) -> Result<O, glib::Error> {
155        let object = Initable::with_mut_values(self.type_, &mut self.properties, cancellable)?;
156        Ok(unsafe { object.unsafe_cast::<O>() })
157    }
158}