gio/
async_initable.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{boxed::Box as Box_, marker::PhantomData, pin::Pin};
4
5use futures_util::TryFutureExt;
6use glib::{object::IsClass, prelude::*, Object, Type};
7
8use crate::{prelude::*, AsyncInitable, Cancellable};
9
10impl AsyncInitable {
11    // rustdoc-stripper-ignore-next
12    /// Create a new instance of an async initable object with the default property values.
13    ///
14    /// Similar to [`Object::new`] but can fail because the object initialization in
15    /// `AsyncInitable::init` failed.
16    #[doc(alias = "g_async_initable_new_async")]
17    #[track_caller]
18    #[allow(clippy::new_ret_no_self)]
19    pub fn new<
20        O: IsClass + IsA<Object> + IsA<AsyncInitable>,
21        Q: FnOnce(Result<O, glib::Error>) + 'static,
22    >(
23        io_priority: glib::Priority,
24        cancellable: Option<&impl IsA<Cancellable>>,
25        callback: Q,
26    ) {
27        Self::with_type(O::static_type(), io_priority, cancellable, move |res| {
28            callback(res.map(|o| unsafe { o.unsafe_cast() }))
29        })
30    }
31
32    // rustdoc-stripper-ignore-next
33    /// Create a new instance of an async initable object with the default property values as future.
34    ///
35    /// Similar to [`Object::new`] but can fail because the object initialization in
36    /// `AsyncInitable::init` failed.
37    #[doc(alias = "g_async_initable_new_async")]
38    #[track_caller]
39    pub fn new_future<O: IsClass + IsA<Object> + IsA<AsyncInitable>>(
40        io_priority: glib::Priority,
41    ) -> Pin<Box_<dyn std::future::Future<Output = Result<O, glib::Error>> + 'static>> {
42        Box::pin(
43            Self::with_type_future(O::static_type(), io_priority)
44                .map_ok(|o| unsafe { o.unsafe_cast() }),
45        )
46    }
47
48    // rustdoc-stripper-ignore-next
49    /// Create a new instance of an async initable object of the given type with the default
50    /// property values.
51    ///
52    /// Similar to [`Object::with_type`] but can fail because the object initialization in
53    /// `AsyncInitable::init` failed.
54    #[doc(alias = "g_async_initable_new_async")]
55    #[track_caller]
56    pub fn with_type<Q: FnOnce(Result<Object, glib::Error>) + 'static>(
57        type_: Type,
58        io_priority: glib::Priority,
59        cancellable: Option<&impl IsA<Cancellable>>,
60        callback: Q,
61    ) {
62        if !type_.is_a(AsyncInitable::static_type()) {
63            panic!("Type '{type_}' is not async initable");
64        }
65
66        unsafe {
67            let obj = Object::new_internal(type_, &mut []);
68            obj.unsafe_cast_ref::<Self>().init_async(
69                io_priority,
70                cancellable,
71                glib::clone!(
72                    #[strong]
73                    obj,
74                    move |res| {
75                        callback(res.map(|_| obj));
76                    }
77                ),
78            )
79        };
80    }
81
82    // rustdoc-stripper-ignore-next
83    /// Create a new instance of an async initable object of the given type with the default property values as future.
84    ///
85    /// Similar to [`Object::with_type`] but can fail because the object initialization in
86    /// `AsyncInitable::init` failed.
87    #[doc(alias = "g_async_initable_new_async")]
88    #[track_caller]
89    pub fn with_type_future(
90        type_: Type,
91        io_priority: glib::Priority,
92    ) -> Pin<Box_<dyn std::future::Future<Output = Result<Object, glib::Error>> + 'static>> {
93        if !type_.is_a(AsyncInitable::static_type()) {
94            panic!("Type '{type_}' is not async initable");
95        }
96
97        unsafe {
98            Box_::pin(crate::GioFuture::new(
99                &(),
100                move |_obj, cancellable, send| {
101                    let obj = Object::new_internal(type_, &mut []);
102                    obj.unsafe_cast_ref::<Self>().init_async(
103                        io_priority,
104                        Some(cancellable),
105                        glib::clone!(
106                            #[strong]
107                            obj,
108                            move |res| {
109                                send.resolve(res.map(|_| obj));
110                            }
111                        ),
112                    );
113                },
114            ))
115        }
116    }
117
118    // rustdoc-stripper-ignore-next
119    /// Create a new instance of an async initable object of the given type with the given properties as mutable values.
120    ///
121    /// Similar to [`Object::with_mut_values`] but can fail because the object initialization in
122    /// `AsyncInitable::init` failed.
123    #[doc(alias = "g_async_initable_new_async")]
124    #[track_caller]
125    pub fn with_mut_values<Q: FnOnce(Result<Object, glib::Error>) + 'static>(
126        type_: Type,
127        properties: &mut [(&str, glib::Value)],
128        io_priority: glib::Priority,
129        cancellable: Option<&impl IsA<Cancellable>>,
130        callback: Q,
131    ) {
132        if !type_.is_a(AsyncInitable::static_type()) {
133            panic!("Type '{type_}' is not async initable");
134        }
135
136        unsafe {
137            let obj = Object::new_internal(type_, properties);
138            obj.unsafe_cast_ref::<Self>().init_async(
139                io_priority,
140                cancellable,
141                glib::clone!(
142                    #[strong]
143                    obj,
144                    move |res| {
145                        callback(res.map(|_| obj));
146                    }
147                ),
148            )
149        };
150    }
151
152    // rustdoc-stripper-ignore-next
153    /// Create a new instance of an async initable object of the given type with the given properties as mutable values as a future.
154    ///
155    /// Similar to [`Object::with_mut_values`] but can fail because the object initialization in
156    /// `AsyncInitable::init` failed.
157    #[doc(alias = "g_async_initable_new_async")]
158    #[track_caller]
159    pub fn with_mut_values_future(
160        type_: Type,
161        properties: &mut [(&str, glib::Value)],
162        io_priority: glib::Priority,
163    ) -> Pin<Box_<dyn std::future::Future<Output = Result<Object, glib::Error>> + 'static>> {
164        if !type_.is_a(AsyncInitable::static_type()) {
165            panic!("Type '{type_}' is not async initable");
166        }
167
168        unsafe {
169            // FIXME: object construction should ideally happen as part of the future
170            let obj = Object::new_internal(type_, properties);
171            Box_::pin(crate::GioFuture::new(
172                &obj,
173                move |obj, cancellable, send| {
174                    obj.unsafe_cast_ref::<Self>().init_async(
175                        io_priority,
176                        Some(cancellable),
177                        glib::clone!(
178                            #[strong]
179                            obj,
180                            move |res| {
181                                send.resolve(res.map(|_| obj));
182                            }
183                        ),
184                    );
185                },
186            ))
187        }
188    }
189
190    // rustdoc-stripper-ignore-next
191    /// Create a new object builder for a specific type.
192    pub fn builder<'a, O: IsA<Object> + IsClass + IsA<AsyncInitable>>(
193    ) -> AsyncInitableBuilder<'a, O> {
194        AsyncInitableBuilder::new(O::static_type())
195    }
196
197    // rustdoc-stripper-ignore-next
198    /// Create a new object builder for a specific type.
199    pub fn builder_with_type<'a>(type_: Type) -> AsyncInitableBuilder<'a, Object> {
200        if !type_.is_a(AsyncInitable::static_type()) {
201            panic!("Type '{type_}' is not async initable");
202        }
203
204        AsyncInitableBuilder::new(type_)
205    }
206}
207
208#[must_use = "builder doesn't do anything unless built"]
209pub struct AsyncInitableBuilder<'a, O> {
210    type_: Type,
211    properties: smallvec::SmallVec<[(&'a str, glib::Value); 16]>,
212    phantom: PhantomData<O>,
213}
214
215impl<'a, O: IsA<Object> + IsClass> AsyncInitableBuilder<'a, O> {
216    #[inline]
217    fn new(type_: Type) -> Self {
218        AsyncInitableBuilder {
219            type_,
220            properties: smallvec::SmallVec::new(),
221            phantom: PhantomData,
222        }
223    }
224
225    // rustdoc-stripper-ignore-next
226    /// Gets the type of this builder.
227    #[inline]
228    pub fn type_(&self) -> Type {
229        self.type_
230    }
231
232    // rustdoc-stripper-ignore-next
233    /// Set property `name` to the given value `value`.
234    #[inline]
235    pub fn property(self, name: &'a str, value: impl Into<glib::Value>) -> Self {
236        let AsyncInitableBuilder {
237            type_,
238            mut properties,
239            ..
240        } = self;
241        properties.push((name, value.into()));
242
243        AsyncInitableBuilder {
244            type_,
245            properties,
246            phantom: PhantomData,
247        }
248    }
249
250    // rustdoc-stripper-ignore-next
251    /// Build the object with the provided properties.
252    ///
253    /// # Panics
254    ///
255    /// This panics if the object is not instantiable, doesn't have all the given properties or
256    /// property values of the wrong type are provided.
257    #[track_caller]
258    #[inline]
259    pub fn build<Q: FnOnce(Result<O, glib::Error>) + 'static>(
260        mut self,
261        io_priority: glib::Priority,
262        cancellable: Option<&impl IsA<Cancellable>>,
263        callback: Q,
264    ) {
265        AsyncInitable::with_mut_values(
266            self.type_,
267            &mut self.properties,
268            io_priority,
269            cancellable,
270            move |res| callback(res.map(|o| unsafe { o.unsafe_cast() })),
271        );
272    }
273
274    // rustdoc-stripper-ignore-next
275    /// Build the object with the provided properties.
276    ///
277    /// # Panics
278    ///
279    /// This panics if the object is not instantiable, doesn't have all the given properties or
280    /// property values of the wrong type are provided.
281    #[track_caller]
282    #[inline]
283    pub fn build_future(
284        mut self,
285        io_priority: glib::Priority,
286    ) -> Pin<Box_<dyn std::future::Future<Output = Result<O, glib::Error>> + 'static>> {
287        Box::pin(
288            AsyncInitable::with_mut_values_future(self.type_, &mut self.properties, io_priority)
289                .map_ok(|o| unsafe { o.unsafe_cast() }),
290        )
291    }
292}