gio/auto/
async_initable.rs

1// This file was generated by gir (https://github.com/gtk-rs/gir)
2// from gir-files (https://github.com/gtk-rs/gir-files)
3// DO NOT EDIT
4
5use crate::{ffi, AsyncResult, Cancellable};
6use glib::{prelude::*, translate::*};
7use std::{boxed::Box as Box_, pin::Pin};
8
9glib::wrapper! {
10    /// `GAsyncInitable` is an interface for asynchronously initializable objects.
11    ///
12    /// This is the asynchronous version of [`Initable`][crate::Initable]; it behaves the same
13    /// in all ways except that initialization is asynchronous. For more details
14    /// see the descriptions on `GInitable`.
15    ///
16    /// A class may implement both the `GInitable` and `GAsyncInitable` interfaces.
17    ///
18    /// Users of objects implementing this are not intended to use the interface
19    /// method directly; instead it will be used automatically in various ways.
20    /// For C applications you generally just call [`new_async()`][Self::new_async()]
21    /// directly, or indirectly via a foo_thing_new_async() wrapper. This will call
22    /// [`AsyncInitableExt::init_async()`][crate::prelude::AsyncInitableExt::init_async()] under the covers, calling back with `NULL`
23    /// and a set `GError` on failure.
24    ///
25    /// A typical implementation might look something like this:
26    ///
27    /// **⚠️ The following code is in c ⚠️**
28    ///
29    /// ```c
30    /// enum {
31    ///    NOT_INITIALIZED,
32    ///    INITIALIZING,
33    ///    INITIALIZED
34    /// };
35    ///
36    /// static void
37    /// _foo_ready_cb (Foo *self)
38    /// {
39    ///   GList *l;
40    ///
41    ///   self->priv->state = INITIALIZED;
42    ///
43    ///   for (l = self->priv->init_results; l != NULL; l = l->next)
44    ///     {
45    ///       GTask *task = l->data;
46    ///
47    ///       if (self->priv->success)
48    ///         g_task_return_boolean (task, TRUE);
49    ///       else
50    ///         g_task_return_new_error (task, ...);
51    ///       g_object_unref (task);
52    ///     }
53    ///
54    ///   g_list_free (self->priv->init_results);
55    ///   self->priv->init_results = NULL;
56    /// }
57    ///
58    /// static void
59    /// foo_init_async (GAsyncInitable       *initable,
60    ///                 int                   io_priority,
61    ///                 GCancellable         *cancellable,
62    ///                 GAsyncReadyCallback   callback,
63    ///                 gpointer              user_data)
64    /// {
65    ///   Foo *self = FOO (initable);
66    ///   GTask *task;
67    ///
68    ///   task = g_task_new (initable, cancellable, callback, user_data);
69    ///   g_task_set_name (task, G_STRFUNC);
70    ///
71    ///   switch (self->priv->state)
72    ///     {
73    ///       case NOT_INITIALIZED:
74    ///         _foo_get_ready (self);
75    ///         self->priv->init_results = g_list_append (self->priv->init_results,
76    ///                                                   task);
77    ///         self->priv->state = INITIALIZING;
78    ///         break;
79    ///       case INITIALIZING:
80    ///         self->priv->init_results = g_list_append (self->priv->init_results,
81    ///                                                   task);
82    ///         break;
83    ///       case INITIALIZED:
84    ///         if (!self->priv->success)
85    ///           g_task_return_new_error (task, ...);
86    ///         else
87    ///           g_task_return_boolean (task, TRUE);
88    ///         g_object_unref (task);
89    ///         break;
90    ///     }
91    /// }
92    ///
93    /// static gboolean
94    /// foo_init_finish (GAsyncInitable       *initable,
95    ///                  GAsyncResult         *result,
96    ///                  GError              **error)
97    /// {
98    ///   g_return_val_if_fail (g_task_is_valid (result, initable), FALSE);
99    ///
100    ///   return g_task_propagate_boolean (G_TASK (result), error);
101    /// }
102    ///
103    /// static void
104    /// foo_async_initable_iface_init (gpointer g_iface,
105    ///                                gpointer data)
106    /// {
107    ///   GAsyncInitableIface *iface = g_iface;
108    ///
109    ///   iface->init_async = foo_init_async;
110    ///   iface->init_finish = foo_init_finish;
111    /// }
112    /// ```
113    ///
114    /// # Implements
115    ///
116    /// [`AsyncInitableExt`][trait@crate::prelude::AsyncInitableExt]
117    #[doc(alias = "GAsyncInitable")]
118    pub struct AsyncInitable(Interface<ffi::GAsyncInitable, ffi::GAsyncInitableIface>);
119
120    match fn {
121        type_ => || ffi::g_async_initable_get_type(),
122    }
123}
124
125impl AsyncInitable {
126    pub const NONE: Option<&'static AsyncInitable> = None;
127}
128
129mod sealed {
130    pub trait Sealed {}
131    impl<T: super::IsA<super::AsyncInitable>> Sealed for T {}
132}
133
134/// Trait containing all [`struct@AsyncInitable`] methods.
135///
136/// # Implementors
137///
138/// [`AsyncInitable`][struct@crate::AsyncInitable], [`DBusConnection`][struct@crate::DBusConnection], [`DBusProxy`][struct@crate::DBusProxy]
139pub trait AsyncInitableExt: IsA<AsyncInitable> + sealed::Sealed + 'static {
140    /// Starts asynchronous initialization of the object implementing the
141    /// interface. This must be done before any real use of the object after
142    /// initial construction. If the object also implements #GInitable you can
143    /// optionally call g_initable_init() instead.
144    ///
145    /// This method is intended for language bindings. If writing in C,
146    /// g_async_initable_new_async() should typically be used instead.
147    ///
148    /// When the initialization is finished, @callback will be called. You can
149    /// then call g_async_initable_init_finish() to get the result of the
150    /// initialization.
151    ///
152    /// Implementations may also support cancellation. If @cancellable is not
153    /// [`None`], then initialization can be cancelled by triggering the cancellable
154    /// object from another thread. If the operation was cancelled, the error
155    /// [`IOErrorEnum::Cancelled`][crate::IOErrorEnum::Cancelled] will be returned. If @cancellable is not [`None`], and
156    /// the object doesn't support cancellable initialization, the error
157    /// [`IOErrorEnum::NotSupported`][crate::IOErrorEnum::NotSupported] will be returned.
158    ///
159    /// As with #GInitable, if the object is not initialized, or initialization
160    /// returns with an error, then all operations on the object except
161    /// g_object_ref() and g_object_unref() are considered to be invalid, and
162    /// have undefined behaviour. They will often fail with g_critical() or
163    /// g_warning(), but this must not be relied on.
164    ///
165    /// Callers should not assume that a class which implements #GAsyncInitable can
166    /// be initialized multiple times; for more information, see g_initable_init().
167    /// If a class explicitly supports being initialized multiple times,
168    /// implementation requires yielding all subsequent calls to init_async() on the
169    /// results of the first call.
170    ///
171    /// For classes that also support the #GInitable interface, the default
172    /// implementation of this method will run the g_initable_init() function
173    /// in a thread, so if you want to support asynchronous initialization via
174    /// threads, just implement the #GAsyncInitable interface without overriding
175    /// any interface methods.
176    /// ## `io_priority`
177    /// the [I/O priority](iface.AsyncResult.html#io-priority) of the operation
178    /// ## `cancellable`
179    /// optional #GCancellable object, [`None`] to ignore.
180    /// ## `callback`
181    /// a #GAsyncReadyCallback to call when the request is satisfied
182    #[doc(alias = "g_async_initable_init_async")]
183    unsafe fn init_async<P: FnOnce(Result<(), glib::Error>) + 'static>(
184        &self,
185        io_priority: glib::Priority,
186        cancellable: Option<&impl IsA<Cancellable>>,
187        callback: P,
188    ) {
189        let main_context = glib::MainContext::ref_thread_default();
190        let is_main_context_owner = main_context.is_owner();
191        let has_acquired_main_context = (!is_main_context_owner)
192            .then(|| main_context.acquire().ok())
193            .flatten();
194        assert!(
195            is_main_context_owner || has_acquired_main_context.is_some(),
196            "Async operations only allowed if the thread is owning the MainContext"
197        );
198
199        let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
200            Box_::new(glib::thread_guard::ThreadGuard::new(callback));
201        unsafe extern "C" fn init_async_trampoline<P: FnOnce(Result<(), glib::Error>) + 'static>(
202            _source_object: *mut glib::gobject_ffi::GObject,
203            res: *mut crate::ffi::GAsyncResult,
204            user_data: glib::ffi::gpointer,
205        ) {
206            let mut error = std::ptr::null_mut();
207            let _ = ffi::g_async_initable_init_finish(_source_object as *mut _, res, &mut error);
208            let result = if error.is_null() {
209                Ok(())
210            } else {
211                Err(from_glib_full(error))
212            };
213            let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
214                Box_::from_raw(user_data as *mut _);
215            let callback: P = callback.into_inner();
216            callback(result);
217        }
218        let callback = init_async_trampoline::<P>;
219        ffi::g_async_initable_init_async(
220            self.as_ref().to_glib_none().0,
221            io_priority.into_glib(),
222            cancellable.map(|p| p.as_ref()).to_glib_none().0,
223            Some(callback),
224            Box_::into_raw(user_data) as *mut _,
225        );
226    }
227
228    unsafe fn init_future(
229        &self,
230        io_priority: glib::Priority,
231    ) -> Pin<Box_<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>> {
232        Box_::pin(crate::GioFuture::new(
233            self,
234            move |obj, cancellable, send| {
235                obj.init_async(io_priority, Some(cancellable), move |res| {
236                    send.resolve(res);
237                });
238            },
239        ))
240    }
241}
242
243impl<O: IsA<AsyncInitable>> AsyncInitableExt for O {}