Skip to main content

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